Merge "AudioManager: Add support for master mute" into ics-aah
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 040a994..95a8e2c 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -124,6 +124,10 @@
             runProfile();
         } else if (op.equals("dumpheap")) {
             runDumpHeap();
+        } else if (op.equals("set-debug-app")) {
+            runSetDebugApp();
+        } else if (op.equals("clear-debug-app")) {
+            runClearDebugApp();
         } else if (op.equals("monitor")) {
             runMonitor();
         } else if (op.equals("screen-compat")) {
@@ -709,6 +713,31 @@
         }
     }
 
+    private void runSetDebugApp() throws Exception {
+        boolean wait = false;
+        boolean persistent = false;
+
+        String opt;
+        while ((opt=nextOption()) != null) {
+            if (opt.equals("-w")) {
+                wait = true;
+            } else if (opt.equals("--persistent")) {
+                persistent = true;
+            } else {
+                System.err.println("Error: Unknown option: " + opt);
+                showUsage();
+                return;
+            }
+        }
+
+        String pkg = nextArgRequired();
+        mAm.setDebugApp(pkg, wait, persistent);
+    }
+
+    private void runClearDebugApp() throws Exception {
+        mAm.setDebugApp(null, false, true);
+    }
+
     class MyActivityController extends IActivityController.Stub {
         final String mGdbPort;
 
@@ -1243,6 +1272,8 @@
                 "       am profile [looper] start <PROCESS> <FILE>\n" +
                 "       am profile [looper] stop [<PROCESS>]\n" +
                 "       am dumpheap [flags] <PROCESS> <FILE>\n" +
+                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
+                "       am clear-debug-app\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
                 "       am display-size [reset|MxN]\n" +
@@ -1286,6 +1317,12 @@
                 "am dumpheap: dump the heap of a process.  Options are:\n" +
                 "    -n: dump native heap instead of managed heap\n" +
                 "\n" +
+                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
+                "    -w: wait for debugger when application starts\n" +
+                "    --persistent: retain this value\n" +
+                "\n" +
+                "am clear-debug-app: clear the previously set-debug-app.\n" +
+                "\n" +
                 "am monitor: start monitoring for crashes or ANRs.\n" +
                 "    --gdb: start gdbserv on the given port at crash/ANR\n" +
                 "\n" +
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f9896f7..303f81b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2734,8 +2734,9 @@
         CharSequence description;
     }
 
-    private class ProviderRefCount {
+    private static final class ProviderRefCount {
         public int count;
+
         ProviderRefCount(int pCount) {
             count = pCount;
         }
@@ -3988,16 +3989,14 @@
             buf.append(": ");
             buf.append(cpi.name);
             Log.i(TAG, buf.toString());
-            IContentProvider cp = installProvider(context, null, cpi, false);
+            IContentProvider cp = installProvider(context, null, cpi,
+                    false /*noisy*/, true /*noReleaseNeeded*/);
             if (cp != null) {
                 IActivityManager.ContentProviderHolder cph =
-                    new IActivityManager.ContentProviderHolder(cpi);
+                        new IActivityManager.ContentProviderHolder(cpi);
                 cph.provider = cp;
+                cph.noReleaseNeeded = true;
                 results.add(cph);
-                // Don't ever unload this provider from the process.
-                synchronized(mProviderMap) {
-                    mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000));
-                }
             }
         }
 
@@ -4008,26 +4007,22 @@
         }
     }
 
-    private IContentProvider getExistingProvider(Context context, String name) {
-        synchronized(mProviderMap) {
-            final ProviderClientRecord pr = mProviderMap.get(name);
-            if (pr != null) {
-                return pr.mProvider;
-            }
-            return null;
-        }
-    }
-
-    private IContentProvider getProvider(Context context, String name) {
-        IContentProvider existing = getExistingProvider(context, name);
-        if (existing != null) {
-            return existing;
+    public final IContentProvider acquireProvider(Context c, String name) {
+        IContentProvider provider = acquireExistingProvider(c, name);
+        if (provider != null) {
+            return provider;
         }
 
+        // There is a possible race here.  Another thread may try to acquire
+        // the same provider at the same time.  When this happens, we want to ensure
+        // that the first one wins.
+        // Note that we cannot hold the lock while acquiring and installing the
+        // provider since it might take a long time to run and it could also potentially
+        // be re-entrant in the case where the provider is in the same process.
         IActivityManager.ContentProviderHolder holder = null;
         try {
             holder = ActivityManagerNative.getDefault().getContentProvider(
-                getApplicationThread(), name);
+                    getApplicationThread(), name);
         } catch (RemoteException ex) {
         }
         if (holder == null) {
@@ -4035,136 +4030,137 @@
             return null;
         }
 
-        IContentProvider prov = installProvider(context, holder.provider,
-                holder.info, true);
-        //Slog.i(TAG, "noReleaseNeeded=" + holder.noReleaseNeeded);
-        if (holder.noReleaseNeeded || holder.provider == null) {
-            // We are not going to release the provider if it is an external
-            // provider that doesn't care about being released, or if it is
-            // a local provider running in this process.
-            //Slog.i(TAG, "*** NO RELEASE NEEDED");
-            synchronized(mProviderMap) {
-                mProviderRefCountMap.put(prov.asBinder(), new ProviderRefCount(10000));
+        // Install provider will increment the reference count for us, and break
+        // any ties in the race.
+        provider = installProvider(c, holder.provider, holder.info,
+                true /*noisy*/, holder.noReleaseNeeded);
+        if (holder.provider != null && provider != holder.provider) {
+            if (localLOGV) {
+                Slog.v(TAG, "acquireProvider: lost the race, releasing extraneous "
+                        + "reference to the content provider");
+            }
+            try {
+                ActivityManagerNative.getDefault().removeContentProvider(
+                        getApplicationThread(), name);
+            } catch (RemoteException ex) {
             }
         }
-        return prov;
-    }
-
-    public final IContentProvider acquireProvider(Context c, String name) {
-        IContentProvider provider = getProvider(c, name);
-        if(provider == null)
-            return null;
-        IBinder jBinder = provider.asBinder();
-        synchronized(mProviderMap) {
-            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
-            if(prc == null) {
-                mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
-            } else {
-                prc.count++;
-            } //end else
-        } //end synchronized
         return provider;
     }
 
     public final IContentProvider acquireExistingProvider(Context c, String name) {
-        IContentProvider provider = getExistingProvider(c, name);
-        if(provider == null)
-            return null;
-        IBinder jBinder = provider.asBinder();
-        synchronized(mProviderMap) {
+        synchronized (mProviderMap) {
+            ProviderClientRecord pr = mProviderMap.get(name);
+            if (pr == null) {
+                return null;
+            }
+
+            IContentProvider provider = pr.mProvider;
+            IBinder jBinder = provider.asBinder();
+
+            // Only increment the ref count if we have one.  If we don't then the
+            // provider is not reference counted and never needs to be released.
             ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
-            if(prc == null) {
-                mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
-            } else {
-                prc.count++;
-            } //end else
-        } //end synchronized
-        return provider;
+            if (prc != null) {
+                prc.count += 1;
+                if (prc.count == 1) {
+                    if (localLOGV) {
+                        Slog.v(TAG, "acquireExistingProvider: "
+                                + "snatched provider from the jaws of death");
+                    }
+                    // Because the provider previously had a reference count of zero,
+                    // it was scheduled to be removed.  Cancel that.
+                    mH.removeMessages(H.REMOVE_PROVIDER, provider);
+                }
+            }
+            return provider;
+        }
     }
 
     public final boolean releaseProvider(IContentProvider provider) {
         if(provider == null) {
             return false;
         }
+
         IBinder jBinder = provider.asBinder();
-        synchronized(mProviderMap) {
+        synchronized (mProviderMap) {
             ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
-            if(prc == null) {
-                if(localLOGV) Slog.v(TAG, "releaseProvider::Weird shouldn't be here");
+            if (prc == null) {
+                // The provider has no ref count, no release is needed.
                 return false;
-            } else {
-                prc.count--;
-                if(prc.count == 0) {
-                    // Schedule the actual remove asynchronously, since we
-                    // don't know the context this will be called in.
-                    // TODO: it would be nice to post a delayed message, so
-                    // if we come back and need the same provider quickly
-                    // we will still have it available.
-                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
-                    mH.sendMessage(msg);
-                } //end if
-            } //end else
-        } //end synchronized
-        return true;
+            }
+
+            if (prc.count == 0) {
+                if (localLOGV) Slog.v(TAG, "releaseProvider: ref count already 0, how?");
+                return false;
+            }
+
+            prc.count -= 1;
+            if (prc.count == 0) {
+                // Schedule the actual remove asynchronously, since we don't know the context
+                // this will be called in.
+                // TODO: it would be nice to post a delayed message, so
+                // if we come back and need the same provider quickly
+                // we will still have it available.
+                Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
+                mH.sendMessage(msg);
+            }
+            return true;
+        }
     }
 
     final void completeRemoveProvider(IContentProvider provider) {
         IBinder jBinder = provider.asBinder();
-        String name = null;
+        String remoteProviderName = null;
         synchronized(mProviderMap) {
             ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
-            if(prc != null && prc.count == 0) {
-                mProviderRefCountMap.remove(jBinder);
-                //invoke removeProvider to dereference provider
-                name = removeProviderLocked(provider);
+            if (prc == null) {
+                // Either no release is needed (so we shouldn't be here) or the
+                // provider was already released.
+                if (localLOGV) Slog.v(TAG, "completeRemoveProvider: release not needed");
+                return;
+            }
+
+            if (prc.count != 0) {
+                // There was a race!  Some other client managed to acquire
+                // the provider before the removal was completed.
+                // Abort the removal.  We will do it later.
+                if (localLOGV) Slog.v(TAG, "completeRemoveProvider: lost the race, "
+                        + "provider still in use");
+                return;
+            }
+
+            mProviderRefCountMap.remove(jBinder);
+
+            Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator();
+            while (iter.hasNext()) {
+                ProviderClientRecord pr = iter.next();
+                IBinder myBinder = pr.mProvider.asBinder();
+                if (myBinder == jBinder) {
+                    iter.remove();
+                    if (pr.mLocalProvider == null) {
+                        myBinder.unlinkToDeath(pr, 0);
+                        if (remoteProviderName == null) {
+                            remoteProviderName = pr.mName;
+                        }
+                    }
+                }
             }
         }
-        
-        if (name != null) {
+
+        if (remoteProviderName != null) {
             try {
-                if(localLOGV) Slog.v(TAG, "removeProvider::Invoking " +
-                        "ActivityManagerNative.removeContentProvider(" + name);
+                if (localLOGV) {
+                    Slog.v(TAG, "removeProvider: Invoking ActivityManagerNative."
+                            + "removeContentProvider(" + remoteProviderName + ")");
+                }
                 ActivityManagerNative.getDefault().removeContentProvider(
-                        getApplicationThread(), name);
+                        getApplicationThread(), remoteProviderName);
             } catch (RemoteException e) {
                 //do nothing content provider object is dead any way
-            } //end catch
+            }
         }
     }
-    
-    public final String removeProviderLocked(IContentProvider provider) {
-        if (provider == null) {
-            return null;
-        }
-        IBinder providerBinder = provider.asBinder();
-
-        String name = null;
-        
-        // remove the provider from mProviderMap
-        Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator();
-        while (iter.hasNext()) {
-            ProviderClientRecord pr = iter.next();
-            IBinder myBinder = pr.mProvider.asBinder();
-            if (myBinder == providerBinder) {
-                //find if its published by this process itself
-                if(pr.mLocalProvider != null) {
-                    if(localLOGV) Slog.i(TAG, "removeProvider::found local provider returning");
-                    return name;
-                }
-                if(localLOGV) Slog.v(TAG, "removeProvider::Not local provider Unlinking " +
-                        "death recipient");
-                //content provider is in another process
-                myBinder.unlinkToDeath(pr, 0);
-                iter.remove();
-                //invoke remove only once for the very first name seen
-                if(name == null) {
-                    name = pr.mName;
-                }
-            } //end if myBinder
-        }  //end while iter
-        
-        return name;
-    }
 
     final void removeDeadProvider(String name, IContentProvider provider) {
         synchronized(mProviderMap) {
@@ -4179,8 +4175,23 @@
         }
     }
 
+    /**
+     * Installs the provider.
+     *
+     * Providers that are local to the process or that come from the system server
+     * may be installed permanently which is indicated by setting noReleaseNeeded to true.
+     * Other remote providers are reference counted.  The initial reference count
+     * for all reference counted providers is one.  Providers that are not reference
+     * counted do not have a reference count (at all).
+     *
+     * This method detects when a provider has already been installed.  When this happens,
+     * it increments the reference count of the existing provider (if appropriate)
+     * and returns the existing provider.  This can happen due to concurrent
+     * attempts to acquire the same provider.
+     */
     private IContentProvider installProvider(Context context,
-            IContentProvider provider, ProviderInfo info, boolean noisy) {
+            IContentProvider provider, ProviderInfo info,
+            boolean noisy, boolean noReleaseNeeded) {
         ContentProvider localProvider = null;
         if (provider == null) {
             if (noisy) {
@@ -4238,24 +4249,69 @@
         }
 
         synchronized (mProviderMap) {
-            // Cache the pointer for the remote provider.
+            // There is a possibility that this thread raced with another thread to
+            // add the provider.  If we find another thread got there first then we
+            // just get out of the way and return the original provider.
+            IBinder jBinder = provider.asBinder();
             String names[] = PATTERN_SEMICOLON.split(info.authority);
-            for (int i=0; i<names.length; i++) {
-                ProviderClientRecord pr = new ProviderClientRecord(names[i], provider,
-                        localProvider);
-                try {
-                    provider.asBinder().linkToDeath(pr, 0);
+            for (int i = 0; i < names.length; i++) {
+                ProviderClientRecord pr = mProviderMap.get(names[i]);
+                if (pr != null) {
+                    if (localLOGV) {
+                        Slog.v(TAG, "installProvider: lost the race, "
+                                + "using existing named provider");
+                    }
+                    provider = pr.mProvider;
+                } else {
+                    pr = new ProviderClientRecord(names[i], provider, localProvider);
+                    if (localProvider == null) {
+                        try {
+                            jBinder.linkToDeath(pr, 0);
+                        } catch (RemoteException e) {
+                            // Provider already dead.  Bail out of here without making
+                            // any changes to the provider map or other data structures.
+                            return null;
+                        }
+                    }
                     mProviderMap.put(names[i], pr);
-                } catch (RemoteException e) {
-                    return null;
                 }
             }
+
             if (localProvider != null) {
-                mLocalProviders.put(provider.asBinder(),
-                        new ProviderClientRecord(null, provider, localProvider));
+                ProviderClientRecord pr = mLocalProviders.get(jBinder);
+                if (pr != null) {
+                    if (localLOGV) {
+                        Slog.v(TAG, "installProvider: lost the race, "
+                                + "using existing local provider");
+                    }
+                    provider = pr.mProvider;
+                } else {
+                    pr = new ProviderClientRecord(null, provider, localProvider);
+                    mLocalProviders.put(jBinder, pr);
+                }
+            }
+
+            if (!noReleaseNeeded) {
+                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
+                if (prc != null) {
+                    if (localLOGV) {
+                        Slog.v(TAG, "installProvider: lost the race, incrementing ref count");
+                    }
+                    prc.count += 1;
+                    if (prc.count == 1) {
+                        if (localLOGV) {
+                            Slog.v(TAG, "installProvider: "
+                                    + "snatched provider from the jaws of death");
+                        }
+                        // Because the provider previously had a reference count of zero,
+                        // it was scheduled to be removed.  Cancel that.
+                        mH.removeMessages(H.REMOVE_PROVIDER, provider);
+                    }
+                } else {
+                    mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
+                }
             }
         }
-
         return provider;
     }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 3becec0..c2a757f 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1111,9 +1111,21 @@
      * Parameters#getMaxNumDetectedFaces()} returns a number larger than 0.
      * If the face detection has started, apps should not call this again.
      *
-     * When the face detection is running, {@link Parameters#setWhiteBalance(String)},
+     * <p>When the face detection is running, {@link Parameters#setWhiteBalance(String)},
      * {@link Parameters#setFocusAreas(List)}, and {@link Parameters#setMeteringAreas(List)}
-     * have no effect.
+     * have no effect. The camera uses the detected faces to do auto-white balance,
+     * auto exposure, and autofocus.
+     *
+     * <p>If the apps call {@link #autoFocus(AutoFocusCallback)}, the camera
+     * will stop sending face callbacks. The last face callback indicates the
+     * areas used to do autofocus. After focus completes, face detection will
+     * resume sending face callbacks. If the apps call {@link
+     * #cancelAutoFocus()}, the face callbacks will also resume.</p>
+     *
+     * <p>After calling {@link #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
+     * Camera.PictureCallback)} or {@link #stopPreview()}, and then resuming
+     * preview with {@link #startPreview()}, the apps should call this method
+     * again to resume face detection.</p>
      *
      * @throws IllegalArgumentException if the face detection is unsupported.
      * @throws RuntimeException if the method fails or the face detection is
@@ -1163,14 +1175,31 @@
          * camera field of view, and (1000, 1000) represents the bottom-right of
          * the field of view. For example, suppose the size of the viewfinder UI
          * is 800x480. The rect passed from the driver is (-1000, -1000, 0, 0).
-         * The corresponding viewfinder rect should be (0, 0, 400, 240). The
-         * width and height of the rect will not be 0 or negative. The
-         * coordinates can be smaller than -1000 or bigger than 1000. But at
-         * least one vertex will be within (-1000, -1000) and (1000, 1000).
+         * The corresponding viewfinder rect should be (0, 0, 400, 240). It is
+         * guaranteed left < right and top < bottom. The coordinates can be
+         * smaller than -1000 or bigger than 1000. But at least one vertex will
+         * be within (-1000, -1000) and (1000, 1000).
          *
          * <p>The direction is relative to the sensor orientation, that is, what
          * the sensor sees. The direction is not affected by the rotation or
-         * mirroring of {@link #setDisplayOrientation(int)}.</p>
+         * mirroring of {@link #setDisplayOrientation(int)}. The face bounding
+         * rectangle does not provide any information about face orientation.</p>
+         *
+         * <p>Here is the matrix to convert driver coordinates to View coordinates
+         * in pixels.</p>
+         * <pre>
+         * Matrix matrix = new Matrix();
+         * CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId];
+         * // Need mirror for front camera.
+         * boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
+         * matrix.setScale(mirror ? -1 : 1, 1);
+         * // This is the value for android.hardware.Camera.setDisplayOrientation.
+         * matrix.postRotate(displayOrientation);
+         * // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
+         * // UI coordinates range from (0, 0) to (width, height).
+         * matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
+         * matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
+         * </pre>
          *
          * @see #startFaceDetection()
          */
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index bfc7c31..8115b36 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -19,7 +19,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -44,6 +43,7 @@
     private String mName;
     private int mSources;
     private int mKeyboardType;
+    private String mKeyCharacterMapFile;
 
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
@@ -360,6 +360,10 @@
         return KeyCharacterMap.load(mId);
     }
 
+    String getKeyCharacterMapFile() {
+        return mKeyCharacterMapFile;
+    }
+
     /**
      * Gets information about the range of values for a particular {@link MotionEvent} axis.
      * If the device supports multiple sources, the same axis may have different meanings
@@ -532,6 +536,7 @@
         mName = in.readString();
         mSources = in.readInt();
         mKeyboardType = in.readInt();
+        mKeyCharacterMapFile = in.readString();
 
         for (;;) {
             int axis = in.readInt();
@@ -549,6 +554,7 @@
         out.writeString(mName);
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
+        out.writeString(mKeyCharacterMapFile);
 
         final int numRanges = mMotionRanges.size();
         for (int i = 0; i < numRanges; i++) {
@@ -587,6 +593,8 @@
         }
         description.append("\n");
 
+        description.append("  Key Character Map: ").append(mKeyCharacterMapFile).append("\n");
+
         description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 885a75f..575af3b 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -20,7 +20,6 @@
 import android.util.AndroidRuntimeException;
 import android.util.SparseIntArray;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.SparseArray;
 
 import java.lang.Character;
@@ -140,7 +139,7 @@
     private final int mDeviceId;
     private int mPtr;
 
-    private static native int nativeLoad(int id);
+    private static native int nativeLoad(String file);
     private static native void nativeDispose(int ptr);
 
     private static native char nativeGetCharacter(int ptr, int keyCode, int metaState);
@@ -178,7 +177,17 @@
         synchronized (sInstances) {
             KeyCharacterMap map = sInstances.get(deviceId);
             if (map == null) {
-                int ptr = nativeLoad(deviceId); // might throw
+                String kcm = null;
+                if (deviceId != VIRTUAL_KEYBOARD) {
+                    InputDevice device = InputDevice.getDevice(deviceId);
+                    if (device != null) {
+                        kcm = device.getKeyCharacterMapFile();
+                    }
+                }
+                if (kcm == null || kcm.length() == 0) {
+                    kcm = "/system/usr/keychars/Virtual.kcm";
+                }
+                int ptr = nativeLoad(kcm); // might throw
                 map = new KeyCharacterMap(deviceId, ptr);
                 sInstances.put(deviceId, map);
             }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7249497..ec2f55b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3097,10 +3097,7 @@
         // Special-case layer scrolling so that we do not trigger normal scroll
         // updating.
         if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
-            nativeScrollLayer(mScrollingLayer, scrollX, scrollY);
-            mScrollingLayerRect.left = scrollX;
-            mScrollingLayerRect.top = scrollY;
-            invalidate();
+            scrollLayerTo(scrollX, scrollY);
             return;
         }
         mInOverScrollMode = false;
@@ -3603,9 +3600,7 @@
                     mScrollY = y;
                 } else {
                     // Update the layer position instead of WebView.
-                    nativeScrollLayer(mScrollingLayer, x, y);
-                    mScrollingLayerRect.left = x;
-                    mScrollingLayerRect.top = y;
+                    scrollLayerTo(x, y);
                 }
                 abortAnimation();
                 nativeSetIsScrolling(false);
@@ -3624,6 +3619,17 @@
         }
     }
 
+    private void scrollLayerTo(int x, int y) {
+        if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
+            return;
+        }
+        nativeScrollLayer(mScrollingLayer, x, y);
+        mScrollingLayerRect.left = x;
+        mScrollingLayerRect.top = y;
+        onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY);
+        invalidate();
+    }
+
     private static int computeDuration(int dx, int dy) {
         int distance = Math.max(Math.abs(dx), Math.abs(dy));
         int duration = distance * 1000 / STD_SPEED;
@@ -8309,12 +8315,8 @@
                     if (mScrollingLayer == 0) {
                         pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0);
                     } else {
-                        mScrollingLayerRect.left += mAutoScrollX;
-                        mScrollingLayerRect.top += mAutoScrollY;
-                        nativeScrollLayer(mScrollingLayer,
-                                mScrollingLayerRect.left,
-                                mScrollingLayerRect.top);
-                        invalidate();
+                        scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX,
+                                mScrollingLayerRect.top + mAutoScrollY);
                     }
                     sendEmptyMessageDelayed(
                             SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b106cc5..f422f60 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -131,7 +131,6 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
 import android.view.textservice.SpellCheckerSubtype;
 import android.view.textservice.TextServicesManager;
 import android.widget.AdapterView.OnItemClickListener;
@@ -5342,7 +5341,6 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_ENTER:
-                mEnterKeyIsDown = true;
                 if (event.hasNoModifiers()) {
                     // When mInputContentType is set, we know that we are
                     // running in a "modern" cupcake environment, so don't need
@@ -5374,7 +5372,6 @@
                 break;
                 
             case KeyEvent.KEYCODE_DPAD_CENTER:
-                mDPadCenterIsDown = true;
                 if (event.hasNoModifiers()) {
                     if (shouldAdvanceFocusOnEnter()) {
                         return 0;
@@ -5488,7 +5485,6 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
-                mDPadCenterIsDown = false;
                 if (event.hasNoModifiers()) {
                     /*
                      * If there is a click listener, just call through to
@@ -5513,7 +5509,6 @@
                 return super.onKeyUp(keyCode, event);
 
             case KeyEvent.KEYCODE_ENTER:
-                mEnterKeyIsDown = false;
                 if (event.hasNoModifiers()) {
                     if (mInputContentType != null
                             && mInputContentType.onEditorActionListener != null
@@ -8972,17 +8967,9 @@
     }
 
     private long getLastTouchOffsets() {
-        int minOffset, maxOffset;
-
-        if (mContextMenuTriggeredByKey) {
-            minOffset = getSelectionStart();
-            maxOffset = getSelectionEnd();
-        } else {
-            SelectionModifierCursorController selectionController = getSelectionController();
-            minOffset = selectionController.getMinTouchOffset();
-            maxOffset = selectionController.getMaxTouchOffset();
-        }
-
+        SelectionModifierCursorController selectionController = getSelectionController();
+        final int minOffset = selectionController.getMinTouchOffset();
+        final int maxOffset = selectionController.getMaxTouchOffset();
         return packRangeInLong(minOffset, maxOffset);
     }
 
@@ -9075,12 +9062,6 @@
     private static final int ID_COPY = android.R.id.copy;
     private static final int ID_PASTE = android.R.id.paste;
 
-    private class MenuHandler implements MenuItem.OnMenuItemClickListener {
-        public boolean onMenuItemClick(MenuItem item) {
-            return onTextContextMenuItem(item.getItemId());
-        }
-    }
-
     /**
      * Called when a context menu option for the text view is selected.  Currently
      * this will be one of {@link android.R.id#selectAll}, {@link android.R.id#cut},
@@ -11480,12 +11461,6 @@
     private boolean                 mSelectionControllerEnabled;
     private boolean                 mInBatchEditControllers;
 
-    // These are needed to desambiguate a long click. If the long click comes from ones of these, we
-    // select from the current cursor position. Otherwise, select from long pressed position.
-    private boolean                 mDPadCenterIsDown = false;
-    private boolean                 mEnterKeyIsDown = false;
-    private boolean                 mContextMenuTriggeredByKey = false;
-
     private boolean                 mSelectAllOnFocus = false;
 
     private int                     mGravity = Gravity.TOP | Gravity.START;
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index aba3a72..b9f3738 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -35,18 +35,25 @@
 } gFallbackActionClassInfo;
 
 
-static jint nativeLoad(JNIEnv *env, jobject clazz, jint deviceId) {
+static jint nativeLoad(JNIEnv *env, jobject clazz, jstring fileStr) {
+    const char* file = env->GetStringUTFChars(fileStr, NULL);
+
     KeyCharacterMap* map;
-    status_t status = KeyCharacterMap::loadByDeviceId(deviceId, &map);
+    status_t status = KeyCharacterMap::load(String8(file), &map);
+    jint result;
     if (status) {
         String8 msg;
-        msg.appendFormat("Could not load key character map for device %d due to error %d.  "
-                "Refer to the log for details.", deviceId, status);
+        msg.appendFormat("Could not load key character map '%s' due to error %d.  "
+                "Refer to the log for details.", file, status);
         jniThrowException(env, "android/view/KeyCharacterMap$KeyCharacterMapUnavailableException",
                 msg.string());
-        return 0;
+        result = 0;
+    } else {
+        result = reinterpret_cast<jint>(map);
     }
-    return reinterpret_cast<jint>(map);
+
+    env->ReleaseStringUTFChars(fileStr, file);
+    return result;
 }
 
 static void nativeDispose(JNIEnv *env, jobject clazz, jint ptr) {
@@ -141,7 +148,7 @@
 
 static JNINativeMethod g_methods[] = {
     /* name, signature, funcPtr */
-    { "nativeLoad", "(I)I",
+    { "nativeLoad", "(Ljava/lang/String;)I",
             (void*)nativeLoad },
     { "nativeDispose", "(I)V",
             (void*)nativeDispose },
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 2392618..b0f1bc5 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -19,6 +19,8 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:orientation="vertical"
     android:fitsSystemWindows="true">
     <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index 19b861c..2a8c7c3 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -19,38 +19,45 @@
 the Action Bar enabled overlaying application content.
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fitsSystemWindows="true">
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/actionBarStyle"
-        android:gravity="top">
-        <com.android.internal.widget.ActionBarView
-            android:id="@+id/action_bar"
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="top">
+        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/actionBarStyle" />
-        <com.android.internal.widget.ActionBarContextView
-            android:id="@+id/action_context_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            style="?android:attr/actionModeStyle" />
-    </com.android.internal.widget.ActionBarContainer>
-    <ImageView android:src="?android:attr/windowContentOverlay"
-               android:scaleType="fitXY"
-               android:layout_width="match_parent"
-               android:layout_height="wrap_content"
-               android:layout_below="@id/action_bar_container" />
+            android:layout_alignParentTop="true"
+            style="?android:attr/actionBarStyle"
+            android:gravity="top">
+            <com.android.internal.widget.ActionBarView
+                android:id="@+id/action_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="?android:attr/actionBarStyle" />
+            <com.android.internal.widget.ActionBarContextView
+                android:id="@+id/action_context_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                style="?android:attr/actionModeStyle" />
+        </com.android.internal.widget.ActionBarContainer>
+        <ImageView android:src="?android:attr/windowContentOverlay"
+                   android:scaleType="fitXY"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:layout_below="@id/action_bar_container" />
+    </LinearLayout>
     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
-                  android:layout_alignParentBottom="true"
+                  android:layout_gravity="bottom"
                   style="?android:attr/actionBarSplitStyle"
                   android:visibility="gone"
                   android:gravity="center"/>
-</RelativeLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/screen_simple.xml b/core/res/res/layout/screen_simple.xml
index 87c29f6..c1914e7 100644
--- a/core/res/res/layout/screen_simple.xml
+++ b/core/res/res/layout/screen_simple.xml
@@ -22,6 +22,8 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     android:orientation="vertical">
     <ViewStub android:id="@+id/action_mode_bar_stub"
diff --git a/core/res/res/layout/screen_simple_overlay_action_mode.xml b/core/res/res/layout/screen_simple_overlay_action_mode.xml
index eb093e7..c790d10 100644
--- a/core/res/res/layout/screen_simple_overlay_action_mode.xml
+++ b/core/res/res/layout/screen_simple_overlay_action_mode.xml
@@ -21,6 +21,8 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:fitsSystemWindows="true">
     <FrameLayout
          android:id="@android:id/content"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4eb47cd..c488116 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -171,7 +171,7 @@
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Kry toegang tot beskikbare rekeninge."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardewarekontroles"</string>
     <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkte toegang tot hardeware op die selfoon."</string>
-    <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"foonoproepe"</string>
+    <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Foonoproepe"</string>
     <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitor, neem op, en verwerk foonoproepe."</string>
     <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Stelselhulpmiddels"</string>
     <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Laervlak-toegang en -beheer van die stelsel."</string>
@@ -991,8 +991,8 @@
     <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Kon nie jou SD-kaart vir USB-massaberging gebruik nie."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB gekoppel"</string>
     <string name="usb_storage_notification_message" msgid="7380082404288219341">"Kies om lêers na/van jou rekenaar te kopieer."</string>
-    <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Skakel USB-geheue af"</string>
-    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Kies om USB-geheue af te skakel."</string>
+    <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Skakel USB-berging af"</string>
+    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Kies om USB-berging af te skakel."</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB-berging in gebruik"</string>
     <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Voordat jy USB-berging afskakel, maak seker dat jy jou Android se USB-berging van jou rekenaar ontheg (\"uitgestoot\") het."</string>
     <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Voordat jy die USB-berging afskakel, maak seker dat jy jou Android se SD-kaart uit die rekenaar ontheg (uitgeskiet) het."</string>
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index 5819afc..57011d7 100644
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s - %6$s، %8$s %7$s، %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE، d MMMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
index d662590..0b9da23 100644
--- a/core/res/res/values-ar/donottranslate-cldr.xml
+++ b/core/res/res/values-ar/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s - %6$s، %8$s %7$s، %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE، d MMMM y</string>
 </resources>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
index dc8b3ad..972d661 100644
--- a/core/res/res/values-bg/donottranslate-cldr.xml
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">d MMMM, EEEE</string>
+    <string name="abbrev_wday_month_day_no_year">d MMMM, EEE</string>
     <string name="abbrev_wday_month_day_year">d MMM yyyy, E</string>
 </resources>
diff --git a/core/res/res/values-ca-rES/donottranslate-cldr.xml b/core/res/res/values-ca-rES/donottranslate-cldr.xml
index 52c33d8..113133d 100644
--- a/core/res/res/values-ca-rES/donottranslate-cldr.xml
+++ b/core/res/res/values-ca-rES/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
index a77aa38..03cf69d 100644
--- a/core/res/res/values-ca/donottranslate-cldr.xml
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index a026734..59b82d3 100644
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">E d. MMMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
index b078385..1dfc96c 100644
--- a/core/res/res/values-da/donottranslate-cldr.xml
+++ b/core/res/res/values-da/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s d. %3$s. %2$s - %6$s d. %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 97ad227..27d0be3 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -159,7 +159,7 @@
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
     <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Tillader, at en applikation kan gøre ting, som kan koste penge."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
-    <string name="permgroupdesc_messages" msgid="7045736972019211994">"Læs og skriv dine sms-, e-mail- og andre beskeder."</string>
+    <string name="permgroupdesc_messages" msgid="7045736972019211994">"Læs og skriv dine sms-, e-mail og andre beskeder."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Dine personlige oplysninger"</string>
     <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Få direkte adgang til dine kontakter og din kalender, der er gemt på tabletcomputeren."</string>
     <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Få direkte adgang til dine kontakter og din kalender, der er gemt på telefonen."</string>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index 6b4bf5c..8b834db 100644
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
index 75c11b90..1e7caa4 100644
--- a/core/res/res/values-el/donottranslate-cldr.xml
+++ b/core/res/res/values-el/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index 02c4ece..557833e 100644
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index 446855e..2aa7cbe 100644
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s - %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, MMMM d</string>
     <string name="abbrev_wday_month_day_year">E, MMM d, yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index 0879d0f..cce895e 100644
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index b611f7a..46b13ec 100644
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 0a8ae5a..177bd7e 100644
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index 329b268..41a00a5 100644
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index a94fb58..15fcd8b 100644
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, MMM d, yyyy</string>
 </resources>
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 7538611..7a5bdbd 100644
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E dd MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 1a59c4bc..e2c3254 100644
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s al %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d \'de\' MMMM</string>
     <string name="abbrev_wday_month_day_year">E d \'de\' MMM \'de\' yyyy</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a5caabf..aa38493 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1024,7 +1024,7 @@
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Verificando errores"</string>
     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Almacenamiento USB en blanco"</string>
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Tarjeta SD vacía"</string>
-    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"Almacenamiento USB en blanco o sistema de archivos no compatible."</string>
+    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"Almacenamiento USB vacío o sistema de archivos no compatible"</string>
     <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"Tarjeta SD en blanco o el sistema de archivos no es compatible."</string>
     <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Almacenamiento USB dañado"</string>
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Tarjeta SD dañada"</string>
@@ -1032,7 +1032,7 @@
     <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Tarjeta SD dañada. Es posible que debas reformatearla."</string>
     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Almacenamiento USB extraído inesperadamente"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Almacenamiento USB extraído de forma imprevista"</string>
-    <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Desmontar el almacenamiento USB antes de extraerlo para evitar la pérdida de datos."</string>
+    <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Desactivar el almacenamiento USB antes de extraerlo para evitar la pérdida de datos."</string>
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
     <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Es seguro extraer el almacenamiento USB"</string>
     <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Es seguro extraer la tarjeta SD"</string>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index 206b56d..faf171a 100644
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s – %6$s %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d \'de\' MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d \'de\' MMM \'de\' yyyy</string>
 </resources>
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
index 83f4942..11473fe 100644
--- a/core/res/res/values-fa/donottranslate-cldr.xml
+++ b/core/res/res/values-fa/donottranslate-cldr.xml
@@ -131,5 +131,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s LLL تا %6$s %8$s %2$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d LLLL</string>
+    <string name="abbrev_wday_month_day_no_year">E d LLLL</string>
     <string name="abbrev_wday_month_day_year">E d MMM y</string>
 </resources>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index ddcc0ea..e9e1a25 100644
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
index 5146a0a..71cccf3 100644
--- a/core/res/res/values-fi/donottranslate-cldr.xml
+++ b/core/res/res/values-fi/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index 86b8d19..840f728 100644
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">du %1$s %3$s %2$s au %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 00cb965..6bfd3de 100644
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
index dfcded5..a601d93 100644
--- a/core/res/res/values-hr-rHR/donottranslate-cldr.xml
+++ b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.%9$s.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d.MMM.yyyy.</string>
 </resources>
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
index 23332aa..9b51862 100644
--- a/core/res/res/values-hr/donottranslate-cldr.xml
+++ b/core/res/res/values-hr/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.%9$s.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d.MMM.y.</string>
 </resources>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 553667b..afb7676 100644
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE MMMM d</string>
     <string name="abbrev_wday_month_day_year">yyyy. MMM d., E</string>
 </resources>
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
index 996eefb..28b65bc 100644
--- a/core/res/res/values-hu/donottranslate-cldr.xml
+++ b/core/res/res/values-hu/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">y. MMM d., E</string>
 </resources>
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
index 4d4ebb2..b79fe00 100644
--- a/core/res/res/values-in-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-in-rID/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE MMMM d</string>
     <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
index 7a58a19..9a634cc 100644
--- a/core/res/res/values-in/donottranslate-cldr.xml
+++ b/core/res/res/values-in/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
 </resources>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 8af25f2..8cee828 100644
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
index d373a34..02d1e9c 100644
--- a/core/res/res/values-iw/donottranslate-cldr.xml
+++ b/core/res/res/values-iw/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 250415c..fd248e5 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -137,7 +137,7 @@
     <string name="turn_off_radio" msgid="8198784949987062346">"כבה אלחוטי"</string>
     <string name="screen_lock" msgid="799094655496098153">"נעילת מסך"</string>
     <string name="power_off" msgid="4266614107412865048">"כיבוי"</string>
-    <string name="shutdown_progress" msgid="2281079257329981203">"מבצע כיבוי..."</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>
     <string name="shutdown_confirm_question" msgid="6656441286856415014">"האם ברצונך לבצע כיבוי?"</string>
@@ -740,7 +740,7 @@
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"כתוב את ההיסטוריה והסימניות של הדפדפן"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"מאפשר ליישום לשנות את ההיסטוריה או את הסימניות של הדפדפן המאוחסנות בטבלט. יישומים זדוניים עלולים להשתמש ביכולת זו כדי למחוק או לשנות את הנתונים בדפדפן."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"מאפשר ליישום לשנות את ההיסטוריה או הסימניות של הדפדפן המאוחסנות בטלפון. יישומים זדוניים עלולים להשתמש ביכולת זו כדי למחוק או לשנות את נתוני הדפדפן."</string>
-    <string name="permlab_setAlarm" msgid="5924401328803615165">"הגדר התראה בשעון המעורר"</string>
+    <string name="permlab_setAlarm" msgid="5924401328803615165">"הגדר צלצול בשעון המעורר"</string>
     <string name="permdesc_setAlarm" msgid="5966966598149875082">"מאפשר ליישום להגדיר התראה ביישום מותקן של שעון מעורר. ייתכן שיישומי שעון מעורר מסוימים לא יישמו תכונה זו."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"הוסף דואר קולי"</string>
     <string name="permdesc_addVoicemail" msgid="4828507394878206682">"מאפשר ליישום להוסיף הודעות לתיבת הדואר הנכנס של הדואר הקולי."</string>
@@ -895,8 +895,8 @@
     <string name="chooseUsbActivity" msgid="7892597146032121735">"בחר יישום עבור מכשיר ה-USB"</string>
     <string name="noApplications" msgid="1691104391758345586">"אין יישומים שיכולים לבצע פעולה זו."</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="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>
     <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g> אינו מגיב."\n\n" האם ברצונך לסגור אותו?"</string>
     <string name="anr_activity_process" msgid="7018289416670457797">"פעילות <xliff:g id="ACTIVITY">%1$s</xliff:g> אינה מגיבה."\n\n"האם ברצונך לסגור אותה?"</string>
@@ -940,8 +940,8 @@
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"עוצמת קול של שיחות"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"עוצמת קול של מדיה"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת קול של התראות"</string>
-    <string name="ringtone_default" msgid="3789758980357696936">"רינגטון המוגדר כברירת מחדל"</string>
-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"רינגטון המוגדר כברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_default" msgid="3789758980357696936">"רינגטון ברירת מחדל"</string>
+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"רינגטון ברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="4440324407807468713">"שקט"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"רינגטונים"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"רינגטון לא ידוע"</string>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index 7447abc..450adc3 100644
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日 (%1$s)~%7$s%8$s日 (%6$s)</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">M月d日 (E)</string>
+    <string name="abbrev_wday_month_day_no_year">M月d日 (E)</string>
     <string name="abbrev_wday_month_day_year">yyyy年M月d日 (E)</string>
 </resources>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index cdbd65e..5382871 100644
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s년 %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">MMMM d일 EEEE</string>
+    <string name="abbrev_wday_month_day_no_year">MMMM d일 EEE</string>
     <string name="abbrev_wday_month_day_year">yyyy년 MMM d일 EEE</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 6aac520..ee098d5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -223,7 +223,7 @@
     <string name="permlab_forceStopPackages" msgid="1447830113260156236">"다른 애플리케이션 강제 종료"</string>
     <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"애플리케이션이 다른 애플리케이션을 강제로 종료할 수 있도록 합니다."</string>
     <string name="permlab_forceBack" msgid="1804196839880393631">"강제로 애플리케이션 닫기"</string>
-    <string name="permdesc_forceBack" msgid="6534109744159919013">"애플리케이션이 포그라운드에 있는 활동을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
+    <string name="permdesc_forceBack" msgid="6534109744159919013">"애플리케이션이 포그라운드에 있는 작업을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
     <string name="permlab_dump" msgid="1681799862438954752">"시스템 내부 상태 검색"</string>
     <string name="permdesc_dump" msgid="2198776174276275220">"애플리케이션이 시스템의 내부 상태를 검색할 수 있도록 합니다. 단, 악성 애플리케이션이 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인정보와 보안정보를 검색할 수 있습니다."</string>
     <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"화면 콘텐츠 검색"</string>
@@ -446,7 +446,7 @@
     <string name="permdesc_useCredentials" msgid="7416570544619546974">"애플리케이션이 인증 토큰을 요청하도록 합니다."</string>
     <string name="permlab_accessNetworkState" msgid="6865575199464405769">"네트워크 상태 보기"</string>
     <string name="permdesc_accessNetworkState" msgid="558721128707712766">"애플리케이션이 모든 네트워크의 상태를 볼 수 있도록 합니다."</string>
-    <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"인터넷에 최대한 액세스"</string>
+    <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"인터넷 액세스"</string>
     <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"애플리케이션이 네트워크 소켓을 만들 수 있도록 합니다."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"네트워크 설정 및 트래픽 차단/변경"</string>
     <string name="permdesc_writeApnSettings" msgid="2369786339323021771">"애플리케이션이 모든 네트워크 트래픽을 가로채고 검사하거나 네트워크 설정을 변경하도록 허용합니다. 예를 들어 프록시나 APN의 포트를 변경할 수 있습니다. 악성 애플리케이션이 사용자 모르게 네트워크 패킷을 모니터링하고 리디렉션하며 수정할 수도 있습니다."</string>
@@ -899,7 +899,7 @@
     <string name="aerr_process" msgid="4507058997035697579">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 중지되었습니다."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g>이(가) 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
-    <string name="anr_activity_process" msgid="7018289416670457797">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동이 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
+    <string name="anr_activity_process" msgid="7018289416670457797">"<xliff:g id="ACTIVITY">%1$s</xliff:g>이(가) 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
     <string name="anr_application_process" msgid="7208175830253210526">"<xliff:g id="APPLICATION">%1$s</xliff:g>이(가) 응답하지 않습니다. 닫으시겠습니까?"</string>
     <string name="anr_process" msgid="306819947562555821">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."\n\n"닫으시겠습니까?"</string>
     <string name="force_close" msgid="8346072094521265605">"확인"</string>
@@ -1208,7 +1208,7 @@
     <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 지문:"</string>
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 지문:"</string>
     <string name="activity_chooser_view_see_all" msgid="180268188117163072">"전체 보기..."</string>
-    <string name="activity_chooser_view_dialog_title_default" msgid="3325054276356556835">"활동 선택"</string>
+    <string name="activity_chooser_view_dialog_title_default" msgid="3325054276356556835">"작업 선택"</string>
     <string name="share_action_provider_share_with" msgid="1791316789651185229">"공유 대상..."</string>
     <string name="status_bar_device_locked" msgid="3092703448690669768">"기기가 잠겼습니다."</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 982f993..0c1d0aa 100644
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d., %1$s-%7$s %8$s d., %6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">MMMM d \'d\'., EEEE</string>
+    <string name="abbrev_wday_month_day_no_year">MMMM d \'d\'., EEE</string>
     <string name="abbrev_wday_month_day_year">yyyy \'m\'. MMM d \'d\'., E</string>
 </resources>
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
index 25458bd..8a2c0f4 100644
--- a/core/res/res/values-lt/donottranslate-cldr.xml
+++ b/core/res/res/values-lt/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d.,%1$s - %7$s %8$s d.,%6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">y \'m\'. MMM d \'d\'.,E</string>
 </resources>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index c4000b0..9dbc5e05 100644
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s. gada %3$s. %2$s-%6$s, y. gada %8$s. %7$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, yyyy. \'g\'. dd. MMM</string>
 </resources>
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
index 2de9367..10dcd35 100644
--- a/core/res/res/values-lv/donottranslate-cldr.xml
+++ b/core/res/res/values-lv/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s. gada %3$s. %2$s - %6$s, y. gada %8$s. %7$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, yyyy. \'g\'. dd. MMM</string>
 </resources>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index 512eb01..637dd5e 100644
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s–%6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 3db9e69..ca3813f 100644
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index baff798..2950e60 100644
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s-%6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index 25dc7b3..54417a4 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d \'de\' MMM \'de\' yyyy</string>
 </resources>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 4431877..d999c06 100644
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d \'de\' MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d \'de\' MMM \'de\' yyyy</string>
 </resources>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index 3e425f0..732ae24 100644
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
index ef34103..e9a70dc 100644
--- a/core/res/res/values-ro/donottranslate-cldr.xml
+++ b/core/res/res/values-ro/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index 8399424..2fbcd43 100644
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d66c2d4..44f4d10 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -348,7 +348,7 @@
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"точное местоположение (GPS)"</string>
     <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Получать доступ к источникам точного местоположения, таким как GPS, когда это возможно. Вредоносные приложения могут использовать это разрешение для определения вашего местоположения и расходовать ресурс батареи."</string>
     <string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Получать доступ к источникам точного местоположения, таким как GPS, если возможно. Вредоносные приложения могут использовать это разрешение для определения вашего местоположения и расходовать ресурс батареи."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"отслеживать местоположение по сигналам сети"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"примерное местоположение по координатам сети"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Получать доступ к источникам данных о местоположении, таким как база данных сотовой сети, для определения приблизительного местоположения планшетного ПК, когда это возможно. Вредоносные приложения могут использовать это разрешение для определения вашего приблизительного местоположения."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Получать доступ к источникам данных о местоположении, таким как база данных сотовой сети, для определения приблизительного местоположения телефона, если возможно. Вредоносные приложения могут использовать эту возможность для определения вашего приблизительного местоположения."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"получать доступ к SurfaceFlinger"</string>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 32272ea..2843ae3 100644
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
index b2ed9b7..dcdaad1 100644
--- a/core/res/res/values-sk/donottranslate-cldr.xml
+++ b/core/res/res/values-sk/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E, d. MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d. MMM y</string>
 </resources>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index e4bc557..cbabccd 100644
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s–%6$s, %8$s. %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE MMMM d</string>
     <string name="abbrev_wday_month_day_year">E, d. MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
index 372b0d5..b804b3f 100644
--- a/core/res/res/values-sl/donottranslate-cldr.xml
+++ b/core/res/res/values-sl/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">E., d. MMM. y</string>
 </resources>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index 79752ab..7168bcc 100644
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, d. MMM yyyy.</string>
 </resources>
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
index 7c5c6a9..7426bdc 100644
--- a/core/res/res/values-sr/donottranslate-cldr.xml
+++ b/core/res/res/values-sr/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, d. MMM y.</string>
 </resources>
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
index bf688ce..8b7833f 100644
--- a/core/res/res/values-sv/donottranslate-cldr.xml
+++ b/core/res/res/values-sv/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index 85dc3b9..7049c52 100644
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
index 4e6bafe..f3196d1 100644
--- a/core/res/res/values-th/donottranslate-cldr.xml
+++ b/core/res/res/values-th/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
 </resources>
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
index e3106c7..6ff92e3 100644
--- a/core/res/res/values-tl/donottranslate-cldr.xml
+++ b/core/res/res/values-tl/donottranslate-cldr.xml
@@ -119,5 +119,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
     <string name="short_format_month">%B</string>
     <string name="full_wday_month_day_no_year">E MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">E MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
 </resources>
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
index 55b6d1f..92b0c72 100644
--- a/core/res/res/values-tr/donottranslate-cldr.xml
+++ b/core/res/res/values-tr/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %1$s - %8$s %7$s %6$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">dd MMMM EEEE</string>
+    <string name="abbrev_wday_month_day_no_year">dd MMMM EEE</string>
     <string name="abbrev_wday_month_day_year">dd MMM yyyy EEE</string>
 </resources>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index 332f845..caf46a3 100644
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s р.</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy \'р\'.</string>
 </resources>
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
index 0a49c20..46211ac 100644
--- a/core/res/res/values-uk/donottranslate-cldr.xml
+++ b/core/res/res/values-uk/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E, d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E, d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index b7edeb3..5d049a1 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, ngày %3$s %2$s - %6$s, ngày %8$s %7$s năm %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">EEE d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM yyyy</string>
 </resources>
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
index 30e0887..9a757cd 100644
--- a/core/res/res/values-vi/donottranslate-cldr.xml
+++ b/core/res/res/values-vi/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, ngày %3$s %2$s - %6$s, ngày %8$s %7$s năm %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">E d MMMM</string>
+    <string name="abbrev_wday_month_day_no_year">E d MMMM</string>
     <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index ec9d8c0..9e6ef1c 100644
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s 年 %2$s %3$s 日%1$s - %7$s %8$s 日%6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">M 月 d 日 E</string>
+    <string name="abbrev_wday_month_day_no_year">M 月 d 日 E</string>
     <string name="abbrev_wday_month_day_year">yyyy 年 M 月 d 日 EEE</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index a43f857..907d82e 100644
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s 年 %2$s %3$s 日%1$s至 %7$s %8$s 日%6$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">M 月 d 日E</string>
+    <string name="abbrev_wday_month_day_no_year">M 月 d 日E</string>
     <string name="abbrev_wday_month_day_year">yyyy 年 M 月 d 日EEE</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e88de76..05da503 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -136,7 +136,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"Vula okungenantambo"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Vala okungenantambo"</string>
     <string name="screen_lock" msgid="799094655496098153">"Ukuvala isikrini"</string>
-    <string name="power_off" msgid="4266614107412865048">"Amandla avaliwe"</string>
+    <string name="power_off" msgid="4266614107412865048">"Vala amandla"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Ivala shaqa..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ithebhulethi yakho izocima."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ifoni yakho izocima."</string>
@@ -146,7 +146,7 @@
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Okukhethwa konke kwethebhulethi"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Okukhethwa kukho kwefoni"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ukuvala isikrini"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"Amandla avaliwe"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Imodi ethulile"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Umsindo UVALIWE"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Umsindo UVULIWE"</string>
@@ -838,7 +838,7 @@
     <item quantity="one" msgid="2178576254385739855">"Kusasa"</item>
     <item quantity="other" msgid="2973062968038355991">"ezinsukwini ezing-<xliff:g id="COUNT">%d</xliff:g>"</item>
   </plurals>
-    <string name="preposition_for_date" msgid="9093949757757445117">"Ngomhla ka <xliff:g id="DATE">%s</xliff:g>"</string>
+    <string name="preposition_for_date" msgid="9093949757757445117">"ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"e-<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"phakathi- <xliff:g id="YEAR">%s</xliff:g>"</string>
     <string name="day" msgid="8144195776058119424">"usuku"</string>
@@ -886,7 +886,7 @@
     <string name="no" msgid="5141531044935541497">"Khansela"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Ukunaka"</string>
     <string name="loading" msgid="1760724998928255250">"Iyalayisha..."</string>
-    <string name="capital_on" msgid="1544682755514494298">"Ngomhla ka"</string>
+    <string name="capital_on" msgid="1544682755514494298">"VULIWE"</string>
     <string name="capital_off" msgid="6815870386972805832">"VALIWE"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Qedela isenzo usebenzisa"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Sebenzisa ngokuzenzakalelayo kulesenzo."</string>
@@ -1146,7 +1146,7 @@
     <string name="checkbox_not_checked" msgid="5174639551134444056">"akuhloliwe"</string>
     <string name="radiobutton_selected" msgid="8603599808486581511">"Okukhethiwe"</string>
     <string name="radiobutton_not_selected" msgid="2908760184307722393">"akukhethiwe"</string>
-    <string name="switch_on" msgid="551417728476977311">"Ngomhla ka-"</string>
+    <string name="switch_on" msgid="551417728476977311">"vuliwe"</string>
     <string name="switch_off" msgid="7249798614327155088">"valiwe"</string>
     <string name="togglebutton_pressed" msgid="4180411746647422233">"kucindezelwe."</string>
     <string name="togglebutton_not_pressed" msgid="4495147725636134425">"akucindezelwe."</string>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index a94fb58..15fcd8b 100644
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -145,5 +145,6 @@
     <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
     <string name="short_format_month">%b</string>
     <string name="full_wday_month_day_no_year">EEEE, MMMM d</string>
+    <string name="abbrev_wday_month_day_no_year">EEE, MMMM d</string>
     <string name="abbrev_wday_month_day_year">EEE, MMM d, yyyy</string>
 </resources>
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 01a5fd0..a781472 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -350,4 +350,4 @@
         }
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index e1db073..1df763a 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -256,6 +256,10 @@
         stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
         assertEquals(24, stats.size());
 
+        // try removing invalid data; should be no change
+        stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
+        assertEquals(24, stats.size());
+
         // try removing far before buckets; should be no change
         stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
         assertEquals(24, stats.size());
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 9fe2dde..6cd07a3 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -137,6 +137,7 @@
     <assign-permission name="android.permission.SET_ALWAYS_FINISH" uid="shell" />
     <assign-permission name="android.permission.DUMP" uid="shell" />
     <assign-permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES" uid="shell" />
+    <assign-permission name="android.permission.KILL_BACKGROUND_PROCESSES" uid="shell" />
     <!-- Internal permissions granted to the shell. -->
     <assign-permission name="android.permission.FORCE_BACK" uid="shell" />
     <assign-permission name="android.permission.BATTERY_STATS" uid="shell" />
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 0338685..af379de 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -797,6 +797,10 @@
       <li><a href="<?cs var:toroot ?>guide/practices/design/seamlessness.html">
             <span class="en">Designing for Seamlessness</span>
           </a></li>
+      <li><a href="<?cs var:toroot ?>guide/practices/security.html">
+            <span class="en">Designing for Security</span></a>
+            <span class="new">new!</span><!-- 11/7/10 -->
+          </li>
     </ul>
   </li>
 
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 3eebd59..6017583 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -476,7 +476,7 @@
 <ul>
   <li><code>CHECK_BILLING_SUPPORTED</code>&mdash;verifies that the Android Market application
   supports in-app billing.</li>
-  <li><code>REQUEST_PURCHASE</code>&mdash;sends a purchase request for an in-app item.</li> 
+  <li><code>REQUEST_PURCHASE</code>&mdash;sends a purchase request for an in-app item.</li>
   <li><code>GET_PURCHASE_INFORMATION</code>&mdash;retrieves transaction information for a purchase
   or refund.</li>
   <li><code>CONFIRM_NOTIFICATIONS</code>&mdash;acknowledges that you received the transaction
@@ -584,9 +584,9 @@
   // Note that the developer payload is optional.
   if (mDeveloperPayload != null) {
     request.putString(DEVELOPER_PAYLOAD, mDeveloperPayload);
+  }
   Bundle response = mService.sendBillingRequest(request);
   // Do something with this response.
-  }
 </pre>
 <p>The <code>makeRequestBundle()</code> method constructs an initial Bundle, which contains the
 three keys that are required for all requests: <code>BILLING_REQUEST</code>,
@@ -930,9 +930,9 @@
 
 <pre>
 public class BillingReceiver extends BroadcastReceiver {
-  
+
   private static final String TAG = "BillingReceiver";
-  
+
   // Intent actions that we receive in the BillingReceiver from Android Market.
   // These are defined by Android Market and cannot be changed.
   // The sample application defines these in the Consts.java file.
@@ -940,7 +940,7 @@
   public static final String ACTION_RESPONSE_CODE = "com.android.vending.billing.RESPONSE_CODE";
   public static final String ACTION_PURCHASE_STATE_CHANGED =
     "com.android.vending.billing.PURCHASE_STATE_CHANGED";
-    
+
   // The intent extras that are passed in an intent from Android Market.
   // These are defined by Android Market and cannot be changed.
   // The sample application defines these in the Consts.java file.
diff --git a/docs/html/guide/practices/security.jd b/docs/html/guide/practices/security.jd
new file mode 100644
index 0000000..5da7e98
--- /dev/null
+++ b/docs/html/guide/practices/security.jd
@@ -0,0 +1,772 @@
+page.title=Designing for Security
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+<li><a href="#Dalvik">Using Davlik Code</a></li>
+<li><a href="#Native">Using Native Code</a></li>
+<li><a href="#Data">Storing Data</a></li>
+<li><a href="#IPC">Using IPC</a></li>
+<li><a href="#Permissions">Using Permissions</a></li>
+<li><a href="#Networking">Using Networking</a></li>
+<li><a href="#DynamicCode">Dynamically Loading Code</a></li>
+<li><a href="#Input">Performing Input Validation</a></li>
+<li><a href="#UserData">Handling User Data</a></li>
+<li><a href="#Crypto">Using Cryptography</a></li>
+</ol>
+<h2>See also</h2>
+<ol>
+<li><a href="http://source.android.com/tech/security/index.html">Android
+Security Overview</a></li>
+<li><a href="{@docRoot}guide/topics/security/security.html">Android Security
+And Permissions</a></li>
+</ol>
+</div></div>
+<p>Android was designed so that most developers will be able to build
+applications using the default settings and not be confronted with difficult
+decisions about security.  Android also has a number of security features built
+into the operating system that significantly reduce the frequency and impact of
+application security issues.</p>
+
+<p>Some of the security features that help developers build secure applications
+include:
+<ul>
+<li>The Android Application Sandbox that isolates data and code execution on a
+per-application basis.</li>
+<li>Android application framework with robust implementations of common
+security functionality such as cryptography, permissions, and secure IPC.</li>
+<li>Technologies like ASLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD
+calloc, and Linux mmap_min_addr to mitigate risks associated with common memory
+management errors</li>
+<li>An encrypted filesystem that can be enabled to protect data on lost or
+stolen devices.</li>
+</ul></p>
+
+<p>Nevertheless, it is important for developers to be familiar with Android
+security best practices to make sure they take advantage of these capabilities
+and to reduce the likelihood of inadvertently introducing security issues that
+can affect their applications.</p>
+
+<p>This document is organized around common APIs and development techniques
+that can have security implications for your application and its users. As
+these best practices are constantly evolving, we recommend you check back
+occasionally throughout your application development process.</p>
+
+<a name="Dalvik"></a>
+<h2>Using Dalvik Code</h2>
+<p>Writing secure code that runs in virtual machines is a well-studied topic
+and many of the issues are not specific to Android.  Rather than attempting to
+rehash these topics, we’d recommend that you familiarize yourself with the
+existing literature. Two of the more popular resources are:
+<ul>
+<li><a href="http://www.securingjava.com/toc.html">
+http://www.securingjava.com/toc.html</a></li>
+<li><a
+href="https://www.owasp.org/index.php/Java_Security_Resources">
+https://www.owasp.org/index.php/Java_Security_Resources</a></li>
+</ul></p>
+
+<p>This document is focused on the areas which are Android specific and/or
+different from other environments.  For developers experienced with VM
+programming in other environments, there are two broad issues that may be
+different about writing apps for Android:
+<ul>
+<li>Some virtual machines, such as the JVM or .net runtime, act as a security
+boundary, isolating code from the underlying operating system capabilities.  On
+Android, the Dalvik VM is not a security boundary -- the application sandbox is
+implemented at the OS level, so Dalvik can interoperate with native code in the
+same application without any security constraints.</li>
+<li>Given the limited storage on mobile devices, it’s common for developers
+to want to build modular applications and use dynamic class loading.  When
+doing this consider both the source where you retrieve your application logic
+and where you store it locally. Do not use dynamic class loading from sources
+that are not verified, such as unsecured network sources or external storage,
+since that code can be modified to include malicious behavior.</li>
+</ul></p>
+
+<a name="Native"></a>
+<h2>Using Native Code</h2>
+
+<p>In general, we encourage developers to use the Android SDK for most
+application development, rather than using native code.   Applications built
+with native code are more complex, less portable, and more like to include
+common memory corruption errors such as buffer overflows.</p>
+
+<p>Android is built using the Linux kernel and being familiar with Linux
+development security best practices is especially useful if you are going to
+use native code. This document is too short to discuss all of those best
+practices, but one of the most popular resources is  “Secure Programming for
+Linux and Unix HOWTO”, available at <a
+href="http://www.dwheeler.com/secure-programs">
+http://www.dwheeler.com/secure-programs</a>.</p>
+
+<p>An important difference between Android and most Linux environments is the
+Application Sandbox.  On Android, all applications run in the Application
+Sandbox, including those written with native code.  At the most basic level, a
+good way to think about it for developers familiar with Linux is to know that
+every application is given a unique UID with very limited permissions. This is
+discussed in more detail in the <a
+href="http://source.android.com/tech/security/index.html">Android Security
+Overview</a> and you should be familiar with application permissions even if
+you are using native code.</p>
+
+<a name="Data"></a>
+<h2>Storing Data</h2>
+
+<h3>Using internal files</h3>
+
+<p>By default, files created on <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal
+storage</a> are only accessible to the application that created the file. This
+protection is implemented by Android and is sufficient for most
+applications.</p>
+
+<p>Use of <a
+href="{@docRoot}reference/android/content/Context.html#MODE_WORLD_WRITEABLE">
+world writable</a> or <a
+href="{@docRoot}reference/android/content/Context.html#MODE_WORLD_READABLE
+">world readable</a> files for IPC is discouraged because it does not provide
+the ability to limit data access to particular applications, nor does it
+provide any control on data format. As an alternative, you might consider using
+a ContentProvider which provides read and write permissions, and can make
+dynamic permission grants on a case-by-case basis.</p>
+
+<p>To provide additional protection for sensitive data, some applications
+choose to encrypt local files using a key that is not accessible to the
+application. (For example, a key can be placed in a <code><a
+href={@docRoot}reference/java/security/KeyStore.html">KeyStore</a></code> and
+protected with a user password that is not stored on the device).  While this
+does not protect data from a root compromise that can monitor the user
+inputting the password,  it can provide protection for a lost device without <a
+href="http://source.android.com/tech/encryption/index.html">file system
+encryption</a>.</p>
+
+<h3>Using external storage</h3>
+
+<p>Files created on <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">external
+storage</a>, such as SD Cards, are globally readable and writable.  Since
+external storage can be removed by the user and also modified by any
+application,  applications should not store sensitive information using
+external storage.</p>
+
+<p>As with data from any untrusted source, applications should perform input
+validation when handling data from external storage (see Input Validation
+section).  We strongly recommend that applications not store executables or
+class files on external storage prior to dynamic loading.  If an application
+does retrieve executable files from external storage they should be signed and
+cryptographically verified prior to dynamic loading.</p>
+
+<h3>Using content providers</h3>
+
+<p>ContentProviders provide a structured storage mechanism that can be limited
+to your own application, or exported to allow access by other applications. By
+default, a <code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code> is
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">exported
+</a> for use by other applications.  If you do not intend to provide other
+applications with access to your<code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code>, mark them as <code><a
+href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
+android:exported=false</a></code> in the application manifest.</p>
+
+<p>When creating a <code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">ContentProvider
+</a></code> that will be exported for use by other applications, you can specify
+a single
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">permission
+</a> for reading and writing, or distinct permissions for reading and writing
+within the manifest. We recommend that you limit your permissions to those
+required to accomplish the task at hand. Keep in mind that it’s usually
+easier to add permissions later to expose new functionality than it is to take
+them away and break existing users.</p>
+
+<p>If you are using a <code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code> for sharing data between applications built by the
+same developer, it is preferable to use
+<a href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">signature
+level permissions</a>.  Signature permissions do not require user confirmation,
+so they provide a better user experience and more controlled access to the
+<code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code>.</p>
+
+<p>ContentProviders can also provide more granular access by declaring the <a
+href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+grantUriPermissions</a> element and using the <code><a
+href="{@docRoot}reference/android/content/Intent.html#FLAG_GRANT_READ_URI_PERMIS
+SION">FLAG_GRANT_READ_URI_PERMISSION</a></code> and <code><a
+href="{@docRoot}reference/android/content/Intent.html#FLAG_GRANT_WRITE_URI_PERMI
+SSION">FLAG_GRANT_WRITE_URI_PERMISSION</a></code> flags in the Intent object
+that activates the component.  The scope of these permissions can be further
+limited by the <code><a
+href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+grant-uri-permission element</a></code>.</p>
+
+<p>When accessing a <code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code>, use parameterized query methods such as <code>
+<a href="{@docRoot}reference/android/content/ContentProvider.html#query(android.net
+.Uri,%20java.lang.String[],%20java.lang.String,%20java.lang.String[],%20java.lan
+g.String)">query()</a></code>, <code><a
+href="{@docRoot}reference/android/content/ContentProvider.html#update(android.ne
+t.Uri,%20android.content.ContentValues,%20java.lang.String,%20java.lang.String[]
+)">update()</a></code>, and <code><a
+href="{@docRoot}reference/android/content/ContentProvider.html#delete(android.ne
+t.Uri,%20java.lang.String,%20java.lang.String[])">delete()</a></code> to avoid
+potential <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL
+Injection</a> from untrusted data. Note that using parameterized methods is not
+sufficient if the <code>selection</code> is built by concatenating user data
+prior to submitting it to the method.</p>
+
+<p>Do not have a false sense of security about the write permission.  Consider
+that the write permission allows SQL statements which make it possible for some
+data to be confirmed using creative <code>WHERE</code> clauses and parsing the
+results. For example, an attacker might probe for presence of a specific phone
+number in a call-log by modifying a row only if that phone number already
+exists. If the content provider data has predictable structure, the write
+permission may be equivalent to providing both reading and writing.</p>
+
+<a name="IPC"></a>
+<h2>Using Interprocess Communication (IPC)</h2>
+
+<p>Some Android applications attempt to implement IPC using traditional Linux
+techniques such as network sockets and shared files.  We strongly encourage the
+use of Android system functionality for IPC such as Intents, Binders, Services,
+and Receivers.  The Android IPC mechanisms allow you to verify the identity of
+the application connecting to your IPC and set security policy for each IPC
+mechanism.</p>
+
+<p>Many of the security elements are shared across IPC mechanisms. <a
+href="{@docRoot}reference/android/content/BroadcastReceiver.html">
+Broadcast Receivers</a>, <a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestActivity">
+Activities</a>, and <a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestService">
+Services</a> are all declared in the application manifest.  If your IPC mechanism is
+not intended for use by other applications, set the android:exported property
+to false.  This is useful for applications that consist of multiple processes
+within the same UID, or if you decide late in development that you do not
+actually want to expose functionality as IPC but you don’t want to rewrite
+the code.</p>
+
+<p>If your IPC is intended to be accessible to other applications, you can
+apply a security policy by using the <a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestPermission">
+Permission</a> tag. If IPC is between applications built by the same developer,
+it is preferable to use <a
+href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">signature
+level permissions</a>.  Signature permissions do not require user confirmation,
+so they provide a better user experience and more controlled access to the IPC
+mechanism.</p>
+
+<p>One area that can introduce confusion is the use of intent filters. Note
+that Intent filters should not be considered a security feature -- components
+can be invoked directly and may not have data that would conform to the intent
+filter. You should perform input validation within your intent receiver to
+confirm that it is properly formatted for the invoked receiver, service, or
+activity.</p>
+
+<h3>Using intents</h3>
+
+<p>Intents are the preferred mechanism for asynchronous IPC in Android.
+Depending on your application requirements, you might use <code><a
+href="{@docRoot}reference/android/content/Context.html#sendBroadcast(android.con
+tent.Intent)">sendBroadcast()</a></code>, <code><a
+href="{@docRoot}reference/android/content/Context.html#sendOrderedBroadcast(andr
+oid.content.Intent,%20java.lang.String)">sendOrderedBroadcast()</a></code>, or
+direct an intent to a specific application component.</p>
+
+<p>Note that ordered broadcasts can be “consumed” by a recipient, so they
+may not be delivered to all applications.  If you are sending an Intent where
+delivery to a specific receiver is required, the intent must be delivered
+directly to the receiver.</p>
+
+<p>Senders of an intent can verify that the recipient has a permission
+specifying a non-Null Permission upon sending.  Only applications with that
+Permission will receive the intent.  If data within a broadcast intent may be
+sensitive, you should consider applying a permission to make sure that
+malicious applications cannot register to receive those messages without
+appropriate permissions.  In those circumstances, you may also consider
+invoking the receiver directly, rather than raising a broadcast.</p>
+
+<h3>Using binder and AIDL interfaces</h3>
+
+<p><a href="{@docRoot}reference/android/os/Binder.html">Binders</a> are the
+preferred mechanism for RPC-style IPC in Android. They provide a well-defined
+interface that enables mutual authentication of the endpoints, if required.</p>
+
+<p>We strongly encourage designing interfaces in a manner that does not require
+interface specific permission checks. Binders are not declared within the
+application manifest, and therefore you cannot apply declarative permissions
+directly to a Binder.  Binders generally inherit permissions declared in the
+application manifest for the Service or Activity within which they are
+implemented.  If you are creating an interface that requires authentication
+and/or access controls on a specific binder interface, those controls must be
+explicitly added as code in the interface.</p>
+
+<p>If providing an interface that does require access controls, use <code><a
+href="{@docRoot}reference/android/content/Context.html#checkCallingPermission(ja
+va.lang.String)">checkCallingPermission()</a></code> to verify whether the
+caller of the Binder has a required permission. This is especially important
+before accessing a Service on behalf of the caller, as the identify of your
+application is passed to other interfaces.  If invoking an interface provided
+by a Service, the <code><a
+href="{@docRoot}reference/android/content/Context.html#bindService(android.conte
+nt.Intent,%20android.content.ServiceConnection,%20int)">bindService()</a></code>
+ invocation may fail if you do not have permission to access the given Service.
+ If calling an interface provided locally by your own application, it may be
+useful to use the <code><a
+href="{@docRoot}reference/android/os/Binder.html#clearCallingIdentity()">
+clearCallingIdentity()</a></code> to satisfy internal security checks.</p>
+
+<h3>Using broadcast receivers</h3>
+
+<p>Broadcast receivers are used to handle asynchronous requests initiated via
+an intent.</p>
+
+<p>By default, receivers are exported and can be invoked by any other
+application. If your <code><a
+href={@docRoot}reference/android/content/BroadcastReceiver.html">
+BroadcastReceivers</a></code> is intended for use by other applications, you
+may want to apply security permissions to receivers using the <code><a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestReceiver">
+&lt;receiver&gt;</a></code> element within the application manifest.  This will
+prevent applications without appropriate permissions from sending an intent to
+the <code><a
+href={@docRoot}reference/android/content/BroadcastReceiver.html">
+BroadcastReceivers</a></code>.</p>
+
+<h3>Using Services</h3>
+
+<p>Services are often used to supply functionality for other applications to
+use. Each service class must have a corresponding <service> declaration in its
+package's AndroidManifest.xml.</p>
+
+<p>By default, Services are exported and can be invoked by any other
+application.  Services can be protected using the android:permission attribute
+within the manifest’s <code><a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestService">
+&lt;service&gt;</a></code> tag. By doing so, other applications will need to declare
+a corresponding <code><a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestService_permis
+sion">&lt;uses-permission&gt;</a></code> element in their own manifest to be
+able to start, stop, or bind to the service.</p>
+
+<p>A Service can protect individual IPC calls into it with permissions, by
+calling <code><a
+href="{@docRoot}reference/android/content/Context.html#checkCallingPermission(ja
+va.lang.String)">checkCallingPermission()</a></code>before executing
+the implementation of that call.  We generally recommend using the
+declarative permissions in the manifest, since those are less prone to
+oversight.</p>
+
+<h3>Using Activities</h3>
+
+<p>Activities are most often used for providing the core user-facing
+functionality of an application. By default, Activities are exported and
+invokable by other applications only if they have an intent filter or binder
+declared.  In general, we recommend that you specifically declare a Receiver or
+Service to handle IPC, since this modular approach reduces the risk of exposing
+functionality that is not intended for use by other applications.</p>
+
+<p>If you do expose an Activity for purposes of IPC, the  <code><a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestActivity_permi
+ssion">android:permission</a></code> attribute in the  <code><a
+href="{@docRoot}reference/android/R.styleable.html#AndroidManifestActivity">
+&lt;activity&gt;</a></code> declaration in the application manifest can be used to
+restrict access to only those applications which have the stated
+permissions.</p>
+
+<a name="Permissions"></a>
+<h2>Using Permissions</h2>
+
+<h3>Requesting Permissions</h3>
+
+<p>We recommend minimizing the number of permissions requested by an
+application. Not having access to sensitive permissions reduces the risk of
+inadvertently misusing those permissions, can improve user adoption, and makes
+applications less attractive targets for attackers.</p>
+
+<p>If it is possible to design your application in a way that does not require
+a permission, that is preferable.  For example, rather than requesting access
+to device information to create an identifier, create a <a
+href="{@docRoot}reference/java/util/UUID.html">GUID</a> for your application.
+(This specific example is also discussed in Handling User Data) Or, rather than
+using external storage, store data in your application directory.</p>
+
+<p>If a permission is not required, do not request it.  This sounds simple, but
+there has been quite a bit of research into the frequency of over-requesting
+permissions. If you’re interested in the subject you might start with this
+research paper published by U.C. Berkeley: <a
+href="http://www.eecs.berkeley.edu/Pubs/TechRpts/2011/EECS-2011-48.pdf">
+http://www.eecs.berkeley.edu/Pubs/TechRpts/2011/EECS-2011-48.pdf</a></p>
+
+<p>In addition to requesting permissions, your application can use <a
+href="{@docRoot}guide/topics/manifest/permission-element.html">permissions</a>
+to protect IPC that is security sensitive and will be exposed to other
+applications -- such as a <code><a
+href="{@docRoot}reference/android/content/ContentProvider.html">
+ContentProvider</a></code>.  In general, we recommend using access controls
+other than user confirmed permissions where possible since permissions can
+be confusing for users. For example, consider using the <a
+href="{@docRoot}guide/topics/manifest/permission-element.html#plevel">signature
+protection level</a> on permissions for IPC communication between applications
+provided by a single developer.</p>
+
+<p>Do not cause permission re-delegation.  This occurs when an app exposes data
+over IPC that is only available because it has a specific permission, but does
+not require that permission of any clients of it’s IPC interface. More
+details on the potential impacts, and frequency of this type of problem is
+provided in this research paper published at USENIX: <a
+href="http://www.cs.berkeley.edu/~afelt/felt_usenixsec2011.pdf">http://www.cs.be
+rkeley.edu/~afelt/felt_usenixsec2011.pdf</a></p>
+
+<h3>Creating Permissions</h3>
+
+<p>Generally, you should strive to create as few permissions as possible while
+satisfying your security requirements.  Creating a new permission is relatively
+uncommon for most applications, since <a
+href="{@docRoot}reference/android/Manifest.permission.html">
+system-defined permissions</a> cover many situations.  Where appropriate,
+perform access checks using existing permissions.</p>
+
+<p>If you must create a new permission, consider whether you can accomplish
+your task with a Signature permission.  Signature permissions are transparent
+to the user and only allow access by applications signed by the same developer
+as application performing the permission check.  If you create a Dangerous
+permission, then the user needs to decide whether to install the application.
+This can be confusing for other developers, as well as for users.</p>
+
+<p>If you create a Dangerous permission, there are a number of complexities
+that you need to consider.
+<ul>
+<li>The permission must have a string that concisely expresses to a user the
+security decision they will be required to make.</li>
+<li>The permission string must be localized to many different languages.</li>
+<li>Uses may choose not to install an application because a permission is
+confusing or perceived as risky.</li>
+<li>Applications may request the permission when the creator of the permission
+has not been installed.</li>
+</ul></p>
+
+<p>Each of these poses a significant non-technical challenge for an application
+developer, which is why we discourage the use of Dangerous permission.</p>
+
+<a name="Networking"></a>
+<h2>Using Networking</h2>
+
+<h3>Using IP Networking</h3>
+
+<p>Networking on Android is not significantly different from Linux
+environments.  The key consideration is making sure that appropriate protocols
+are used for sensitive data, such as <a
+href="{@docRoot}reference/javax/net/ssl/HttpsURLConnection.html">HTTPS</a> for
+web traffic.   We prefer use of HTTPS over HTTP anywhere that HTTPS is
+supported on the server, since mobile devices frequently connect on networks
+that are not secured, such as public WiFi hotspots.</p>
+
+<p>Authenticated, encrypted socket-level communication can be easily
+implemented using the <code><a
+href="{@docRoot}reference/javax/net/ssl/SSLSocket.html">SSLSocket</a></code>
+class.  Given the frequency with which Android devices connect to unsecured
+wireless networks using WiFi, the use of secure networking is strongly
+encouraged for all applications.</p>
+
+<p>We have seen some applications use <a
+href="http://en.wikipedia.org/wiki/Localhost">localhost</a> network ports for
+handling sensitive IPC.  We discourage this approach since these interfaces are
+accessible by other applications on the device.  Instead, use an Android IPC
+mechanism where authentication is possible such as a Service and Binder.  (Even
+worse than using loopback is to bind to INADDR_ANY since then your application
+may receive requests from anywhere.  We’ve seen that, too.)</p>
+
+<p>Also, one common issue that warrants repeating is to make sure that you do
+not trust data downloaded from HTTP or other insecure protocols.  This includes
+validation of input in <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code> and
+any responses to intents issued against HTTP.</p>
+
+<h3>Using Telephony Networking</h3>
+
+<p>SMS is the telephony protocol most frequently used by Android developers.
+Developers should keep in mind that this protocol was primarily designed for
+user-to-user communication and is not well-suited for some application
+purposes. Due to the limitations of SMS, we strongly recommend the use of <a
+href="http://code.google.com/android/c2dm/">C2DM</a> and IP networking for
+sending data messages to devices.</p>
+
+<p>Many developers do not realize that SMS is not encrypted or strongly
+authenticated on the network or on the device.  In particular, any SMS receiver
+should expect that a malicious user may have sent the SMS to your application
+-- do not rely on unauthenticated SMS data to perform sensitive commands.
+Also, you should be aware that SMS may be subject to spoofing and/or
+interception on the network.  On the Android-powered device itself, SMS
+messages are transmitted as Broadcast intents, so they may be read or captured
+by other applications that have the READ_SMS permission.</p>
+
+<a name="DynamicCode"></a>
+<h2>Dynamically Loading Code</h2>
+
+<p>We strongly discourage loading code from outside of the application APK.
+Doing so significantly increases the likelihood of application compromise due
+to code injection or code tampering.  It also adds complexity around version
+management and application testing.  Finally, it can make it impossible to
+verify the behavior of an application, so it may be prohibited in some
+environments.</p>
+
+<p>If your application does dynamically load code, the most important thing to
+keep in mind about dynamically loaded code is that it runs with the same
+security permissions as the application APK.  The user made a decision to
+install your application based on your identity, and they are expecting that
+you provide any code run within the application, including code that is
+dynamically loaded.</p>
+
+<p>The major security risk associated with dynamically loading code is that the
+code needs to come from a verifiable source. If the modules are included
+directly within your APK, then they cannot be modified by other applications.
+This is true whether the code is a native library or a class being loaded using
+<a href="{@docRoot}reference/dalvik/system/DexClassLoader.html">
+<code>DexClassLoader</code></a>.  We have seen many instances of applications
+attempting to load code from insecure locations, such as downloaded from the
+network over unencrypted protocols or from world writable locations such as
+external storage. These locations could allow someone on the network to modify
+the content in transit, or another application on a users device to modify the
+content, respectively.</p>
+
+
+<h3>Using WebView</h3>
+
+<p>Since WebView consumes web content that can include HTML and JavaScript,
+improper use can introduce common web security issues such as <a
+href="http://en.wikipedia.org/wiki/Cross_site_scripting">cross-site-scripting</a
+> (JavaScript injection).  Android includes a number of mechanisms to reduce
+the scope of these potential issues by limiting the capability of WebView to
+the minimum functionality required by your application.</p>
+
+<p>If your application does not directly use JavaScript within a <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code>, do
+not call
+<a href="{@docRoot}reference/android/webkit/WebSettings.html#setJavaScriptEnabled(boolean)
+<code>setJavaScriptEnabled()</code></a>. We have seen this method invoked
+in sample code that might be repurposed in production application -- so
+remove it if necessary. By default, <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code> does
+not execute JavaScript so cross-site-scripting is not possible.</p>
+
+<p>Use <code><a
+href="{@docRoot}reference/android/webkit/WebView.html#addJavascriptInterface(jav
+a.lang.Object,%20java.lang.String)">addJavaScriptInterface()</a></code> with
+particular care because it allows JavaScript to invoke operations that are
+normally reserved for Android applications.  Only expose <code><a
+href="{@docRoot}reference/android/webkit/WebView.html#addJavascriptInterface(jav
+a.lang.Object,%20java.lang.String)">addJavaScriptInterface()</a></code> to
+sources from which all input is trustworthy.  If untrusted input is allowed,
+untrusted JavaScript may be able to invoke Android methods.  In general, we
+recommend only exposing <code><a
+href="{@docRoot}reference/android/webkit/WebView.html#addJavascriptInterface(jav
+a.lang.Object,%20java.lang.String)">addJavaScriptInterface()</a></code> to
+JavaScript that is contained within your application APK.</p>
+
+<p>Do not trust information downloaded over HTTP, use HTTPS instead.  Even if
+you are connecting only to a single website that you trust or control, HTTP is
+subject to <a
+href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack">MiTM</a> attacks
+and interception of data.  Sensitive capabilities using <code><a
+href="{@docRoot}reference/android/webkit/WebView.html#addJavascriptInterface(jav
+a.lang.Object,%20java.lang.String)">addJavaScriptInterface()</a></code> should
+not ever be exposed to unverified script downloaded over HTTP. Note that even
+with the use of HTTPS,
+<code><a
+href="{@docRoot}reference/android/webkit/WebView.html#addJavascriptInterface(jav
+a.lang.Object,%20java.lang.String)">addJavaScriptInterface()</a></code>
+increases the attack surface of your application to include the server
+infrastructure and all CAs trusted by the Android-powered device.</p>
+
+<p>If your application accesses sensitive data with a <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code>, you
+may want to use the <code><a
+href="{@docRoot}reference/android/webkit/WebView.html#clearCache(boolean)">
+clearCache()</a></code> method to delete any files stored locally. Server side
+headers like no-cache can also be used to indicate that an application should
+not cache particular content.</p>
+
+<a name="Input"></a>
+<h2>Performing Input Validation</h2>
+
+<p>Insufficient input validation is one of the most common security problems
+affecting applications, regardless of what platform they run on. Android does
+have platform-level countermeasures that reduce the exposure of applications to
+input validation issues, you should use those features where possible. Also
+note that selection of type-safe languages tends to reduce the likelihood of
+input validation issues.  We strongly recommend building your applications with
+the Android SDK.</p>
+
+<p>If you are using native code, then any data read from files, received over
+the network, or received from an IPC has the potential to introduce a security
+issue.  The most common problems are <a
+href="http://en.wikipedia.org/wiki/Buffer_overflow">buffer overflows</a>, <a
+href="http://en.wikipedia.org/wiki/Double_free#Use_after_free">use after
+free</a>, and <a
+href="http://en.wikipedia.org/wiki/Off-by-one_error">off-by-one errors</a>.
+Android provides a number of technologies like ASLR and DEP that reduce the
+exploitability of these errors, but they do not solve the underlying problem.
+These can be prevented by careful handling of pointers and managing of
+buffers.</p>
+
+<p>Dynamic, string based languages such as JavaScript and SQL are also subject
+to input validation problems due to escape characters and <a
+href="http://en.wikipedia.org/wiki/Code_injection">script injection</a>.</p>
+
+<p>If you are using data within queries that are submitted to SQL Database or a
+Content Provider, SQL Injection may be an issue.  The best defense is to use
+parameterized queries, as is discussed in the ContentProviders section.
+Limiting permissions to read-only or write-only can also reduce the potential
+for harm related to SQL Injection.</p>
+
+<p>If you are using <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code>, then
+you must consider the possibility of XSS.  If your application does not
+directly use JavaScript within a <code><a
+href="{@docRoot}reference/android/webkit/WebView.html">WebView</a></code>, do
+not call setJavaScriptEnabled() and XSS is no longer possible. If you must
+enable JavaScript then the WebView section provides other security best
+practices.</p>
+
+<p>If you cannot use the security features above, we strongly recommend the use
+of well-structured data formats and verifying that the data conforms to the
+expected format. While blacklisting of characters or character-replacement can
+be an effective strategy, these techniques are error-prone in practice and
+should be avoided when possible.</p>
+
+<a name="UserData"></a>
+<h2>Handling User Data</h2>
+
+<p>In general, the best approach is to minimize use of APIs that access
+sensitive or personal user data. If you have access to data and can avoid
+storing or transmitting the information, do not store or transmit the data.
+Finally, consider if there is a way that your application logic can be
+implemented using a hash or non-reversible form of the data.  For example, your
+application might use the hash of an an email address as a primary key, to
+avoid transmitting or storing the email address.  This reduces the chances of
+inadvertently exposing data, and it also reduces the chance of attackers
+attempting to exploit your application.</p>
+
+<p>If your application accesses personal information such as passwords or
+usernames, keep in mind that some jurisdictions may require you to provide a
+privacy policy explaining your use and storage of that data.  So following the
+security best practice of minimizing access to user data may also simplify
+compliance.</p>
+
+<p>You should also consider whether your application might be inadvertently
+exposing personal information to other parties such as third-party components
+for advertising or third-party services used by your application. If you don't
+know why a component or service requires a personal information, don’t
+provide it.  In general, reducing the access to personal information by your
+application will reduce the potential for problems in this area.</p>
+
+<p>If access to sensitive data is required, evaluate whether that information
+must be transmitted to a server, or whether the operation can be performed on
+the client.  Consider running any code using sensitive data on the client to
+avoid transmitting user data.</p>
+
+<p>Also, make sure that you do not inadvertently expose user data to other
+application on the device through overly permissive IPC, world writable files,
+or network sockets. This is a special case of permission redelegation,
+discussed in the Requesting Permissions section.</p>
+
+<p>If a GUID is required, create a large, unique number and store it.  Do not
+use phone identifiers such as the phone number or IMEI which may be associated
+with personal information.  This topic is discussed in more detail in the <a
+href="http://android-developers.blogspot.com/2011/03/identifying-app-installatio
+ns.html">Android Developer Blog</a>.</p>
+
+<h3>Handling Credentials</h3>
+
+<p>In general, we recommend minimizing the frequency of asking for user
+credentials -- to make phishing attacks more conspicuous, and less likely to be
+successful.  Instead use an authorization token and refresh it.</p>
+
+<p>Where possible, username and password should not be stored on the device.
+Instead, perform initial authentication using the username and password
+supplied by the user, and then use a short-lived, service-specific
+authorization token.</p>
+
+<p>Services that will be accessible to multiple applications should be accessed
+using <code>
+<a href="{@docRoot}reference/android/accounts/AccountManager.html">
+AccountManager</a></code>. If possible, use the <code><a
+href="{@docRoot}reference/android/accounts/AccountManager.html">
+AccountManager</a></code> class to invoke a cloud-based service and do not store
+passwords on the device.</p>
+
+<p>After using <code><a
+href="{@docRoot}reference/android/accounts/AccountManager.html">
+AccountManager</a></code> to retrieve an Account, check the <code><a
+href="{@docRoot}reference/android/accounts/Account.html#CREATOR">CREATOR</a>
+</code> before passing in any credentials, so that you do not inadvertently pass
+credentials to the wrong application.</p>
+
+<p>If credentials are to be used only by applications that you create, then you
+can verify the application which accesses the <code><a
+href="{@docRoot}reference/android/accounts/AccountManager.html">
+AccountManager</a></code> using <code><a href="<code><a
+href="{@docRoot}h/reference/android/content/pm/PackageManager.html#checkSignatur
+es(java.lang.String,%20java.lang.String)">checkSignature()</a></code>.
+Alternatively, if only one application will use the credential, you might use a
+<code><a
+href={@docRoot}reference/java/security/KeyStore.html">KeyStore</a></code> for
+storage.</p>
+
+<a name="Crypto"></a>
+<h2>Using Cryptography</h2>
+
+<p>In addition to providing data isolation, supporting full-filesystem
+encryption, and providing secure communications channels Android provides a
+wide array of algorithms for protecting data using cryptography.</p>
+
+<p>In general, try to use the highest level of pre-existing framework
+implementation that can  support your use case.  If you need to securely
+retrieve a file from a known location, a simple HTTPS URI may be adequate and
+require no knowledge of cryptography on your part.  If you need a secure
+tunnel, consider using
+<a href="{@docRoot}reference/javax/net/ssl/HttpsURLConnection.html">
+<code>HttpsURLConnection</code></a> or <code><a
+href="{@docRoot}reference/javax/net/ssl/SSLSocket.html">SSLSocket</a></code>,
+rather than writing your own protocol.</p>
+
+<p>If you do find yourself needing to implement your own protocol, we strongly
+recommend that you not implement your own cryptographic algorithms. Use
+existing cryptographic algorithms such as those in the implementation of AES or
+RSA provided in the <code><a
+href="{@docRoot}reference/javax/crypto/Cipher.html">Cipher</a></code> class.</p>
+
+<p>Use a secure random number generator (
+<a href="http://developer.android.com/reference/java/security/SecureRandom.html">
+<code>SecureRandom</code></a>) to initialize any cryptographic keys (<a
+href="http://developer.android.com/reference/javax/crypto/KeyGenerator.html">
+<code>KeyGenerator</code></a>). Use of a key that is not generated with a secure random
+number generator significantly weakens the strength of the algorithm, and may
+allow offline attacks.</p>
+
+<p>If you need to store a key for repeated use, use a mechanism like <code><a
+href={@docRoot}reference/java/security/KeyStore.html">KeyStore</a></code> that
+provides a mechanism for long term storage and retrieval of cryptographic
+keys.</p>
+
+<h2>Conclusion</h2>
+
+<p>Android provides developers with the ability to design applications with a
+broad range of security requirements.  These best practices will help you make
+sure that your application takes advantage of the security benefits provided by
+the platform.</p>
+
+<p>You can receive more information on these topics and discuss security best
+practices with other developers in the <a
+href="http://groups.google.com/group/android-security-discuss">Android Security
+Discuss</a> Google Group</p>
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index eab7648..250f267 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -48,15 +48,21 @@
 };
 
 /**
- *Set CIF as default maximum import and export resolution of video editor.
- *The maximum import and export resolutions are platform specific,
- *which should be defined in media_profiles.xml.
+ * Set CIF as default maximum import and export resolution of video editor.
+ * The maximum import and export resolutions are platform specific,
+ * which should be defined in media_profiles.xml.
+ * Set default maximum prefetch YUV frames to 6, which means video editor can
+ * queue up to 6 YUV frames in the video encoder source.
+ * This value is used to limit the amount of memory used by video editor
+ * engine when the encoder consumes YUV frames at a lower speed
+ * than video editor engine produces.
  */
 enum videoeditor_capability {
     VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH = 352,
     VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT = 288,
     VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH = 352,
     VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT = 288,
+    VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES = 6
 };
 
 enum video_decoder {
@@ -138,6 +144,8 @@
      * videoeditor.input.height.max - max input video frame height
      * videoeditor.output.width.max - max output video frame width
      * videoeditor.output.height.max - max output video frame height
+     * maxPrefetchYUVFrames - max prefetch YUV frames in video editor engine. This value is used
+     * to limit the memory consumption.
      */
     int getVideoEditorCapParamByName(const char *name) const;
 
@@ -357,11 +365,12 @@
     };
     struct VideoEditorCap {
         VideoEditorCap(int inFrameWidth, int inFrameHeight,
-            int outFrameWidth, int outFrameHeight)
+            int outFrameWidth, int outFrameHeight, int frames)
             : mMaxInputFrameWidth(inFrameWidth),
               mMaxInputFrameHeight(inFrameHeight),
               mMaxOutputFrameWidth(outFrameWidth),
-              mMaxOutputFrameHeight(outFrameHeight) {}
+              mMaxOutputFrameHeight(outFrameHeight),
+              mMaxPrefetchYUVFrames(frames) {}
 
         ~VideoEditorCap() {}
 
@@ -369,6 +378,7 @@
         int mMaxInputFrameHeight;
         int mMaxOutputFrameWidth;
         int mMaxOutputFrameHeight;
+        int mMaxPrefetchYUVFrames;
     };
 
     int getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const;
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 438a1a0..c2cbe1d 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -826,6 +826,9 @@
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
 
+    inline void setKeyCharacterMapFile(const String8& value) { mKeyCharacterMapFile = value; }
+    inline const String8& getKeyCharacterMapFile() const { return mKeyCharacterMapFile; }
+
     inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
@@ -835,6 +838,7 @@
     String8 mName;
     uint32_t mSources;
     int32_t mKeyboardType;
+    String8 mKeyCharacterMapFile;
 
     Vector<MotionRange> mMotionRanges;
 };
diff --git a/include/ui/KeyCharacterMap.h b/include/ui/KeyCharacterMap.h
index 10a3810..be14432 100644
--- a/include/ui/KeyCharacterMap.h
+++ b/include/ui/KeyCharacterMap.h
@@ -53,7 +53,6 @@
     ~KeyCharacterMap();
 
     static status_t load(const String8& filename, KeyCharacterMap** outMap);
-    static status_t loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap);
 
     /* Gets the keyboard type. */
     int32_t getKeyboardType() const;
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
index 609f319..274f526 100644
--- a/include/ui/Keyboard.h
+++ b/include/ui/Keyboard.h
@@ -81,24 +81,6 @@
         const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
 
 /**
- * Sets keyboard system properties.
- */
-extern void setKeyboardProperties(int32_t deviceId, const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyLayoutFile, const String8& keyCharacterMapFile);
-
-/**
- * Clears keyboard system properties.
- */
-extern void clearKeyboardProperties(int32_t deviceId);
-
-/**
- * Gets the key character map filename for a device using inspecting system properties
- * and then falling back on a default key character map if necessary.
- * Returns a NAME_NOT_FOUND if none found.
- */
-extern status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile);
-
-/**
  * Gets a key code by its short form label, eg. "HOME".
  * Returns 0 if unknown.
  */
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index ed319f5..9767568 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -32,6 +32,10 @@
 
 LOCAL_MODULE:= libgui
 
+ifeq ($(TARGET_BOARD_PLATFORM), tegra)
+	LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 6f84206..374f3c5 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -36,8 +36,12 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 
-
-#define ALLOW_DEQUEUE_CURRENT_BUFFER    false
+#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 SurfaceTexture name in log messages
 #define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -323,7 +327,7 @@
             LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
                     "dequeueBuffer: buffer %d is both FREE and current!", i);
 
-            if (ALLOW_DEQUEUE_CURRENT_BUFFER) {
+            if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
                 if (state == BufferSlot::FREE || i == mCurrentTexture) {
                     foundSync = i;
                     if (i != mCurrentTexture) {
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index 2decfe9..77f18de 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -124,17 +124,6 @@
     return status;
 }
 
-status_t KeyCharacterMap::loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap) {
-    *outMap = NULL;
-
-    String8 filename;
-    status_t result = getKeyCharacterMapFile(deviceId, filename);
-    if (!result) {
-        result = load(filename, outMap);
-    }
-    return result;
-}
-
 int32_t KeyCharacterMap::getKeyboardType() const {
     return mType;
 }
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index 600a951..10bb39c 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -173,50 +173,6 @@
     return strstr(deviceIdentifier.name.string(), "-keypad");
 }
 
-void setKeyboardProperties(int32_t deviceId,
-        const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyLayoutFile, const String8& keyCharacterMapFile) {
-    char propName[PROPERTY_KEY_MAX];
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
-    property_set(propName, deviceIdentifier.name.string());
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
-    property_set(propName, keyLayoutFile.string());
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-    property_set(propName, keyCharacterMapFile.string());
-}
-
-void clearKeyboardProperties(int32_t deviceId) {
-    char propName[PROPERTY_KEY_MAX];
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
-    property_set(propName, "");
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
-    property_set(propName, "");
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-    property_set(propName, "");
-}
-
-status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) {
-    if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) {
-        char propName[PROPERTY_KEY_MAX];
-        char fn[PROPERTY_VALUE_MAX];
-        snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-        if (property_get(propName, fn, "") > 0) {
-            outKeyCharacterMapFile.setTo(fn);
-            return OK;
-        }
-    }
-
-    // Default to Virtual since the keyboard does not appear to be installed.
-    outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"),
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
-    if (!outKeyCharacterMapFile.isEmpty()) {
-        return OK;
-    }
-
-    LOGE("Can't find any key character map files including the Virtual key map!");
-    return NAME_NOT_FOUND;
-}
-
 static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
     while (list->literal) {
         if (strcmp(literal, list->literal) == 0) {
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index e3b5155..13e1a30 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2875,21 +2875,21 @@
             mCallingUid = uid;
         }
 
-        private void unlinkToDeath() {
-            if (mSourceRef != null && mHandler != null) {
-                mSourceRef.unlinkToDeath(mHandler, 0);
+        public void unlinkToDeath() {
+            try {
+                if (mSourceRef != null && mHandler != null) {
+                    mSourceRef.unlinkToDeath(mHandler, 0);
+                    mHandler = null;
+                }
+            } catch (java.util.NoSuchElementException e) {
+                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
             }
         }
 
         @Override
         protected void finalize() throws Throwable {
-            try {
-                unlinkToDeath();
-            } catch (java.util.NoSuchElementException e) {
-                Log.w(TAG, e + " thrown by unlinkToDeath() during finalize, ignoring");
-            } finally {
-                super.finalize();
-            }
+            unlinkToDeath(); // unlink exception handled inside method
+            super.finalize();
         }
     }
 
@@ -2921,11 +2921,12 @@
      *   focus, notify the next item in the stack it gained focus.
      */
     private void removeFocusStackEntry(String clientToRemove, boolean signal) {
-        // is the current top of the focus stack abandoning focus? (because of death or request)
+        // is the current top of the focus stack abandoning focus? (because of request, not death)
         if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
         {
             //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
-            mFocusStack.pop();
+            FocusStackEntry fse = mFocusStack.pop();
+            fse.unlinkToDeath();
             if (signal) {
                 // notify the new top of the stack it gained focus
                 notifyTopOfAudioFocusStack();
@@ -2944,6 +2945,7 @@
                     Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
                             + fse.mClientId);
                     stackIterator.remove();
+                    fse.unlinkToDeath();
                 }
             }
         }
@@ -2952,7 +2954,7 @@
     /**
      * Helper function:
      * Called synchronized on mAudioFocusLock
-     * Remove focus listeners from the focus stack for a particular client.
+     * Remove focus listeners from the focus stack for a particular client when it has died.
      */
     private void removeFocusStackEntryForClient(IBinder cb) {
         // is the owner of the audio focus part of the client to remove?
@@ -2965,6 +2967,7 @@
                 Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
                         + fse.mClientId);
                 stackIterator.remove();
+                // the client just died, no need to unlink to its death
             }
         }
         if (isTopOfStackForClientToRemove) {
@@ -3056,7 +3059,8 @@
                 }
                 // the reason for the audio focus request has changed: remove the current top of
                 // stack and respond as if we had a new focus owner
-                mFocusStack.pop();
+                FocusStackEntry fse = mFocusStack.pop();
+                fse.unlinkToDeath();
             }
 
             // notify current top of stack it is losing focus
@@ -3244,6 +3248,7 @@
             if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
                 try {
                     mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+                    mRcClientDeathHandler = null;
                 } catch (java.util.NoSuchElementException e) {
                     // not much we can do here
                     Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
@@ -3251,6 +3256,12 @@
                 }
             }
         }
+
+        @Override
+        protected void finalize() throws Throwable {
+            unlinkToRcClientDeath();// unlink exception handled inside method
+            super.finalize();
+        }
     }
 
     /**
@@ -3297,6 +3308,7 @@
                     if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
                         // a stack entry is from the package being removed, remove it from the stack
                         stackIterator.remove();
+                        rcse.unlinkToRcClientDeath();
                     }
                 }
                 if (mRCStack.empty()) {
@@ -3377,6 +3389,7 @@
             RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
             if(rcse.mMediaIntent.equals(pi)) {
                 stackIterator.remove();
+                rcse.unlinkToRcClientDeath();
                 break;
             }
         }
@@ -3638,7 +3651,7 @@
                         rcse.mCallingPackageName = callingPackageName;
                         rcse.mCallingUid = Binder.getCallingUid();
                         if (rcClient == null) {
-                            rcse.mRcClientDeathHandler = null;
+                            // here rcse.mRcClientDeathHandler is null;
                             break;
                         }
 
@@ -3694,7 +3707,6 @@
                         rcse.unlinkToRcClientDeath();
                         // reset the client-related fields
                         rcse.mRcClient = null;
-                        rcse.mRcClientDeathHandler = null;
                         rcse.mCallingPackageName = null;
                     }
                 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index eb32563..8d71dcf 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1149,14 +1149,20 @@
     /**
      * Releases resources associated with this MediaPlayer object.
      * It is considered good practice to call this method when you're
-     * done using the MediaPlayer. For instance, whenever the Activity
-     * of an application is paused, this method should be invoked to
-     * release the MediaPlayer object. In addition to unnecessary resources
-     * (such as memory and instances of codecs) being hold, failure to
-     * call this method immediately if a MediaPlayer object is no longer
-     * needed may also lead to continuous battery consumption for mobile
-     * devices, and playback failure if no multiple instances of the
-     * same codec is supported on a device.
+     * done using the MediaPlayer. In particular, whenever an Activity
+     * of an application is paused (its onPause() method is called),
+     * or stopped (its onStop() method is called), this method should be
+     * invoked to release the MediaPlayer object, unless the application
+     * has a special need to keep the object around. In addition to
+     * unnecessary resources (such as memory and instances of codecs)
+     * being held, failure to call this method immediately if a
+     * MediaPlayer object is no longer needed may also lead to
+     * continuous battery consumption for mobile devices, and playback
+     * failure for other applications if no multiple instances of the
+     * same codec are supported on a device. Even if multiple instances
+     * of the same codec are supported, some performance degradation
+     * may be expected when unnecessary multiple instances are used
+     * at the same time.
      */
     public void release() {
         stayAwake(false);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index ceeacbb5..08e6032 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -926,7 +926,20 @@
     /**
      * Releases resources associated with this MediaRecorder object.
      * It is good practice to call this method when you're done
-     * using the MediaRecorder.
+     * using the MediaRecorder. In particular, whenever an Activity
+     * of an application is paused (its onPause() method is called),
+     * or stopped (its onStop() method is called), this method should be
+     * invoked to release the MediaRecorder object, unless the application
+     * has a special need to keep the object around. In addition to
+     * unnecessary resources (such as memory and instances of codecs)
+     * being held, failure to call this method immediately if a
+     * MediaRecorder object is no longer needed may also lead to
+     * continuous battery consumption for mobile devices, and recording
+     * failure for other applications if no multiple instances of the
+     * same codec are supported on a device. Even if multiple instances
+     * of the same codec are supported, some performance degradation
+     * may be expected when unnecessary multiple instances are used
+     * at the same time.
      */
     public native void release();
 
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index ad55ff8..6096b72 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -404,11 +404,12 @@
     CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
           !strcmp("maxInputFrameHeight", atts[2])  &&
           !strcmp("maxOutputFrameWidth", atts[4]) &&
-          !strcmp("maxOutputFrameHeight", atts[6]));
+          !strcmp("maxOutputFrameHeight", atts[6]) &&
+          !strcmp("maxPrefetchYUVFrames", atts[8]));
 
     MediaProfiles::VideoEditorCap *pVideoEditorCap =
         new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
-                atoi(atts[5]), atoi(atts[7]));
+                atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
 
     logVideoEditorCap(*pVideoEditorCap);
     profiles->mVideoEditorCap = pVideoEditorCap;
@@ -850,7 +851,8 @@
                 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
                 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
                 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
-                VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT);
+                VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
+                VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
 }
 /*static*/ void
 MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
@@ -1019,6 +1021,8 @@
         return mVideoEditorCap->mMaxOutputFrameWidth;
     if (!strcmp("videoeditor.output.height.max", name))
         return mVideoEditorCap->mMaxOutputFrameHeight;
+    if (!strcmp("maxPrefetchYUVFrames", name))
+        return mVideoEditorCap->mMaxPrefetchYUVFrames;
 
     LOGE("The given video editor param name %s is not found", name);
     return -1;
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index 62213de..9c87c22 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -16,6 +16,8 @@
 
 package com.android.nfc_extras;
 
+import java.util.HashMap;
+
 import android.content.Context;
 import android.nfc.INfcAdapterExtras;
 import android.nfc.NfcAdapter;
@@ -57,20 +59,22 @@
     // protected by NfcAdapterExtras.class, and final after first construction,
     // except for attemptDeadServiceRecovery() when NFC crashes - we accept a
     // best effort recovery
-    private static NfcAdapter sAdapter;
     private static INfcAdapterExtras sService;
     private static final CardEmulationRoute ROUTE_OFF =
             new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
 
+    // contents protected by NfcAdapterExtras.class
+    private static final HashMap<NfcAdapter, NfcAdapterExtras> sNfcExtras = new HashMap();
+
     private final NfcExecutionEnvironment mEmbeddedEe;
     private final CardEmulationRoute mRouteOnWhenScreenOn;
 
-    final Context mContext;
+    private final NfcAdapter mAdapter;
     final String mPackageName;
 
     /** get service handles */
-    private static void initService() {
-        final INfcAdapterExtras service = sAdapter.getNfcAdapterExtrasInterface();
+    private static void initService(NfcAdapter adapter) {
+        final INfcAdapterExtras service = adapter.getNfcAdapterExtrasInterface();
         if (service != null) {
             // Leave stale rather than receive a null value.
             sService = service;
@@ -95,23 +99,20 @@
 
         synchronized (NfcAdapterExtras.class) {
             if (sService == null) {
-                try {
-                    sAdapter = adapter;
-                    initService();
-                } finally {
-                    if (sService == null) {
-                        sAdapter = null;
-                    }
-                }
+                initService(adapter);
             }
+            NfcAdapterExtras extras = sNfcExtras.get(adapter);
+            if (extras == null) {
+                extras = new NfcAdapterExtras(adapter);
+                sNfcExtras.put(adapter,  extras);
+            }
+            return extras;
         }
-
-        return new NfcAdapterExtras(context);
     }
 
-    private NfcAdapterExtras(Context context) {
-        mContext = context.getApplicationContext();
-        mPackageName = context.getPackageName();
+    private NfcAdapterExtras(NfcAdapter adapter) {
+        mAdapter = adapter;
+        mPackageName = adapter.getContext().getPackageName();
         mEmbeddedEe = new NfcExecutionEnvironment(this);
         mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
                 mEmbeddedEe);
@@ -160,8 +161,8 @@
      */
     void attemptDeadServiceRecovery(Exception e) {
         Log.e(TAG, "NFC Adapter Extras dead - attempting to recover");
-        sAdapter.attemptDeadServiceRecovery(e);
-        initService();
+        mAdapter.attemptDeadServiceRecovery(e);
+        initService(mAdapter);
     }
 
     INfcAdapterExtras getService() {
diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk
new file mode 100644
index 0000000..3eca76d
--- /dev/null
+++ b/nfc-extras/tests/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := \
+    android.test.runner \
+    com.android.nfc_extras
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := NfcExtrasTests
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/nfc-extras/tests/AndroidManifest.xml b/nfc-extras/tests/AndroidManifest.xml
new file mode 100644
index 0000000..0cc6653
--- /dev/null
+++ b/nfc-extras/tests/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.nfc_extras.tests">
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="com.android.nfc_extras" />
+    </application>
+
+    <uses-permission android:name="android.permission.NFC"/>
+
+    <!--
+    Run all tests with
+    adb shell am instrument -w com.android.nfc_extras.tests/android.test.InstrumentationTestRunner
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.nfc_extras.tests"
+                     android:label="Tests for NFC Extras library"/>
+
+</manifest>
diff --git a/nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java b/nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java
new file mode 100644
index 0000000..e1025aa
--- /dev/null
+++ b/nfc-extras/tests/src/com/android/nfc_extras/BasicNfcEeTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.nfc_extras;
+
+import android.content.Context;
+import android.nfc.NfcAdapter;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import com.android.nfc_extras.NfcAdapterExtras;
+import com.android.nfc_extras.NfcAdapterExtras.CardEmulationRoute;
+import com.android.nfc_extras.NfcExecutionEnvironment;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+public class BasicNfcEeTest extends InstrumentationTestCase {
+    private Context mContext;
+    private NfcAdapterExtras mAdapterExtras;
+    private NfcExecutionEnvironment mEe;
+
+    public static final byte[] SELECT_CARD_MANAGER_COMMAND = new byte[] {
+        (byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00,  // command
+        (byte)0x08,  // data length
+        (byte)0xA0, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x00,
+        (byte)0x00,  // card manager AID
+        (byte)0x00  // trailer
+    };
+
+    public static final byte[] SELECT_CARD_MANAGER_RESPONSE = new byte[] {
+        (byte)0x90, (byte)0x00,
+    };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+        mAdapterExtras = NfcAdapterExtras.get(NfcAdapter.getDefaultAdapter(mContext));
+        mEe = mAdapterExtras.getEmbeddedExecutionEnvironment();
+    }
+
+    public void testSendCardManagerApdu() throws IOException {
+        mEe.open();
+
+        try {
+            byte[] out = mEe.transceive(SELECT_CARD_MANAGER_COMMAND);
+            assertTrue(out.length >= SELECT_CARD_MANAGER_RESPONSE.length);
+            byte[] trailing = Arrays.copyOfRange(out,
+                    out.length - SELECT_CARD_MANAGER_RESPONSE.length,
+                    out.length);
+            assertByteArrayEquals(SELECT_CARD_MANAGER_RESPONSE, trailing);
+
+        } finally {
+            mEe.close();
+        }
+
+    }
+
+    public void testSendCardManagerApduMultiple() throws IOException {
+        for (int i=0; i<10; i++) {
+            try {
+            mEe.open();
+
+            try {
+                byte[] out = mEe.transceive(SELECT_CARD_MANAGER_COMMAND);
+                byte[] trailing = Arrays.copyOfRange(out,
+                        out.length - SELECT_CARD_MANAGER_RESPONSE.length,
+                        out.length);
+
+            } finally {
+                try {Thread.sleep(1000);} catch (InterruptedException e) {}
+                mEe.close();
+            }
+            } catch (IOException e) {}
+        }
+
+        testSendCardManagerApdu();
+
+    }
+
+    public void testEnableEe() {
+        mAdapterExtras.setCardEmulationRoute(
+                new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, mEe));
+        CardEmulationRoute newRoute = mAdapterExtras.getCardEmulationRoute();
+        assertEquals(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, newRoute.route);
+        assertEquals(mEe, newRoute.nfcEe);
+    }
+
+    public void testDisableEe() {
+        mAdapterExtras.setCardEmulationRoute(
+                new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null));
+        CardEmulationRoute newRoute = mAdapterExtras.getCardEmulationRoute();
+        assertEquals(CardEmulationRoute.ROUTE_OFF, newRoute.route);
+        assertNull(newRoute.nfcEe);
+    }
+
+    private static void assertByteArrayEquals(byte[] b1, byte[] b2) {
+        assertEquals(b1.length, b2.length);
+        for (int i = 0; i < b1.length; i++) {
+            assertEquals(b1[i], b2[i]);
+        }
+    }
+}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index c926670..ca11863 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -229,14 +229,6 @@
 #define EGL_NATIVE_BUFFER_ANDROID               0x3140  /* eglCreateImageKHR target */
 #endif
 
-#ifndef EGL_ANDROID_swap_rectangle
-#define EGL_ANDROID_swap_rectangle 1
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
-#endif
-
 #ifndef EGL_ANDROID_recordable
 #define EGL_ANDROID_recordable 1
 #define EGL_RECORDABLE_ANDROID                  0x3142  /* EGLConfig attribute */
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 03db8d7..6d4098c 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -49,6 +49,11 @@
 #undef NELEM
 #define NELEM(x) (sizeof(x)/sizeof(*(x)))
 
+
+EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+        EGLint left, EGLint top, EGLint width, EGLint height);
+
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
diff --git a/opengl/libagl2/Android.mk b/opengl/libagl2/Android.mk
deleted file mode 100644
index b442a2d..0000000
--- a/opengl/libagl2/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Build the software OpenGL ES library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	src/api.cpp \
-	src/egl.cpp \
-    src/get.cpp \
-	src/shader.cpp \
-	src/state.cpp \
-	src/texture.cpp \
-	src/vertex.cpp
-
-LOCAL_C_INCLUDES :=	\
-    $(LOCAL_PATH) \
-    external/mesa3d/include \
-    external/mesa3d/src \
-    external/stlport/stlport \
-    bionic
-    
-#LOCAL_CFLAGS += -DLOG_TAG=\"libagl2\"
-#LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-#LOCAL_CFLAGS += -fvisibility=hidden
-#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
-LOCAL_CFLAGS += -O3
-LOCAL_STATIC_LIBRARIES := libMesa
-LOCAL_SHARED_LIBRARIES := libstlport libcutils libhardware libutils libbcc libdl
-LOCAL_LDLIBS := -lpthread
-
-ifeq ($(TARGET_ARCH),arm)
-	LOCAL_CFLAGS += -fstrict-aliasing
-endif
-
-ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
-    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-
-# we need to access the private Bionic header <bionic_tls.h>
-# on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
-# behavior from the bionic Android.mk file
-ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
-    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
-#replace libagl for now
-LOCAL_MODULE:= libGLES_android
-LOCAL_MODULE_TAGS := eng
-
-## Disable this makefile for now
-## include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl2/README b/opengl/libagl2/README
deleted file mode 100644
index 34746d3..0000000
--- a/opengl/libagl2/README
+++ /dev/null
@@ -1,26 +0,0 @@
-libAgl2 provides software GL ES 2.0 implementation using Pixelflinger2 in external/mesa3d
-
-To build, enable Android.mk, which builds libGLES_android.so, then replace the one built from libAgl in system/lib/egl.
-ES 1.0 functions are not implemented and will cause exit, so do not setprop debug.egl.hw 0 until launcher is loaded.
-
-All functions have little to none error checking.
-Not thread safe, Pixelflinger2 uses some static data.
-
-Most shader functions are implemented, however, most Get* functions for shaders/programs/uniforms/attribs are not.
-No name system for shaders/programs, just using the pointers as names.
-
-Basic glTexImage2D, glTexSubImage2D, glCopyImage2D and glCopySubImage2D are implemented, with a range of 8/16/24/32bpp formats.
-Cube map support is minimal. No mipmapping.
-TexParameter is mostly implemented, supports texcoord wrap modes, and only linear for both min and mag, or nearest for both min and mag filtering.
-Texture names are implemented, but bad.
-
-Frame buffer and render buffers are not implemented.
-
-Depth and stencil are implemented, but not tested.
-Blending seems to work.
-Colorbuffer supports RGBA_8888 and RGB_565.
-
-Vertex buffer objects are implemented.
-Some GL_TRIANGLES and GL_TRIANGLE_STRIPS modes for glDrawArrays and glDrawElements are implemented, but vertex order is probably wrong so culling is disabled.
-
-Basic apps should work, and some libhwui should work, except for frame buffer operations, which will cause exit.
diff --git a/opengl/libagl2/libagl2.project b/opengl/libagl2/libagl2.project
deleted file mode 100644
index f234421..0000000
--- a/opengl/libagl2/libagl2.project
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<CodeLite_Project Name="libagl2" InternalType="Console">
-  <Plugins>
-    <Plugin Name="qmake">
-      <![CDATA[00010001N0005Debug000000000000]]>
-    </Plugin>
-  </Plugins>
-  <Description/>
-  <Dependencies/>
-  <Dependencies Name="Release"/>
-  <VirtualDirectory Name="src">
-    <File Name="src/egl.cpp"/>
-    <File Name="src/api.cpp"/>
-    <File Name="src/gles2context.h"/>
-    <File Name="src/shader.cpp"/>
-    <File Name="src/vertex.cpp"/>
-    <File Name="src/state.cpp"/>
-    <File Name="src/texture.cpp"/>
-    <File Name="src/get.cpp"/>
-  </VirtualDirectory>
-  <VirtualDirectory Name="include"/>
-  <Settings Type="Executable">
-    <Configuration Name="Debug" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
-      <Compiler Options="-g;-m32" Required="yes" PreCompiledHeader="">
-        <IncludePath Value="/usr/include/c++/4.4"/>
-        <IncludePath Value="/usr/include/c++/4.4/ext"/>
-        <IncludePath Value="."/>
-        <IncludePath Value="include"/>
-        <IncludePath Value="../../../../external/mesa3d/include"/>
-        <IncludePath Value="../../../../external/mesa3d/src"/>
-        <IncludePath Value="../../../../hardware/libhardware/include"/>
-        <IncludePath Value="../../../../system/core/include"/>
-        <IncludePath Value="../include"/>
-        <IncludePath Value="../../include"/>
-        <IncludePath Value="../../../../development/ndk/platforms/android-9/include"/>
-        <IncludePath Value="../../../../bionic/libc/include/"/>
-        <IncludePath Value="/../../../../development/ndk/platforms/android-5/arch-x86/include"/>
-        <IncludePath Value="../../../../bionic/libc/arch-x86/include"/>
-        <IncludePath Value="../../../../bionic/libc/kernel/arch-x86"/>
-        <IncludePath Value="/../../../../external/kernel-headers/original"/>
-        <IncludePath Value="../../../../prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-x86/usr/include"/>
-      </Compiler>
-      <Linker Options="-m32;-lstdc++" Required="yes"/>
-      <ResourceCompiler Options="" Required="no"/>
-      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
-      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
-        <PostConnectCommands/>
-        <StartupCommands/>
-      </Debugger>
-      <PreBuild/>
-      <PostBuild/>
-      <CustomBuild Enabled="no">
-        <RebuildCommand/>
-        <CleanCommand/>
-        <BuildCommand/>
-        <PreprocessFileCommand/>
-        <SingleFileCommand/>
-        <MakefileGenerationCommand/>
-        <ThirdPartyToolName>None</ThirdPartyToolName>
-        <WorkingDirectory/>
-      </CustomBuild>
-      <AdditionalRules>
-        <CustomPostBuild/>
-        <CustomPreBuild/>
-      </AdditionalRules>
-    </Configuration>
-    <Configuration Name="Release" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
-      <Compiler Options="" Required="yes" PreCompiledHeader="">
-        <IncludePath Value="."/>
-      </Compiler>
-      <Linker Options="-O2" Required="yes"/>
-      <ResourceCompiler Options="" Required="no"/>
-      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
-      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
-        <PostConnectCommands/>
-        <StartupCommands/>
-      </Debugger>
-      <PreBuild/>
-      <PostBuild/>
-      <CustomBuild Enabled="no">
-        <RebuildCommand/>
-        <CleanCommand/>
-        <BuildCommand/>
-        <PreprocessFileCommand/>
-        <SingleFileCommand/>
-        <MakefileGenerationCommand/>
-        <ThirdPartyToolName>None</ThirdPartyToolName>
-        <WorkingDirectory/>
-      </CustomBuild>
-      <AdditionalRules>
-        <CustomPostBuild/>
-        <CustomPreBuild/>
-      </AdditionalRules>
-    </Configuration>
-    <GlobalSettings>
-      <Compiler Options="">
-        <IncludePath Value="."/>
-      </Compiler>
-      <Linker Options="">
-        <LibraryPath Value="."/>
-      </Linker>
-      <ResourceCompiler Options=""/>
-    </GlobalSettings>
-  </Settings>
-  <Dependencies Name="Debug">
-    <Project Name="libMesa"/>
-  </Dependencies>
-</CodeLite_Project>
diff --git a/opengl/libagl2/src/api.cpp b/opengl/libagl2/src/api.cpp
deleted file mode 100644
index bb8d62b..0000000
--- a/opengl/libagl2/src/api.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-#include "gles2context.h"
-
-#define API_ENTRY
-#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
-#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
-
-
-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);
-}
-GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target)
-{
-   CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
-}
-void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-{
-   CALL_GL_API(glColorMask, red, green, blue, alpha);
-}
-void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers)
-{
-   CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers)
-{
-   CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
-}
-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(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 glGenerateMipmap(GLenum target)
-{
-   //CALL_GL_API(glGenerateMipmap, target);
-   LOGD("agl2: glGenerateMipmap not implemented");
-}
-void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers)
-{
-   CALL_GL_API(glGenFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers)
-{
-   CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* 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* 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);
-}
-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 glGetError(void)
-{
-   puts("agl2: glGetError");
-   return GL_NO_ERROR;
-   //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(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
-}
-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* source)
-{
-   CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
-}
-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);
-}
-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);
-}
-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);
-}
-void API_ENTRY(glLineWidth)(GLfloat width)
-{
-   CALL_GL_API(glLineWidth, width);
-}
-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(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(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(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v)
-{
-   CALL_GL_API(glUniform1fv, location, count, v);
-}
-void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v)
-{
-   CALL_GL_API(glUniform1iv, location, count, v);
-}
-void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* 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* 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* 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* v)
-{
-   CALL_GL_API(glUniform3iv, location, count, v);
-}
-void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* 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* v)
-{
-   CALL_GL_API(glUniform4iv, location, count, v);
-}
-void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
-}
-void API_ENTRY(glValidateProgram)(GLuint program)
-{
-   CALL_GL_API(glValidateProgram, program);
-}
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
deleted file mode 100644
index 0d02ce6..0000000
--- a/opengl/libagl2/src/egl.cpp
+++ /dev/null
@@ -1,2172 +0,0 @@
-/*
- **
- ** Copyright 2007 The Android Open Source Project
- **
- ** Licensed under the Apache License Version 2.0(the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing software
- ** distributed under the License is distributed on an "AS IS" BASIS
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/atomic.h>
-
-
-#include <private/ui/android_natives_priv.h>
-
-#include "gles2context.h"
-
-// ----------------------------------------------------------------------------
-namespace android
-{
-// ----------------------------------------------------------------------------
-
-const unsigned int NUM_DISPLAYS = 1;
-
-static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_key_t gEGLErrorKey = -1;
-#ifndef HAVE_ANDROID_OS
-namespace gl {
-pthread_key_t gGLKey = -1;
-}; // namespace gl
-#endif
-
-template<typename T>
-static T setError(GLint error, T returnValue)
-{
-    if (ggl_unlikely(gEGLErrorKey == -1)) {
-        pthread_mutex_lock(&gErrorKeyMutex);
-        if (gEGLErrorKey == -1)
-            pthread_key_create(&gEGLErrorKey, NULL);
-        pthread_mutex_unlock(&gErrorKeyMutex);
-    }
-    pthread_setspecific(gEGLErrorKey, (void*)error);
-    return returnValue;
-}
-
-static GLint getError()
-{
-    if (ggl_unlikely(gEGLErrorKey == -1))
-        return EGL_SUCCESS;
-    GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
-    if (error == 0) {
-        // The TLS key has been created by another thread, but the value for
-        // this thread has not been initialized.
-        return EGL_SUCCESS;
-    }
-    pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
-    return error;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_display_t {
-    egl_display_t() : type(0), initialized(0) { }
-
-    static egl_display_t& get_display(EGLDisplay dpy);
-
-    static EGLBoolean is_valid(EGLDisplay dpy) {
-        return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
-    }
-
-    NativeDisplayType   type;
-    volatile int32_t    initialized;
-};
-
-static egl_display_t gDisplays[NUM_DISPLAYS];
-
-egl_display_t& egl_display_t::get_display(EGLDisplay dpy)
-{
-    return gDisplays[uintptr_t(dpy)-1U];
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_surface_t {
-    enum {
-        PAGE_FLIP = 0x00000001,
-        MAGIC     = 0x31415265
-    };
-
-    uint32_t            magic;
-    EGLDisplay          dpy;
-    EGLConfig           config;
-    EGLContext          ctx;
-
-    egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
-    virtual     ~egl_surface_t();
-    bool    isValid() const;
-    virtual     bool    initCheck() const = 0;
-
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl) = 0;
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl) = 0;
-    virtual     EGLBoolean  connect() {
-        return EGL_TRUE;
-    }
-    virtual     void        disconnect() {}
-    virtual     EGLint      getWidth() const = 0;
-    virtual     EGLint      getHeight() const = 0;
-
-    virtual     EGLint      getHorizontalResolution() const;
-    virtual     EGLint      getVerticalResolution() const;
-    virtual     EGLint      getRefreshRate() const;
-    virtual     EGLint      getSwapBehavior() const;
-    virtual     EGLBoolean  swapBuffers();
-    virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-protected:
-    GGLSurface              depth;
-};
-
-egl_surface_t::egl_surface_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat)
-: magic(MAGIC), dpy(dpy), config(config), ctx(0)
-{
-    depth.version = sizeof(GGLSurface);
-    depth.data = 0;
-    depth.format = (GGLPixelFormat)depthFormat;
-}
-egl_surface_t::~egl_surface_t()
-{
-    magic = 0;
-    free(depth.data);
-}
-bool egl_surface_t::isValid() const
-{
-    LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
-    return magic == MAGIC;
-}
-
-EGLBoolean egl_surface_t::swapBuffers()
-{
-    return EGL_FALSE;
-}
-EGLint egl_surface_t::getHorizontalResolution() const
-{
-    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getVerticalResolution() const
-{
-    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getRefreshRate() const
-{
-    return (60 * EGL_DISPLAY_SCALING);
-}
-EGLint egl_surface_t::getSwapBehavior() const
-{
-    return EGL_BUFFER_PRESERVED;
-}
-EGLBoolean egl_surface_t::setSwapRectangle(
-        EGLint l, EGLint t, EGLint w, EGLint h)
-{
-    return EGL_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_window_surface_v2_t : public egl_surface_t {
-    egl_window_surface_v2_t(
-            EGLDisplay dpy, EGLConfig config,
-            int32_t depthFormat,
-            ANativeWindow* window);
-
-    ~egl_window_surface_v2_t();
-
-    virtual     bool        initCheck() const {
-        return true;   // TODO: report failure if ctor fails
-    }
-    virtual     EGLBoolean  swapBuffers();
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLBoolean  connect();
-    virtual     void        disconnect();
-    virtual     EGLint      getWidth() const    {
-        return width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return height;
-    }
-    virtual     EGLint      getHorizontalResolution() const;
-    virtual     EGLint      getVerticalResolution() const;
-    virtual     EGLint      getRefreshRate() const;
-    virtual     EGLint      getSwapBehavior() const;
-    virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-
-private:
-    status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
-    status_t unlock(ANativeWindowBuffer* buf);
-    ANativeWindow*   nativeWindow;
-    ANativeWindowBuffer*   buffer;
-    ANativeWindowBuffer*   previousBuffer;
-    gralloc_module_t const*    module;
-    int width;
-    int height;
-    void* bits;
-    GGLFormat const* pixelFormatTable;
-
-    struct Rect {
-        inline Rect() { };
-        inline Rect(int32_t w, int32_t h)
-        : left(0), top(0), right(w), bottom(h) { }
-        inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
-        : left(l), top(t), right(r), bottom(b) { }
-        Rect& andSelf(const Rect& r) {
-            left   = max(left, r.left);
-            top    = max(top, r.top);
-            right  = min(right, r.right);
-            bottom = min(bottom, r.bottom);
-            return *this;
-        }
-        bool isEmpty() const {
-            return (left>=right || top>=bottom);
-        }
-        void dump(char const* what) {
-            LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
-                    what, left, top, right-left, bottom-top);
-        }
-
-        int32_t left;
-        int32_t top;
-        int32_t right;
-        int32_t bottom;
-    };
-
-    struct Region {
-        inline Region() : count(0) { }
-        typedef Rect const* const_iterator;
-        const_iterator begin() const {
-            return storage;
-        }
-        const_iterator end() const {
-            return storage+count;
-        }
-        static Region subtract(const Rect& lhs, const Rect& rhs) {
-            Region reg;
-            Rect* storage = reg.storage;
-            if (!lhs.isEmpty()) {
-                if (lhs.top < rhs.top) { // top rect
-                    storage->left   = lhs.left;
-                    storage->top    = lhs.top;
-                    storage->right  = lhs.right;
-                    storage->bottom = rhs.top;
-                    storage++;
-                }
-                const int32_t top = max(lhs.top, rhs.top);
-                const int32_t bot = min(lhs.bottom, rhs.bottom);
-                if (top < bot) {
-                    if (lhs.left < rhs.left) { // left-side rect
-                        storage->left   = lhs.left;
-                        storage->top    = top;
-                        storage->right  = rhs.left;
-                        storage->bottom = bot;
-                        storage++;
-                    }
-                    if (lhs.right > rhs.right) { // right-side rect
-                        storage->left   = rhs.right;
-                        storage->top    = top;
-                        storage->right  = lhs.right;
-                        storage->bottom = bot;
-                        storage++;
-                    }
-                }
-                if (lhs.bottom > rhs.bottom) { // bottom rect
-                    storage->left   = lhs.left;
-                    storage->top    = rhs.bottom;
-                    storage->right  = lhs.right;
-                    storage->bottom = lhs.bottom;
-                    storage++;
-                }
-                reg.count = storage - reg.storage;
-            }
-            return reg;
-        }
-        bool isEmpty() const {
-            return count<=0;
-        }
-    private:
-        Rect storage[4];
-        ssize_t count;
-    };
-
-    void copyBlt(
-            ANativeWindowBuffer* dst, void* dst_vaddr,
-            ANativeWindowBuffer* src, void const* src_vaddr,
-            const Region& clip);
-
-    Rect dirtyRegion;
-    Rect oldDirtyRegion;
-};
-
-egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat,
-        ANativeWindow* window)
-: egl_surface_t(dpy, config, depthFormat),
-  nativeWindow(window), buffer(0), previousBuffer(0), module(0),
-  bits(NULL)
-{
-    pixelFormatTable = gglGetPixelFormatTable();
-
-    // keep a reference on the window
-    nativeWindow->common.incRef(&nativeWindow->common);
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
-    int format = 0;
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format);
-    LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format);
-    //   assert(0);
-}
-
-egl_window_surface_v2_t::~egl_window_surface_v2_t()
-{
-    if (buffer) {
-        buffer->common.decRef(&buffer->common);
-    }
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-    }
-    nativeWindow->common.decRef(&nativeWindow->common);
-}
-
-EGLBoolean egl_window_surface_v2_t::connect()
-{
-    // we're intending to do software rendering
-    native_window_set_usage(nativeWindow,
-            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
-    // dequeue a buffer
-    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
-        return setError(EGL_BAD_ALLOC, EGL_FALSE);
-    }
-
-    // allocate a corresponding depth-buffer
-    width = buffer->width;
-    height = buffer->height;
-    if (depth.format) {
-        depth.width   = width;
-        depth.height  = height;
-        depth.stride  = depth.width; // use the width here
-        assert(GGL_PIXEL_FORMAT_Z_32 == depth.format);
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*4);
-        if (depth.data == 0) {
-            return setError(EGL_BAD_ALLOC, EGL_FALSE);
-        }
-    }
-
-    // keep a reference on the buffer
-    buffer->common.incRef(&buffer->common);
-
-    // Lock the buffer
-    nativeWindow->lockBuffer(nativeWindow, buffer);
-    // pin the buffer down
-    if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
-            GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
-        LOGE("connect() failed to lock buffer %p (%ux%u)",
-                buffer, buffer->width, buffer->height);
-        return setError(EGL_BAD_ACCESS, EGL_FALSE);
-        // FIXME: we should make sure we're not accessing the buffer anymore
-    }
-    return EGL_TRUE;
-}
-
-void egl_window_surface_v2_t::disconnect()
-{
-    if (buffer && bits) {
-        bits = NULL;
-        unlock(buffer);
-    }
-    // enqueue the last frame
-    if (buffer)
-        nativeWindow->queueBuffer(nativeWindow, buffer);
-    if (buffer) {
-        buffer->common.decRef(&buffer->common);
-        buffer = 0;
-    }
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-        previousBuffer = 0;
-    }
-}
-
-status_t egl_window_surface_v2_t::lock(
-        ANativeWindowBuffer* buf, int usage, void** vaddr)
-{
-    int err;
-
-    err = module->lock(module, buf->handle,
-            usage, 0, 0, buf->width, buf->height, vaddr);
-
-    return err;
-}
-
-status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
-{
-    if (!buf) return BAD_VALUE;
-    int err = NO_ERROR;
-
-    err = module->unlock(module, buf->handle);
-
-    return err;
-}
-
-void egl_window_surface_v2_t::copyBlt(
-        ANativeWindowBuffer* dst, void* dst_vaddr,
-        ANativeWindowBuffer* src, void const* src_vaddr,
-        const Region& clip)
-{
-    // NOTE: dst and src must be the same format
-
-    Region::const_iterator cur = clip.begin();
-    Region::const_iterator end = clip.end();
-
-    const size_t bpp = pixelFormatTable[src->format].size;
-    const size_t dbpr = dst->stride * bpp;
-    const size_t sbpr = src->stride * bpp;
-
-    uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
-    uint8_t       * const dst_bits = (uint8_t       *)dst_vaddr;
-
-    while (cur != end) {
-        const Rect& r(*cur++);
-        ssize_t w = r.right - r.left;
-        ssize_t h = r.bottom - r.top;
-        if (w <= 0 || h<=0) continue;
-        size_t size = w * bpp;
-        uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
-        uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
-        if (dbpr==sbpr && size==sbpr) {
-            size *= h;
-            h = 1;
-        }
-        do {
-            memcpy(d, s, size);
-            d += dbpr;
-            s += sbpr;
-        } while (--h > 0);
-    }
-}
-
-EGLBoolean egl_window_surface_v2_t::swapBuffers()
-{
-    if (!buffer) {
-        return setError(EGL_BAD_ACCESS, EGL_FALSE);
-    }
-
-    /*
-     * Handle eglSetSwapRectangleANDROID()
-     * We copyback from the front buffer
-     */
-    if (!dirtyRegion.isEmpty()) {
-        dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
-        if (previousBuffer) {
-            // This was const Region copyBack, but that causes an
-            // internal compile error on simulator builds
-            /*const*/
-            Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
-            if (!copyBack.isEmpty()) {
-                void* prevBits;
-                if (lock(previousBuffer,
-                        GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
-                    // copy from previousBuffer to buffer
-                    copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
-                    unlock(previousBuffer);
-                }
-            }
-        }
-        oldDirtyRegion = dirtyRegion;
-    }
-
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-        previousBuffer = 0;
-    }
-
-    unlock(buffer);
-    previousBuffer = buffer;
-    nativeWindow->queueBuffer(nativeWindow, buffer);
-    buffer = 0;
-
-    // dequeue a new buffer
-    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
-
-        // TODO: lockBuffer should rather be executed when the very first
-        // direct rendering occurs.
-        nativeWindow->lockBuffer(nativeWindow, buffer);
-
-        // reallocate the depth-buffer if needed
-        if ((width != buffer->width) || (height != buffer->height)) {
-            // TODO: we probably should reset the swap rect here
-            // if the window size has changed
-            width = buffer->width;
-            height = buffer->height;
-            if (depth.data) {
-                free(depth.data);
-                depth.width   = width;
-                depth.height  = height;
-                depth.stride  = buffer->stride;
-                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-                if (depth.data == 0) {
-                    setError(EGL_BAD_ALLOC, EGL_FALSE);
-                    return EGL_FALSE;
-                }
-            }
-        }
-
-        // keep a reference on the buffer
-        buffer->common.incRef(&buffer->common);
-
-        // finally pin the buffer down
-        if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
-                GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
-            LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
-                    buffer, buffer->width, buffer->height);
-            return setError(EGL_BAD_ACCESS, EGL_FALSE);
-            // FIXME: we should make sure we're not accessing the buffer anymore
-        }
-    } else {
-        return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
-    }
-
-    return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
-        EGLint l, EGLint t, EGLint w, EGLint h)
-{
-    dirtyRegion = Rect(l, t, l+w, t+h);
-    return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::bindDrawSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = this->buffer->width;
-    buffer.height  = this->buffer->height;
-    buffer.stride  = this->buffer->stride;
-    buffer.data    = (GGLubyte*)bits;
-    buffer.format  = (GGLPixelFormat)this->buffer->format;
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-
-    return EGL_TRUE;
-}
-EGLBoolean egl_window_surface_v2_t::bindReadSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = this->buffer->width;
-    buffer.height  = this->buffer->height;
-    buffer.stride  = this->buffer->stride;
-    buffer.data    = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
-    buffer.format  = (GGLPixelFormat)this->buffer->format;
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &buffer);
-    return EGL_TRUE;
-}
-EGLint egl_window_surface_v2_t::getHorizontalResolution() const
-{
-    return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getVerticalResolution() const
-{
-    return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getRefreshRate() const
-{
-    return (60 * EGL_DISPLAY_SCALING); // FIXME
-}
-EGLint egl_window_surface_v2_t::getSwapBehavior() const
-{
-    /*
-     * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
-     * the content of the swapped buffer.
-     *
-     * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
-     *
-     * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
-     * only applies to the area specified by eglSetSwapRectangleANDROID(), that
-     * is, everything outside of this area is preserved.
-     *
-     * This implementation of EGL assumes the later case.
-     *
-     */
-
-    return EGL_BUFFER_DESTROYED;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pixmap_surface_t : public egl_surface_t {
-    egl_pixmap_surface_t(
-            EGLDisplay dpy, EGLConfig config,
-            int32_t depthFormat,
-            egl_native_pixmap_t const * pixmap);
-
-    virtual ~egl_pixmap_surface_t() { }
-
-    virtual     bool        initCheck() const {
-        return !depth.format || depth.data!=0;
-    }
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLint      getWidth() const    {
-        return nativePixmap.width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return nativePixmap.height;
-    }
-private:
-    egl_native_pixmap_t     nativePixmap;
-};
-
-egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat,
-        egl_native_pixmap_t const * pixmap)
-: egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
-{
-    if (depthFormat) {
-        depth.width   = pixmap->width;
-        depth.height  = pixmap->height;
-        depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-        if (depth.data == 0) {
-            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-        }
-    }
-}
-EGLBoolean egl_pixmap_surface_t::bindDrawSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = nativePixmap.width;
-    buffer.height  = nativePixmap.height;
-    buffer.stride  = nativePixmap.stride;
-    buffer.data    = nativePixmap.data;
-    buffer.format  = (GGLPixelFormat)nativePixmap.format;
-
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-    return EGL_TRUE;
-}
-EGLBoolean egl_pixmap_surface_t::bindReadSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = nativePixmap.width;
-    buffer.height  = nativePixmap.height;
-    buffer.stride  = nativePixmap.stride;
-    buffer.data    = nativePixmap.data;
-    buffer.format  = (GGLPixelFormat)nativePixmap.format;
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &buffer);
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pbuffer_surface_t : public egl_surface_t {
-    egl_pbuffer_surface_t(
-            EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
-            int32_t w, int32_t h, int32_t f);
-
-    virtual ~egl_pbuffer_surface_t();
-
-    virtual     bool        initCheck() const   {
-        return pbuffer.data != 0;
-    }
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLint      getWidth() const    {
-        return pbuffer.width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return pbuffer.height;
-    }
-private:
-    GGLSurface  pbuffer;
-};
-
-egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
-        EGLConfig config, int32_t depthFormat,
-        int32_t w, int32_t h, int32_t f)
-: egl_surface_t(dpy, config, depthFormat)
-{
-    size_t size = w*h;
-    switch (f) {
-        case GGL_PIXEL_FORMAT_A_8:
-            size *= 1;
-            break;
-        case GGL_PIXEL_FORMAT_RGB_565:
-            size *= 2;
-            break;
-        case GGL_PIXEL_FORMAT_RGBA_8888:
-            size *= 4;
-            break;
-        case GGL_PIXEL_FORMAT_RGBX_8888:
-            size *= 4;
-            break;
-        default:
-            LOGE("incompatible pixel format for pbuffer (format=%d)", f);
-            pbuffer.data = 0;
-            break;
-    }
-    pbuffer.version = sizeof(GGLSurface);
-    pbuffer.width   = w;
-    pbuffer.height  = h;
-    pbuffer.stride  = w;
-    pbuffer.data    = (GGLubyte*)malloc(size);
-    pbuffer.format  = (GGLPixelFormat)f;
-
-    if (depthFormat) {
-        depth.width   = pbuffer.width;
-        depth.height  = pbuffer.height;
-        depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-        if (depth.data == 0) {
-            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-            return;
-        }
-    }
-}
-egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
-{
-    free(pbuffer.data);
-}
-EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(GLES2Context* gl)
-{
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-    return EGL_TRUE;
-}
-EGLBoolean egl_pbuffer_surface_t::bindReadSurface(GLES2Context* gl)
-{
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &pbuffer);
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct config_pair_t {
-    GLint key;
-    GLint value;
-};
-
-struct configs_t {
-    const config_pair_t* array;
-    int                  size;
-};
-
-struct config_management_t {
-    GLint key;
-    bool (*match)(GLint reqValue, GLint confValue);
-    static bool atLeast(GLint reqValue, GLint confValue) {
-        return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
-    }
-    static bool exact(GLint reqValue, GLint confValue) {
-        return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
-    }
-    static bool mask(GLint reqValue, GLint confValue) {
-        return (confValue & reqValue) == reqValue;
-    }
-    static bool ignore(GLint reqValue, GLint confValue) {
-        return true;
-    }
-};
-
-// ----------------------------------------------------------------------------
-
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 2
-static char const * const gVendorString     = "Google Inc.";
-static char const * const gVersionString    = "0.0 Android Driver 0.0.0";
-static char const * const gClientApiString  = "OpenGL ES2";
-static char const * const gExtensionsString =
-        //"EGL_KHR_image_base "
-        // "KHR_image_pixmap "
-        //"EGL_ANDROID_image_native_buffer "
-        //"EGL_ANDROID_swap_rectangle "
-        "";
-
-// ----------------------------------------------------------------------------
-
-struct extention_map_t {
-    const char * const name;
-    __eglMustCastToProperFunctionPointerType address;
-};
-
-static const extention_map_t gExtentionMap[] = {
-        //    { "glDrawTexsOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
-        //    { "glDrawTexiOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
-        //    { "glDrawTexfOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
-        //    { "glDrawTexxOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
-        //    { "glDrawTexsvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
-        //    { "glDrawTexivOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
-        //    { "glDrawTexfvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
-        //    { "glDrawTexxvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
-        //    { "glQueryMatrixxOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
-        //    { "glEGLImageTargetTexture2DOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
-        //    { "glEGLImageTargetRenderbufferStorageOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
-        //    { "glClipPlanef",
-        //            (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
-        //    { "glClipPlanex",
-        //            (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
-        //    { "glBindBuffer",
-        //            (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
-        //    { "glBufferData",
-        //            (__eglMustCastToProperFunctionPointerType)&glBufferData },
-        //    { "glBufferSubData",
-        //            (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
-        //    { "glDeleteBuffers",
-        //            (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
-        //    { "glGenBuffers",
-        //            (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
-        //    { "eglCreateImageKHR",
-        //            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
-        //    { "eglDestroyImageKHR",
-        //            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-        //    { "eglSetSwapRectangleANDROID",
-        //            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
-};
-
-/*
- * In the lists below, attributes names MUST be sorted.
- * Additionally, all configs must be sorted according to
- * the EGL specification.
- */
-
-static config_pair_t const config_base_attribute_list[] = {
-        { EGL_STENCIL_SIZE,               0                                 },
-        { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
-        { EGL_LEVEL,                      0                                 },
-        { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
-        { EGL_MAX_PBUFFER_PIXELS,
-                GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
-                { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
-                { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
-                { EGL_NATIVE_VISUAL_ID,           0                                 },
-                { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGBA_8888        },
-                { EGL_SAMPLES,                    0                                 },
-                { EGL_SAMPLE_BUFFERS,             0                                 },
-                { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
-                { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
-                { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
-                { EGL_TRANSPARENT_RED_VALUE,      0                                 },
-                { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
-                { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
-                { EGL_MIN_SWAP_INTERVAL,          1                                 },
-                { EGL_MAX_SWAP_INTERVAL,          1                                 },
-                { EGL_LUMINANCE_SIZE,             0                                 },
-                { EGL_ALPHA_MASK_SIZE,            0                                 },
-                { EGL_COLOR_BUFFER_TYPE,          EGL_RGB_BUFFER                    },
-                { EGL_RENDERABLE_TYPE,            EGL_OPENGL_ES2_BIT                },
-                { EGL_CONFORMANT,                 0                                 }
-};
-
-// These configs can override the base attribute list
-// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
-
-// 565 configs
-static config_pair_t const config_0_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     16 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        5 },
-        { EGL_GREEN_SIZE,       6 },
-        { EGL_RED_SIZE,         5 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        0 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_1_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     16 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        5 },
-        { EGL_GREEN_SIZE,       6 },
-        { EGL_RED_SIZE,         5 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        1 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// RGB 888 configs
-static config_pair_t const config_2_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        6 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_3_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        7 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// 8888 configs
-static config_pair_t const config_4_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        2 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_5_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        3 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// A8 configs
-static config_pair_t const config_6_attribute_list[] = {
-        { EGL_BUFFER_SIZE,      8 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        0 },
-        { EGL_GREEN_SIZE,       0 },
-        { EGL_RED_SIZE,         0 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        4 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_7_attribute_list[] = {
-        { EGL_BUFFER_SIZE,      8 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        0 },
-        { EGL_GREEN_SIZE,       0 },
-        { EGL_RED_SIZE,         0 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        5 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static configs_t const gConfigs[] = {
-        { config_0_attribute_list, NELEM(config_0_attribute_list) },
-        { config_1_attribute_list, NELEM(config_1_attribute_list) },
-        { config_2_attribute_list, NELEM(config_2_attribute_list) },
-        { config_3_attribute_list, NELEM(config_3_attribute_list) },
-        { config_4_attribute_list, NELEM(config_4_attribute_list) },
-        { config_5_attribute_list, NELEM(config_5_attribute_list) },
-        //   { config_6_attribute_list, NELEM(config_6_attribute_list) },
-        //   { config_7_attribute_list, NELEM(config_7_attribute_list) },
-};
-
-static config_management_t const gConfigManagement[] = {
-        { EGL_BUFFER_SIZE,                config_management_t::atLeast },
-        { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
-        { EGL_BLUE_SIZE,                  config_management_t::atLeast },
-        { EGL_GREEN_SIZE,                 config_management_t::atLeast },
-        { EGL_RED_SIZE,                   config_management_t::atLeast },
-        { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
-        { EGL_STENCIL_SIZE,               config_management_t::atLeast },
-        { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
-        { EGL_CONFIG_ID,                  config_management_t::exact   },
-        { EGL_LEVEL,                      config_management_t::exact   },
-        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::ignore   },
-        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::ignore   },
-        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::ignore   },
-        { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
-        { EGL_NATIVE_VISUAL_ID,           config_management_t::ignore   },
-        { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
-        { EGL_SAMPLES,                    config_management_t::exact   },
-        { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
-        { EGL_SURFACE_TYPE,               config_management_t::mask    },
-        { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
-        { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
-        { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
-        { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
-        { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
-        { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
-        { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
-        { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
-        { EGL_LUMINANCE_SIZE,             config_management_t::atLeast },
-        { EGL_ALPHA_MASK_SIZE,            config_management_t::atLeast },
-        { EGL_COLOR_BUFFER_TYPE,          config_management_t::exact   },
-        { EGL_RENDERABLE_TYPE,            config_management_t::mask    },
-        { EGL_CONFORMANT,                 config_management_t::mask    }
-};
-
-
-static config_pair_t const config_defaults[] = {
-        // attributes that are not specified are simply ignored, if a particular
-        // one needs not be ignored, it must be specified here, eg:
-        // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
-};
-
-// ----------------------------------------------------------------------------
-
-static status_t getConfigFormatInfo(EGLint configID,
-        int32_t& pixelFormat, int32_t& depthFormat)
-{
-    switch (configID) {
-        case 0:
-            pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
-            depthFormat = 0;
-            break;
-        case 1:
-            pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 2:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = 0;
-            break;
-        case 3:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 4:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = 0;
-            break;
-        case 5:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 6:
-            pixelFormat = GGL_PIXEL_FORMAT_A_8;
-            depthFormat = 0;
-            break;
-        case 7:
-            pixelFormat = GGL_PIXEL_FORMAT_A_8;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        default:
-            return NAME_NOT_FOUND;
-    }
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-template<typename T>
-static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
-{
-    while (first <= last) {
-        int mid = (first + last) / 2;
-        if (key > sortedArray[mid].key) {
-            first = mid + 1;
-        } else if (key < sortedArray[mid].key) {
-            last = mid - 1;
-        } else {
-            return mid;
-        }
-    }
-    return -1;
-}
-
-static int isAttributeMatching(int i, EGLint attr, EGLint val)
-{
-    // look for the attribute in all of our configs
-    config_pair_t const* configFound = gConfigs[i].array;
-    int index = binarySearch<config_pair_t>(
-            gConfigs[i].array,
-            0, gConfigs[i].size-1,
-            attr);
-    if (index < 0) {
-        configFound = config_base_attribute_list;
-        index = binarySearch<config_pair_t>(
-                config_base_attribute_list,
-                0, NELEM(config_base_attribute_list)-1,
-                attr);
-    }
-    if (index >= 0) {
-        // attribute found, check if this config could match
-        int cfgMgtIndex = binarySearch<config_management_t>(
-                gConfigManagement,
-                0, NELEM(gConfigManagement)-1,
-                attr);
-        if (cfgMgtIndex >= 0) {
-            bool match = gConfigManagement[cfgMgtIndex].match(
-                    val, configFound[index].value);
-            if (match) {
-                // this config matches
-                return 1;
-            }
-        } else {
-            // attribute not found. this should NEVER happen.
-        }
-    } else {
-        // error, this attribute doesn't exist
-    }
-    return 0;
-}
-
-static int makeCurrent(GLES2Context* gl)
-{
-    GLES2Context* current = (GLES2Context*)getGlThreadSpecific();
-    if (gl) {
-        egl_context_t* c = egl_context_t::context(gl);
-        if (c->flags & egl_context_t::IS_CURRENT) {
-            if (current != gl) {
-                // it is an error to set a context current, if it's already
-                // current to another thread
-                return -1;
-            }
-        } else {
-            if (current) {
-                // mark the current context as not current, and flush
-                glFlush();
-                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
-            }
-        }
-        if (!(c->flags & egl_context_t::IS_CURRENT)) {
-            // The context is not current, make it current!
-            setGlThreadSpecific(gl);
-            c->flags |= egl_context_t::IS_CURRENT;
-        }
-    } else {
-        if (current) {
-            // mark the current context as not current, and flush
-            glFlush();
-            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
-        }
-        // this thread has no context attached to it
-        setGlThreadSpecific(0);
-    }
-    return 0;
-}
-
-static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
-        EGLint attribute, EGLint *value)
-{
-    size_t numConfigs =  NELEM(gConfigs);
-    int index = (int)config;
-    if (uint32_t(index) >= numConfigs)
-        return setError(EGL_BAD_CONFIG, EGL_FALSE);
-
-    int attrIndex;
-    attrIndex = binarySearch<config_pair_t>(
-            gConfigs[index].array,
-            0, gConfigs[index].size-1,
-            attribute);
-    if (attrIndex>=0) {
-        *value = gConfigs[index].array[attrIndex].value;
-        return EGL_TRUE;
-    }
-
-    attrIndex = binarySearch<config_pair_t>(
-            config_base_attribute_list,
-            0, NELEM(config_base_attribute_list)-1,
-            attribute);
-    if (attrIndex>=0) {
-        *value = config_base_attribute_list[attrIndex].value;
-        return EGL_TRUE;
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
-        NativeWindowType window, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    if (window == 0)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_WINDOW_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    if (reinterpret_cast<ANativeWindow*>(window)->common.magic !=
-            ANDROID_NATIVE_WINDOW_MAGIC) {
-        return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
-    }
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    // FIXME: we don't have access to the pixelFormat here just yet.
-    // (it's possible that the surface is not fully initialized)
-    // maybe this should be done after the page-flip
-    //if (EGLint(info.format) != pixelFormat)
-    //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    egl_surface_t* surface;
-    surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
-            reinterpret_cast<ANativeWindow*>(window));
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
-        NativePixmapType pixmap, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    if (pixmap == 0)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_PIXMAP_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version !=
-            sizeof(egl_native_pixmap_t)) {
-        return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
-    }
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    egl_surface_t* surface =
-            new egl_pixmap_surface_t(dpy, config, depthFormat,
-                    reinterpret_cast<egl_native_pixmap_t*>(pixmap));
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
-        const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_PBUFFER_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    int32_t w = 0;
-    int32_t h = 0;
-    while (attrib_list[0]) {
-        if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
-        if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
-        attrib_list+=2;
-    }
-
-    egl_surface_t* surface =
-            new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-// Initialization
-// ----------------------------------------------------------------------------
-
-EGLDisplay eglGetDisplay(NativeDisplayType display)
-{
-    puts("agl2:eglGetDisplay");
-#ifndef HAVE_ANDROID_OS
-    // this just needs to be done once
-    if (gGLKey == -1) {
-        pthread_mutex_lock(&gInitMutex);
-        if (gGLKey == -1)
-            pthread_key_create(&gGLKey, NULL);
-        pthread_mutex_unlock(&gInitMutex);
-    }
-#endif
-    if (display == EGL_DEFAULT_DISPLAY) {
-        EGLDisplay dpy = (EGLDisplay)1;
-        egl_display_t& d = egl_display_t::get_display(dpy);
-        d.type = display;
-        return dpy;
-    }
-    return EGL_NO_DISPLAY;
-}
-
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
-    puts("agl2:eglInitialize");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean res = EGL_TRUE;
-    egl_display_t& d = egl_display_t::get_display(dpy);
-
-    if (android_atomic_inc(&d.initialized) == 0) {
-        // initialize stuff here if needed
-        //pthread_mutex_lock(&gInitMutex);
-        //pthread_mutex_unlock(&gInitMutex);
-    }
-
-    if (res == EGL_TRUE) {
-        if (major != NULL) *major = VERSION_MAJOR;
-        if (minor != NULL) *minor = VERSION_MINOR;
-    }
-    return res;
-}
-
-EGLBoolean eglTerminate(EGLDisplay dpy)
-{
-    puts("agl2:eglTerminate");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean res = EGL_TRUE;
-    egl_display_t& d = egl_display_t::get_display(dpy);
-    if (android_atomic_dec(&d.initialized) == 1) {
-        // TODO: destroy all resources (surfaces, contexts, etc...)
-        //pthread_mutex_lock(&gInitMutex);
-        //pthread_mutex_unlock(&gInitMutex);
-    }
-    return res;
-}
-
-// ----------------------------------------------------------------------------
-// configuration
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglGetConfigs(   EGLDisplay dpy,
-        EGLConfig *configs,
-        EGLint config_size, EGLint *num_config)
-{
-    puts("agl2:eglGetConfigs");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    GLint numConfigs = NELEM(gConfigs);
-    if (!configs) {
-        *num_config = numConfigs;
-        return EGL_TRUE;
-    }
-    GLint i;
-    for (i=0 ; i<numConfigs && i<config_size ; i++) {
-        *configs++ = (EGLConfig)i;
-    }
-    *num_config = i;
-    return EGL_TRUE;
-}
-
-static const char * ATTRIBUTE_NAMES [] = {
-        "EGL_BUFFER_SIZE",
-        "EGL_ALPHA_SIZE",
-        "EGL_BLUE_SIZE",
-        "EGL_GREEN_SIZE",
-        "EGL_RED_SIZE",
-        "EGL_DEPTH_SIZE",
-        "EGL_STENCIL_SIZE",
-        "EGL_CONFIG_CAVEAT",
-        "EGL_CONFIG_ID",
-        "EGL_LEVEL",
-        "EGL_MAX_PBUFFER_HEIGHT",
-        "EGL_MAX_PBUFFER_PIXELS",
-        "EGL_MAX_PBUFFER_WIDTH",
-        "EGL_NATIVE_RENDERABLE",
-        "EGL_NATIVE_VISUAL_ID",
-        "EGL_NATIVE_VISUAL_TYPE",
-        "EGL_PRESERVED_RESOURCES",
-        "EGL_SAMPLES",
-        "EGL_SAMPLE_BUFFERS",
-        "EGL_SURFACE_TYPE",
-        "EGL_TRANSPARENT_TYPE",
-        "EGL_TRANSPARENT_BLUE_VALUE",
-        "EGL_TRANSPARENT_GREEN_VALUE",
-        "EGL_TRANSPARENT_RED_VALUE",
-        "EGL_NONE",   /* Attrib list terminator */
-        "EGL_BIND_TO_TEXTURE_RGB",
-        "EGL_BIND_TO_TEXTURE_RGBA",
-        "EGL_MIN_SWAP_INTERVAL",
-        "EGL_MAX_SWAP_INTERVAL",
-        "EGL_LUMINANCE_SIZE",
-        "EGL_ALPHA_MASK_SIZE",
-        "EGL_COLOR_BUFFER_TYPE",
-        "EGL_RENDERABLE_TYPE",
-        "EGL_MATCH_NATIVE_PIXMAP",   /* Pseudo-attribute (not queryable) */
-        "EGL_CONFORMANT",
-};
-
-EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
-        EGLConfig *configs, EGLint config_size,
-        EGLint *num_config)
-{
-    puts("agl2:eglChooseConfig");
-    LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    if (ggl_unlikely(num_config==0)) {
-        LOGD("\n***\n***\n num_config==0 \n***\n***\n");
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-    }
-
-    if (ggl_unlikely(attrib_list==0)) {
-        /*
-         * A NULL attrib_list should be treated as though it was an empty
-         * one (terminated with EGL_NONE) as defined in
-         * section 3.4.1 "Querying Configurations" in the EGL specification.
-         */
-        LOGD("\n***\n***\n attrib_list==0 \n***\n***\n");
-        static const EGLint dummy = EGL_NONE;
-        attrib_list = &dummy;
-    }
-
-    for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) {
-        LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]);
-        if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0])
-            LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]);
-    }
-
-    int numAttributes = 0;
-    int numConfigs =  NELEM(gConfigs);
-    uint32_t possibleMatch = (1<<numConfigs)-1;
-    while (possibleMatch && *attrib_list != EGL_NONE) {
-        numAttributes++;
-        EGLint attr = *attrib_list++;
-        EGLint val  = *attrib_list++;
-        for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
-            if (!(possibleMatch & (1<<i)))
-                continue;
-            if (isAttributeMatching(i, attr, val) == 0) {
-                LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val);
-                possibleMatch &= ~(1<<i);
-            }
-        }
-    }
-
-    LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch);
-
-    // now, handle the attributes which have a useful default value
-    for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
-        // see if this attribute was specified, if not, apply its
-        // default value
-        if (binarySearch<config_pair_t>(
-                (config_pair_t const*)attrib_list,
-                0, numAttributes-1,
-                config_defaults[j].key) < 0) {
-            for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
-                if (!(possibleMatch & (1<<i)))
-                    continue;
-                if (isAttributeMatching(i,
-                        config_defaults[j].key,
-                        config_defaults[j].value) == 0) {
-                    possibleMatch &= ~(1<<i);
-                }
-            }
-        }
-    }
-
-    // return the configurations found
-    int n=0;
-    if (possibleMatch) {
-        if (configs) {
-            for (int i=0 ; config_size && i<numConfigs ; i++) {
-                if (possibleMatch & (1<<i)) {
-                    *configs++ = (EGLConfig)i;
-                    config_size--;
-                    n++;
-                }
-            }
-        } else {
-            for (int i=0 ; i<numConfigs ; i++) {
-                if (possibleMatch & (1<<i)) {
-                    n++;
-                }
-            }
-        }
-    }
-    *num_config = n;
-    LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config);
-    return EGL_TRUE;
-}
-
-EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
-        EGLint attribute, EGLint *value)
-{
-    puts("agl2:eglGetConfigAttrib");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    return getConfigAttrib(dpy, config, attribute, value);
-}
-
-// ----------------------------------------------------------------------------
-// surfaces
-// ----------------------------------------------------------------------------
-
-EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
-        NativeWindowType window,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreateWindowSurface");
-    return createWindowSurface(dpy, config, window, attrib_list);
-}
-
-EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
-        NativePixmapType pixmap,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreatePixmapSurface");
-    return createPixmapSurface(dpy, config, pixmap, attrib_list);
-}
-
-EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreatePbufferSurface");
-    return createPbufferSurface(dpy, config, attrib_list);
-}
-
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
-{
-    puts("agl2:eglDestroySurface");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (eglSurface != EGL_NO_SURFACE) {
-        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
-        if (!surface->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (surface->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        if (surface->ctx) {
-            // FIXME: this surface is current check what the spec says
-            surface->disconnect();
-            surface->ctx = 0;
-        }
-        delete surface;
-    }
-    return EGL_TRUE;
-}
-
-EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
-        EGLint attribute, EGLint *value)
-{
-    puts("agl2:eglQuerySurface");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
-    if (!surface->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (surface->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean ret = EGL_TRUE;
-    switch (attribute) {
-        case EGL_CONFIG_ID:
-            ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
-            break;
-        case EGL_WIDTH:
-            *value = surface->getWidth();
-            break;
-        case EGL_HEIGHT:
-            *value = surface->getHeight();
-            break;
-        case EGL_LARGEST_PBUFFER:
-            // not modified for a window or pixmap surface
-            break;
-        case EGL_TEXTURE_FORMAT:
-            *value = EGL_NO_TEXTURE;
-            break;
-        case EGL_TEXTURE_TARGET:
-            *value = EGL_NO_TEXTURE;
-            break;
-        case EGL_MIPMAP_TEXTURE:
-            *value = EGL_FALSE;
-            break;
-        case EGL_MIPMAP_LEVEL:
-            *value = 0;
-            break;
-        case EGL_RENDER_BUFFER:
-            // TODO: return the real RENDER_BUFFER here
-            *value = EGL_BACK_BUFFER;
-            break;
-        case EGL_HORIZONTAL_RESOLUTION:
-            // pixel/mm * EGL_DISPLAY_SCALING
-            *value = surface->getHorizontalResolution();
-            break;
-        case EGL_VERTICAL_RESOLUTION:
-            // pixel/mm * EGL_DISPLAY_SCALING
-            *value = surface->getVerticalResolution();
-            break;
-        case EGL_PIXEL_ASPECT_RATIO: {
-            // w/h * EGL_DISPLAY_SCALING
-            int wr = surface->getHorizontalResolution();
-            int hr = surface->getVerticalResolution();
-            *value = (wr * EGL_DISPLAY_SCALING) / hr;
-        }
-        break;
-        case EGL_SWAP_BEHAVIOR:
-            *value = surface->getSwapBehavior();
-            break;
-        default:
-            ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-    }
-    return ret;
-}
-
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
-        EGLContext share_list, const EGLint *attrib_list)
-{
-    puts("agl2:eglCreateContext");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
-    GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t));
-    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
-
-    //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
-    egl_context_t * c = &gl->egl;
-    c->flags = egl_context_t::NEVER_CURRENT;
-    c->dpy = dpy;
-    c->config = config;
-    c->read = 0;
-    c->draw = 0;
-
-    c->frame = 0;
-    c->lastSwapTime = clock();
-    c->accumulateSeconds = 0;
-    return (EGLContext)gl;
-}
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
-{
-    puts("agl2:eglDestroyContext");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_context_t* c = egl_context_t::context(ctx);
-    if (c->flags & egl_context_t::IS_CURRENT)
-        setGlThreadSpecific(0);
-    //ogles_uninit((GLES2Context*)ctx);
-    delete (GLES2Context*)ctx;
-    return EGL_TRUE;
-}
-
-EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
-        EGLSurface read, EGLContext ctx)
-{
-    puts("agl2:eglMakeCurrent");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (draw) {
-        egl_surface_t* s = (egl_surface_t*)draw;
-        if (!s->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (s->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        // TODO: check that draw is compatible with the context
-    }
-    if (read && read!=draw) {
-        egl_surface_t* s = (egl_surface_t*)read;
-        if (!s->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (s->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        // TODO: check that read is compatible with the context
-    }
-
-    EGLContext current_ctx = EGL_NO_CONTEXT;
-
-    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
-        return setError(EGL_BAD_MATCH, EGL_FALSE);
-
-    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
-        return setError(EGL_BAD_MATCH, EGL_FALSE);
-
-    if (ctx == EGL_NO_CONTEXT) {
-        // if we're detaching, we need the current context
-        current_ctx = (EGLContext)getGlThreadSpecific();
-    } else {
-        egl_context_t* c = egl_context_t::context(ctx);
-        egl_surface_t* d = (egl_surface_t*)draw;
-        egl_surface_t* r = (egl_surface_t*)read;
-        if ((d && d->ctx && d->ctx != ctx) ||
-                (r && r->ctx && r->ctx != ctx)) {
-            // one of the surface is bound to a context in another thread
-            return setError(EGL_BAD_ACCESS, EGL_FALSE);
-        }
-    }
-
-    GLES2Context* gl = (GLES2Context*)ctx;
-    if (makeCurrent(gl) == 0) {
-        if (ctx) {
-            egl_context_t* c = egl_context_t::context(ctx);
-            egl_surface_t* d = (egl_surface_t*)draw;
-            egl_surface_t* r = (egl_surface_t*)read;
-
-            if (c->draw) {
-                egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
-                s->disconnect();
-            }
-            if (c->read) {
-                // FIXME: unlock/disconnect the read surface too
-            }
-
-            c->draw = draw;
-            c->read = read;
-
-            if (c->flags & egl_context_t::NEVER_CURRENT) {
-                c->flags &= ~egl_context_t::NEVER_CURRENT;
-                GLint w = 0;
-                GLint h = 0;
-                if (draw) {
-                    w = d->getWidth();
-                    h = d->getHeight();
-                }
-                gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h);
-                //ogles_surfaceport(gl, 0, 0);
-                //ogles_viewport(gl, 0, 0, w, h);
-                //ogles_scissor(gl, 0, 0, w, h);
-            }
-            if (d) {
-                if (d->connect() == EGL_FALSE) {
-                    return EGL_FALSE;
-                }
-                d->ctx = ctx;
-                d->bindDrawSurface(gl);
-            }
-            if (r) {
-                // FIXME: lock/connect the read surface too
-                r->ctx = ctx;
-                r->bindReadSurface(gl);
-            }
-        } else {
-            // if surfaces were bound to the context bound to this thread
-            // mark then as unbound.
-            if (current_ctx) {
-                egl_context_t* c = egl_context_t::context(current_ctx);
-                egl_surface_t* d = (egl_surface_t*)c->draw;
-                egl_surface_t* r = (egl_surface_t*)c->read;
-                if (d) {
-                    c->draw = 0;
-                    d->ctx = EGL_NO_CONTEXT;
-                    d->disconnect();
-                }
-                if (r) {
-                    c->read = 0;
-                    r->ctx = EGL_NO_CONTEXT;
-                    // FIXME: unlock/disconnect the read surface too
-                }
-            }
-        }
-        return EGL_TRUE;
-    }
-    return setError(EGL_BAD_ACCESS, EGL_FALSE);
-}
-
-EGLContext eglGetCurrentContext(void)
-{
-    // eglGetCurrentContext returns the current EGL rendering context,
-    // as specified by eglMakeCurrent. If no context is current,
-    // EGL_NO_CONTEXT is returned.
-    return (EGLContext)getGlThreadSpecific();
-}
-
-EGLSurface eglGetCurrentSurface(EGLint readdraw)
-{
-    // eglGetCurrentSurface returns the read or draw surface attached
-    // to the current EGL rendering context, as specified by eglMakeCurrent.
-    // If no context is current, EGL_NO_SURFACE is returned.
-    EGLContext ctx = (EGLContext)getGlThreadSpecific();
-    if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
-    egl_context_t* c = egl_context_t::context(ctx);
-    if (readdraw == EGL_READ) {
-        return c->read;
-    } else if (readdraw == EGL_DRAW) {
-        return c->draw;
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
-}
-
-EGLDisplay eglGetCurrentDisplay(void)
-{
-    // eglGetCurrentDisplay returns the current EGL display connection
-    // for the current EGL rendering context, as specified by eglMakeCurrent.
-    // If no context is current, EGL_NO_DISPLAY is returned.
-    EGLContext ctx = (EGLContext)getGlThreadSpecific();
-    if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
-    egl_context_t* c = egl_context_t::context(ctx);
-    return c->dpy;
-}
-
-EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
-        EGLint attribute, EGLint *value)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_context_t* c = egl_context_t::context(ctx);
-    switch (attribute) {
-        case EGL_CONFIG_ID:
-            // Returns the ID of the EGL frame buffer configuration with
-            // respect to which the context was created
-            return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-EGLBoolean eglWaitGL(void)
-{
-    return EGL_TRUE;
-}
-
-EGLBoolean eglWaitNative(EGLint engine)
-{
-    return EGL_TRUE;
-}
-
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
-    if (!d->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (d->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    // post the surface
-    d->swapBuffers();
-
-    // if it's bound to a context, update the buffer
-    if (d->ctx != EGL_NO_CONTEXT) {
-        d->bindDrawSurface((GLES2Context*)d->ctx);
-        // if this surface is also the read surface of the context
-        // it is bound to, make sure to update the read buffer as well.
-        // The EGL spec is a little unclear about this.
-        egl_context_t* c = egl_context_t::context(d->ctx);
-        if (c->read == draw) {
-            d->bindReadSurface((GLES2Context*)d->ctx);
-        }
-        clock_t time = clock();
-        float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC;
-        c->accumulateSeconds += elapsed;
-        c->frame++;
-        //      LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000);
-        if (20 == c->frame) {
-            float avg = c->accumulateSeconds / c->frame;
-            LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*",
-                    c->frame, 1 / avg, avg * 1000);
-            c->frame = 0;
-            c->accumulateSeconds = 0;
-        }
-        c->lastSwapTime = time;
-    }
-
-    return EGL_TRUE;
-}
-
-EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
-        NativePixmapType target)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglCopyBuffers()
-    return EGL_FALSE;
-}
-
-EGLint eglGetError(void)
-{
-    return getError();
-}
-
-const char* eglQueryString(EGLDisplay dpy, EGLint name)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, (const char*)0);
-
-    switch (name) {
-        case EGL_VENDOR:
-            return gVendorString;
-        case EGL_VERSION:
-            return gVersionString;
-        case EGL_EXTENSIONS:
-            return gExtensionsString;
-        case EGL_CLIENT_APIS:
-            return gClientApiString;
-    }
-    return setError(EGL_BAD_PARAMETER, (const char *)0);
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.1
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSurfaceAttrib(
-        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglSurfaceAttrib()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglBindTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglBindTexImage()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglReleaseTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglReleaseTexImage()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglSwapInterval()
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.2
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglBindAPI(EGLenum api)
-{
-    if (api != EGL_OPENGL_ES_API)
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-    return EGL_TRUE;
-}
-
-EGLenum eglQueryAPI(void)
-{
-    return EGL_OPENGL_ES_API;
-}
-
-EGLBoolean eglWaitClient(void)
-{
-    glFinish();
-    return EGL_TRUE;
-}
-
-EGLBoolean eglReleaseThread(void)
-{
-    // TODO: eglReleaseThread()
-    return EGL_TRUE;
-}
-
-EGLSurface eglCreatePbufferFromClientBuffer(
-        EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
-        EGLConfig config, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    // TODO: eglCreatePbufferFromClientBuffer()
-    return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 3
-// ----------------------------------------------------------------------------
-
-void (*eglGetProcAddress (const char *procname))()
-        {
-    extention_map_t const * const map = gExtentionMap;
-    for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
-        if (!strcmp(procname, map[i].name)) {
-            return map[i].address;
-        }
-    }
-    return NULL;
-        }
-
-EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
-        const EGLint *attrib_list)
-{
-    EGLBoolean result = EGL_FALSE;
-    return result;
-}
-
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
-{
-    EGLBoolean result = EGL_FALSE;
-    return result;
-}
-
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
-        EGLClientBuffer buffer, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
-        return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
-    }
-    if (ctx != EGL_NO_CONTEXT) {
-        return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
-    }
-    if (target != EGL_NATIVE_BUFFER_ANDROID) {
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-    }
-
-    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
-
-    if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
-    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
-    switch (native_buffer->format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-        case HAL_PIXEL_FORMAT_RGB_888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        case HAL_PIXEL_FORMAT_RGBA_5551:
-        case HAL_PIXEL_FORMAT_RGBA_4444:
-            break;
-        default:
-            return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-    }
-
-    native_buffer->common.incRef(&native_buffer->common);
-    return (EGLImageKHR)native_buffer;
-}
-
-EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
-
-    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
-
-    if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
-    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
-    native_buffer->common.decRef(&native_buffer->common);
-
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// ANDROID extensions
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
-        EGLint left, EGLint top, EGLint width, EGLint height)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
-    if (!d->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (d->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    // post the surface
-    d->setSwapRectangle(left, top, width, height);
-
-    return EGL_TRUE;
-}
diff --git a/opengl/libagl2/src/get.cpp b/opengl/libagl2/src/get.cpp
deleted file mode 100644
index 13c28ce..0000000
--- a/opengl/libagl2/src/get.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "gles2context.h"
-
-static char const * const gVendorString     = "Android";
-static char const * const gRendererString   = "Android PixelFlinger2 0.0";
-static char const * const gVersionString    = "OpenGL ES 2.0";
-static char const * const gExtensionsString =
-//   "GL_OES_byte_coordinates "              // OK
-//   "GL_OES_fixed_point "                   // OK
-//   "GL_OES_single_precision "              // OK
-//   "GL_OES_read_format "                   // OK
-//   "GL_OES_compressed_paletted_texture "   // OK
-//   "GL_OES_draw_texture "                  // OK
-//   "GL_OES_matrix_get "                    // OK
-//   "GL_OES_query_matrix "                  // OK
-//   //        "GL_OES_point_size_array "              // TODO
-//   //        "GL_OES_point_sprite "                  // TODO
-//   "GL_OES_EGL_image "                     // OK
-//#ifdef GL_OES_compressed_ETC1_RGB8_texture
-//   "GL_OES_compressed_ETC1_RGB8_texture "  // OK
-//#endif
-//   "GL_ARB_texture_compression "           // OK
-//   "GL_ARB_texture_non_power_of_two "      // OK
-//   "GL_ANDROID_user_clip_plane "           // OK
-//   "GL_ANDROID_vertex_buffer_object "      // OK
-//   "GL_ANDROID_generate_mipmap "           // OK
-   ""
-   ;
-
-void glGetIntegerv(GLenum pname, GLint* params)
-{
-   switch (pname) {
-   case GL_MAX_TEXTURE_SIZE :
-      *params = 4096; // limit is in precision of texcoord calculation, which uses 16.16
-      break;
-   case GL_MAX_VERTEX_ATTRIBS:
-      *params = GGL_MAXVERTEXATTRIBS;
-      break;
-   case GL_MAX_VERTEX_UNIFORM_VECTORS:
-      *params = GGL_MAXVERTEXUNIFORMVECTORS;
-      break;
-   case GL_MAX_VARYING_VECTORS:
-      *params = GGL_MAXVARYINGVECTORS;
-      break;
-   case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXCOMBINEDTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXVERTEXTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
-      *params = GGL_MAXFRAGMENTUNIFORMVECTORS;
-      break;
-   case GL_ALIASED_LINE_WIDTH_RANGE:
-      *params = 1; // TODO: not implemented
-      break;
-   default:
-      LOGD("agl2: glGetIntegerv 0x%.4X", pname);
-      assert(0);
-   }
-}
-
-const GLubyte* glGetString(GLenum name)
-{
-   switch (name) {
-   case GL_VENDOR:
-      return (const GLubyte*)gVendorString;
-   case GL_RENDERER:
-      return (const GLubyte*)gRendererString;
-   case GL_VERSION:
-      return (const GLubyte*)gVersionString;
-   case GL_EXTENSIONS:
-      return (const GLubyte*)gExtensionsString;
-   }
-   assert(0); //(c, GL_INVALID_ENUM);
-   return 0;
-}
diff --git a/opengl/libagl2/src/gles2context.h b/opengl/libagl2/src/gles2context.h
deleted file mode 100644
index cec0340..0000000
--- a/opengl/libagl2/src/gles2context.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <utils/threads.h>
-#include <pthread.h>
-
-#include <cutils/log.h>
-
-#include <assert.h>
-
-#ifdef __arm__
-#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) { do { if (!(EXPR)) {LOGD("\n*\n*\n*\n* assert fail: '"#EXPR"' at "__location__"\n*\n*\n*\n*"); exit(EXIT_FAILURE); } } while (false); }
-//#define printf LOGD
-#else // #ifdef __arm__
-//#define LOGD printf
-#endif // #ifdef __arm__
-
-
-#include <pixelflinger2/pixelflinger2_format.h>
-#include <pixelflinger2/pixelflinger2.h>
-
-#include <map>
-
-typedef uint8_t                 GGLubyte;               // ub
-
-#define ggl_likely(x)   __builtin_expect(!!(x), 1)
-#define ggl_unlikely(x) __builtin_expect(!!(x), 0)
-
-#undef NELEM
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-
-template<typename T>
-inline T max(T a, T b)
-{
-   return a<b ? b : a;
-}
-
-template<typename T>
-inline T min(T a, T b)
-{
-   return a<b ? a : b;
-}
-
-struct egl_context_t {
-   enum {
-      IS_CURRENT      =   0x00010000,
-      NEVER_CURRENT   =   0x00020000
-   };
-   uint32_t            flags;
-   EGLDisplay          dpy;
-   EGLConfig           config;
-   EGLSurface          read;
-   EGLSurface          draw;
-
-   unsigned frame;
-   clock_t lastSwapTime;
-   float accumulateSeconds;
-   
-   static inline egl_context_t* context(EGLContext ctx);
-};
-
-struct GLES2Context;
-
-#ifdef HAVE_ANDROID_OS
-#include <bionic_tls.h>
-// We have a dedicated TLS slot in bionic
-inline void setGlThreadSpecific(GLES2Context *value)
-{
-   ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
-}
-inline GLES2Context* getGlThreadSpecific()
-{
-   return (GLES2Context *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
-}
-#else
-extern pthread_key_t gGLKey;
-inline void setGlThreadSpecific(GLES2Context *value)
-{
-   pthread_setspecific(gGLKey, value);
-}
-inline GLES2Context* getGlThreadSpecific()
-{
-   return static_cast<GLES2Context*>(pthread_getspecific(gGLKey));
-}
-#endif
-
-struct VBO {
-   unsigned size;
-   GLenum usage;
-   void * data;
-};
-
-struct GLES2Context {
-   GGLContext rasterizer;
-   egl_context_t egl;
-   GGLInterface * iface; // shortcut to &rasterizer.interface
-
-   struct VertexState {
-      struct VertAttribPointer {
-         unsigned size; // number of values per vertex
-         GLenum type;  // data type
-         unsigned stride; // bytes
-         const void * ptr;
-bool normalized :
-         1;
-bool enabled :
-         1;
-      } attribs [GGL_MAXVERTEXATTRIBS];
-
-      VBO * vbo, * indices;
-      std::map<GLuint, VBO *> vbos;
-      GLuint free;
-
-      Vector4 defaultAttribs [GGL_MAXVERTEXATTRIBS];
-   } vert;
-
-   struct TextureState {
-      GGLTexture * tmus[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS];
-      int sampler2tmu[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; // sampler2tmu[sampler] is index of tmu, -1 means not used
-      unsigned active;
-      std::map<GLuint, GGLTexture *> textures;
-      GLuint free; // first possible free name
-      GGLTexture * tex2D, * texCube; // default textures
-      unsigned unpack;
-      
-      void UpdateSampler(GGLInterface * iface, unsigned tmu);
-   } tex;
-
-   GLES2Context();
-   void InitializeTextures();
-   void InitializeVertices();
-
-   ~GLES2Context();
-   void UninitializeTextures();
-   void UninitializeVertices();
-
-   static inline GLES2Context* get() {
-      return getGlThreadSpecific();
-   }
-};
-
-inline egl_context_t* egl_context_t::context(EGLContext ctx)
-{
-   GLES2Context* const gl = static_cast<GLES2Context*>(ctx);
-   return static_cast<egl_context_t*>(&gl->egl);
-}
-
-#define GLES2_GET_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
-                                 /*puts(__FUNCTION__);*/
-#define GLES2_GET_CONST_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
-                                       /*puts(__FUNCTION__);*/
diff --git a/opengl/libagl2/src/shader.cpp b/opengl/libagl2/src/shader.cpp
deleted file mode 100644
index 076e388..0000000
--- a/opengl/libagl2/src/shader.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...)
-
-static inline GLuint s2n(gl_shader * s)
-{
-   return (GLuint)s ^ 0xaf3c532d;
-}
-
-static inline gl_shader * n2s(GLuint n)
-{
-   return (gl_shader *)(n ^ 0xaf3c532d);
-}
-
-static inline GLuint p2n(gl_shader_program * p)
-{
-   return (GLuint)p ^ 0x04dc18f9;
-}
-
-static inline gl_shader_program * n2p(GLuint n)
-{
-   return (gl_shader_program *)(n ^ 0x04dc18f9);
-}
-
-void glAttachShader(GLuint program, GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderAttach(ctx->iface, n2p(program), n2s(shader));
-}
-
-void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderAttributeBind(n2p(program), index, name);
-//   assert(0);
-}
-
-GLuint glCreateShader(GLenum type)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return s2n(ctx->iface->ShaderCreate(ctx->iface, type));
-}
-
-GLuint glCreateProgram(void)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return  p2n(ctx->iface->ShaderProgramCreate(ctx->iface));
-}
-
-void glCompileShader(GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderCompile(ctx->iface, n2s(shader), NULL, NULL);
-}
-
-void glDeleteProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramDelete(ctx->iface, n2p(program));
-}
-
-void glDeleteShader(GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderDelete(ctx->iface, n2s(shader));
-}
-
-void glDetachShader(GLuint program, GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderDetach(ctx->iface, n2p(program), n2s(shader));
-}
-
-GLint glGetAttribLocation(GLuint program, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   GLint location = ctx->iface->ShaderAttributeLocation(n2p(program), name);
-//   LOGD("\n*\n*\n* agl2: glGetAttribLocation program=%u name=%s location=%d \n*\n*",
-//        program, name, location);
-   return location;
-}
-
-void glGetProgramiv(GLuint program, GLenum pname, GLint* params)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramGetiv(n2p(program), pname, params);
-   LOGD("agl2: glGetProgramiv 0x%.4X=%d \n", pname, *params);
-}
-
-void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramGetInfoLog(n2p(program), bufsize, length, infolog);
-}
-
-void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderGetiv(n2s(shader), pname, params);
-   LOGD("agl2: glGetShaderiv 0x%.4X=%d \n", pname, *params);
-}
-
-void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderGetInfoLog(n2s(shader), bufsize, length, infolog);
-}
-
-int glGetUniformLocation(GLuint program, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return ctx->iface->ShaderUniformLocation(n2p(program), name);
-}
-
-void glLinkProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   GLboolean linked = ctx->iface->ShaderProgramLink(n2p(program), NULL);
-   assert(linked);
-}
-
-void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderSource(n2s(shader), count, string, length);
-}
-
-void glUniform1f(GLint location, GLfloat x)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, &x, GL_FLOAT);
-   assert(0 > sampler); // should be assigning to sampler
-}
-
-void glUniform1i(GLint location, GLint x)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[1] = {x};
-   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_INT);
-   if (0 <= sampler) {
-//      LOGD("\n*\n* agl2: glUniform1i updated sampler=%d tmu=%d location=%d\n*", sampler, x, location);
-      assert(0 <= x && GGL_MAXCOMBINEDTEXTUREIMAGEUNITS > x);
-//      LOGD("tmu%u: format=0x%.2X w=%u h=%u levels=%p", x, ctx->tex.tmus[x]->format, 
-//         ctx->tex.tmus[x]->width, ctx->tex.tmus[x]->height, ctx->tex.tmus[x]->format);
-      ctx->tex.sampler2tmu[sampler] = x;
-      ctx->tex.UpdateSampler(ctx->iface, x);
-   }
-}
-
-void glUniform2f(GLint location, GLfloat x, GLfloat y)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[4] = {x, y};
-   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC2);
-}
-
-void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[4] = {x, y, z, w};
-//   LOGD("agl2: glUniform4f location=%d %f,%f,%f,%f", location, x, y, z, w);
-   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC4);
-}
-
-void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   const gl_shader_program * program = ctx->rasterizer.CurrentProgram;
-//   if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, ").a;")) {
-//   LOGD("agl2: glUniformMatrix4fv location=%d count=%d transpose=%d", location, count, transpose);
-//   for (unsigned i = 0; i < 4; i++)
-//      LOGD("agl2: glUniformMatrix4fv %.2f \t %.2f \t %.2f \t %.2f", value[i * 4 + 0],
-//           value[i * 4 + 1], value[i * 4 + 2], value[i * 4 + 3]);
-//   }
-   ctx->iface->ShaderUniformMatrix(ctx->rasterizer.CurrentProgram, 4, 4, location, count, transpose, value);
-//   while (true)
-//      ;
-//   assert(0);
-}
-
-void glUseProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("\n*\n*\n* agl2: glUseProgram %d \n*\n*\n*", program);
-   ctx->iface->ShaderUse(ctx->iface, n2p(program));
-   ctx->iface->ShaderUniformGetSamplers(n2p(program), ctx->tex.sampler2tmu);
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-      if (0 <= ctx->tex.sampler2tmu[i])
-         ctx->iface->SetSampler(ctx->iface, i, ctx->tex.tmus[ctx->tex.sampler2tmu[i]]);
-}
diff --git a/opengl/libagl2/src/state.cpp b/opengl/libagl2/src/state.cpp
deleted file mode 100644
index 22e73fa..0000000
--- a/opengl/libagl2/src/state.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "gles2context.h"
-
-GLES2Context::GLES2Context()
-{
-   memset(this, 0, sizeof *this);
-
-   assert((void *)&rasterizer == &rasterizer.interface);
-   InitializeGGLState(&rasterizer.interface);
-   iface = &rasterizer.interface;
-   printf("gl->rasterizer.PickScanLine(%p) = %p \n", &rasterizer.PickScanLine, rasterizer.PickScanLine);
-   assert(rasterizer.PickRaster);
-   assert(rasterizer.PickScanLine);
-
-   InitializeTextures();
-   InitializeVertices();
-}
-
-GLES2Context::~GLES2Context()
-{
-   UninitializeTextures();
-   UninitializeVertices();
-   UninitializeGGLState(&rasterizer.interface);
-}
-
-void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendColor(ctx->iface, red, green, blue, alpha);
-}
-
-void glBlendEquation( GLenum mode )
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendEquationSeparate(ctx->iface, mode, mode);
-}
-
-void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendEquationSeparate(ctx->iface, modeRGB, modeAlpha);
-}
-
-void glBlendFunc(GLenum sfactor, GLenum dfactor)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendFuncSeparate(ctx->iface, sfactor, dfactor, sfactor, dfactor);
-}
-
-void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendFuncSeparate(ctx->iface, srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-
-void glClear(GLbitfield mask)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->Clear(ctx->iface, mask);
-}
-
-void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearColor(ctx->iface, red, green, blue, alpha);
-}
-
-void glClearDepthf(GLclampf depth)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearDepthf(ctx->iface, depth);
-}
-
-void glClearStencil(GLint s)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearStencil(ctx->iface, s);
-}
-
-void glCullFace(GLenum mode)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->CullFace(ctx->iface, mode);
-}
-
-void glDisable(GLenum cap)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->EnableDisable(ctx->iface, cap, false);
-}
-
-void glEnable(GLenum cap)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->EnableDisable(ctx->iface, cap, true);
-}
-
-void glFinish(void)
-{
-   // do nothing
-}
-
-void glFrontFace(GLenum mode)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->FrontFace(ctx->iface, mode);
-}
-
-void glFlush(void)
-{
-   // do nothing
-}
-
-void glHint(GLenum target, GLenum mode)
-{
-   // do nothing
-}
-
-void glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-//   LOGD("agl2: glScissor not implemented x=%d y=%d width=%d height=%d", x, y, width, height);
-   //CALL_GL_API(glScissor, x, y, width, height);
-}
-
-void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glViewport x=%d y=%d width=%d height=%d", x, y, width, height);
-   ctx->iface->Viewport(ctx->iface, x, y, width, height);
-}
diff --git a/opengl/libagl2/src/texture.cpp b/opengl/libagl2/src/texture.cpp
deleted file mode 100644
index 4de1f16..0000000
--- a/opengl/libagl2/src/texture.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...) 
-
-#define API_ENTRY
-#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
-#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
-
-static inline GGLTexture * AllocTexture()
-{
-   GGLTexture * tex = (GGLTexture *)calloc(1, sizeof(GGLTexture));
-   tex->minFilter = GGLTexture::GGL_LINEAR; // should be NEAREST_ MIPMAP_LINEAR
-   tex->magFilter = GGLTexture::GGL_LINEAR;
-   return tex;
-}
-
-void GLES2Context::InitializeTextures()
-{
-   tex.textures = std::map<GLuint, GGLTexture *>(); // the entire struct has been zeroed in constructor
-   tex.tex2D = AllocTexture();
-   tex.textures[GL_TEXTURE_2D] = tex.tex2D;
-   tex.texCube = AllocTexture();
-   tex.textures[GL_TEXTURE_CUBE_MAP] = tex.texCube;
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) {
-      tex.tmus[i] = NULL;
-      tex.sampler2tmu[i] = NULL;
-   }
-
-   tex.active = 0;
-
-   tex.free = max(GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP) + 1;
-
-   tex.tex2D->format = GGL_PIXEL_FORMAT_RGBA_8888;
-   tex.tex2D->type = GL_TEXTURE_2D;
-   tex.tex2D->levelCount = 1;
-   tex.tex2D->wrapS = tex.tex2D->wrapT = GGLTexture::GGL_REPEAT;
-   tex.tex2D->minFilter = tex.tex2D->magFilter = GGLTexture::GGL_NEAREST;
-   tex.tex2D->width = tex.tex2D->height = 1;
-   tex.tex2D->levels = malloc(4);
-   *(unsigned *)tex.tex2D->levels = 0xff000000;
-
-
-   tex.texCube->format = GGL_PIXEL_FORMAT_RGBA_8888;
-   tex.texCube->type = GL_TEXTURE_CUBE_MAP;
-   tex.texCube->levelCount = 1;
-   tex.texCube->wrapS = tex.texCube->wrapT = GGLTexture::GGL_REPEAT;
-   tex.texCube->minFilter = tex.texCube->magFilter = GGLTexture::GGL_NEAREST;
-   tex.texCube->width = tex.texCube->height = 1;
-   tex.texCube->levels = malloc(4 * 6);
-   static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
-                                 0xff00ffff, 0xffffff00, 0xffff00ff
-                                };
-   memcpy(tex.texCube->levels, texels, sizeof texels);
-
-   //texture.levelCount = GenerateMipmaps(texture.levels, texture.width, texture.height);
-
-   //    static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
-   //    0xff00ffff, 0xffffff00, 0xffff00ff};
-   //    memcpy(texture.levels[0], texels, sizeof texels);
-   //    texture.format = GGL_PIXEL_FORMAT_RGBA_8888;
-   //    texture.width = texture.height = 1;
-   //texture.height /= 6;
-   //texture.type = GL_TEXTURE_CUBE_MAP;
-   
-   tex.unpack = 4;
-}
-
-void GLES2Context::TextureState::UpdateSampler(GGLInterface * iface, unsigned tmu)
-{
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-      if (tmu == sampler2tmu[i])
-         iface->SetSampler(iface, i, tmus[tmu]);
-}
-
-void GLES2Context::UninitializeTextures()
-{
-   for (std::map<GLuint, GGLTexture *>::iterator it = tex.textures.begin(); it != tex.textures.end(); it++) {
-      if (!it->second)
-         continue;
-      free(it->second->levels);
-      free(it->second);
-   }
-}
-
-static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned * bytesPerPixel,
-      GGLPixelFormat * texFormat)
-{
-   switch (format) {
-   case GL_ALPHA:
-      *texFormat = GGL_PIXEL_FORMAT_A_8;
-      *bytesPerPixel = 1;
-      break;
-   case GL_LUMINANCE:
-      *texFormat = GGL_PIXEL_FORMAT_L_8;
-      *bytesPerPixel = 1;
-      break;
-   case GL_LUMINANCE_ALPHA:
-      *texFormat = GGL_PIXEL_FORMAT_LA_88;
-      *bytesPerPixel = 2;
-      break;
-   case GL_RGB:
-      *texFormat = GGL_PIXEL_FORMAT_RGB_888;
-      *bytesPerPixel = 3;
-      break;
-   case GL_RGBA:
-      *texFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-      *bytesPerPixel = 4;
-      break;
-
-      // internal formats to avoid conversion
-   case GL_UNSIGNED_SHORT_5_6_5:
-      *texFormat = GGL_PIXEL_FORMAT_RGB_565;
-      *bytesPerPixel = 2;
-      break;
-
-   default:
-      assert(0);
-      return;
-   }
-}
-
-static inline void CopyTexture(char * dst, const char * src, const unsigned bytesPerPixel,
-                               const unsigned sx, const unsigned sy,  const unsigned sw,
-                               const unsigned dx, const unsigned dy, const unsigned dw,
-                               const unsigned w, const unsigned h)
-{
-   const unsigned bpp = bytesPerPixel;
-   if (dw == sw && dw == w && sx == 0 && dx == 0)
-      memcpy(dst + dy * dw * bpp, src + sy * sw * bpp, w * h * bpp);
-   else
-      for (unsigned y = 0; y < h; y++)
-         memcpy(dst + ((dy + y) * dw + dx) * bpp, src + ((sy + y) * sw + sx) * bpp, w * bpp); 
-}
-
-void glActiveTexture(GLenum texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   unsigned index = texture - GL_TEXTURE0;
-   assert(NELEM(ctx->tex.tmus) > index);
-//   LOGD("agl2: glActiveTexture %u", index);
-   ctx->tex.active = index;
-}
-
-void glBindTexture(GLenum target, GLuint texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glBindTexture target=0x%.4X texture=%u active=%u", target, texture, ctx->tex.active);
-   std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(texture);
-   GGLTexture * tex = NULL;
-   if (it != ctx->tex.textures.end()) {
-      tex = it->second;
-      if (!tex) {
-         tex = AllocTexture();
-         tex->type = target;
-         it->second = tex;
-//         LOGD("agl2: glBindTexture allocTexture");
-      }
-//      else
-//         LOGD("agl2: glBindTexture bind existing texture");
-      assert(target == tex->type);
-   } else if (0 == texture) {
-      if (GL_TEXTURE_2D == target)
-      {
-         tex = ctx->tex.tex2D;
-//         LOGD("agl2: glBindTexture bind default tex2D");
-      }
-      else if (GL_TEXTURE_CUBE_MAP == target)
-      {
-         tex = ctx->tex.texCube;
-//         LOGD("agl2: glBindTexture bind default texCube");
-      }
-      else
-         assert(0);
-   } else {
-      if (texture <= ctx->tex.free)
-         ctx->tex.free = texture + 1;
-      tex = AllocTexture();
-      tex->type = target;
-      ctx->tex.textures[texture] = tex;
-//      LOGD("agl2: glBindTexture new texture=%u", texture);
-   }
-   ctx->tex.tmus[ctx->tex.active] = tex;
-//   LOGD("agl2: glBindTexture format=0x%.2X w=%u h=%u levels=%p", tex->format,
-//      tex->width, tex->height, tex->levels);
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-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 glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
-                      GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glCopyTexImage2D target=0x%.4X internalformat=0x%.4X", target, internalformat);
-//   LOGD("x=%d y=%d width=%d height=%d border=%d level=%d ", x, y, width, height, border, level);
-   assert(0 == border);
-   assert(0 == level);
-   unsigned bytesPerPixel = 0;
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   GetFormatAndBytesPerPixel(internalformat, &bytesPerPixel, &texFormat);
-
-   assert(texFormat == ctx->rasterizer.frameSurface.format);
-//   LOGD("texFormat=0x%.2X bytesPerPixel=%d \n", texFormat, bytesPerPixel);
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   assert(y + height <= ctx->rasterizer.frameSurface.height);
-   assert(x + width <= ctx->rasterizer.frameSurface.width);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   tex.width = width;
-   tex.height = height;
-   tex.levelCount = 1;
-   tex.format = texFormat;
-   switch (target) {
-   case GL_TEXTURE_2D:
-      tex.levels = realloc(tex.levels, totalSize);
-      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
-                  x, y, ctx->rasterizer.frameSurface.width, 0, 0, width, width, height);
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
-   // x, y are src offset
-   // xoffset and yoffset are dst offset
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glCopyTexSubImage2D target=0x%.4X level=%d", target, level);
-//   LOGD("xoffset=%d yoffset=%d x=%d y=%d width=%d height=%d", xoffset, yoffset, x, y, width, height);
-   assert(0 == level);
-
-   unsigned bytesPerPixel = 4;
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-
-   assert(tex.format == ctx->rasterizer.frameSurface.format);
-   assert(GGL_PIXEL_FORMAT_RGBA_8888 == tex.format);
-
-   const unsigned srcWidth = ctx->rasterizer.frameSurface.width;
-   const unsigned srcHeight = ctx->rasterizer.frameSurface.height;
-
-   assert(x >= 0 && y >= 0);
-   assert(xoffset >= 0 && yoffset >= 0);
-   assert(x + width <= srcWidth);
-   assert(y + height <= srcHeight);
-   assert(xoffset + width <= tex.width);
-   assert(yoffset + height <= tex.height);
-
-   switch (target) {
-   case GL_TEXTURE_2D:
-      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
-                  x, y, srcWidth, xoffset, yoffset, tex.width, width, height);
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glDeleteTextures(GLsizei n, const GLuint* textures)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(textures[i]);
-      if (it == ctx->tex.textures.end())
-         continue;
-      ctx->tex.free = min(ctx->tex.free, textures[i]);
-      for (unsigned i = 0; i <  GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-         if (ctx->tex.tmus[i] == it->second) {
-            if (GL_TEXTURE_2D == it->second->type)
-               ctx->tex.tmus[i] = ctx->tex.tex2D;
-            else if (GL_TEXTURE_CUBE_MAP == it->second->type)
-               ctx->tex.tmus[i] = ctx->tex.texCube;
-            else
-               assert(0);
-            ctx->tex.UpdateSampler(ctx->iface, i);
-         }
-      if (it->second) {
-         free(it->second->levels);
-         free(it->second);
-      }
-      ctx->tex.textures.erase(it);
-   }
-}
-
-void glGenTextures(GLsizei n, GLuint* textures)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      textures[i] = 0;
-      for (ctx->tex.free; ctx->tex.free < 0xffffffffu; ctx->tex.free++)
-         if (ctx->tex.textures.find(ctx->tex.free) == ctx->tex.textures.end()) {
-            ctx->tex.textures[ctx->tex.free] = NULL;
-            textures[i] = ctx->tex.free;
-            ctx->tex.free++;
-            break;
-         }
-      assert(textures[i]);
-   }
-}
-
-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);
-}
-
-GLboolean glIsTexture(GLuint texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (ctx->tex.textures.find(texture) == ctx->tex.textures.end())
-      return GL_FALSE;
-   else
-      return GL_TRUE;
-}
-
-void glPixelStorei(GLenum pname, GLint param)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GL_UNPACK_ALIGNMENT == pname);
-   assert(1 == param || 2 == param || 4 == param || 8 == param);
-//   LOGD("\n*\n* agl2: glPixelStorei not implemented pname=0x%.4X param=%d \n*", pname, param);
-   ctx->tex.unpack = param;
-//   CALL_GL_API(glPixelStorei, pname, param);
-}
-void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
-                  GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glTexImage2D internalformat=0x%.4X format=0x%.4X type=0x%.4X \n", internalformat, format, type);
-//   LOGD("width=%d height=%d border=%d level=%d pixels=%p \n", width, height, border, level, pixels);
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-      break;
-   case GL_UNSIGNED_SHORT_5_6_5:
-      internalformat = format = GL_UNSIGNED_SHORT_5_6_5;
-      assert(4 == ctx->tex.unpack);
-      break;
-   default:
-      assert(0);
-   }
-   assert(internalformat == format);
-   assert(0 == border);
-   if (0 != level) {
-      LOGD("agl2: glTexImage2D level=%d", level);
-      return;
-   }
-   unsigned bytesPerPixel = 0;
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
-
-   assert(texFormat && bytesPerPixel);
-//   LOGD("texFormat=0x%.2X bytesPerPixel=%d active=%u", texFormat, bytesPerPixel, ctx->tex.active);
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   tex.width = width;
-   tex.height = height;
-   tex.levelCount = 1;
-   tex.format = texFormat;
-
-   switch (target) {
-   case GL_TEXTURE_2D:
-      assert(GL_TEXTURE_2D == ctx->tex.tmus[ctx->tex.active]->type);
-      offset = 0;
-      break;
-      break;
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-      assert(GL_TEXTURE_CUBE_MAP == ctx->tex.tmus[ctx->tex.active]->type);
-      assert(width == height);
-      offset = (target - GL_TEXTURE_CUBE_MAP_POSITIVE_X) * size;
-      totalSize = 6 * size;
-      break;
-   default:
-      assert(0);
-      return;
-   }
-
-   tex.levels = realloc(tex.levels, totalSize);
-   if (pixels)
-      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, 0, 0, width, width, height);
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
-{
-//   LOGD("agl2: glTexParameterf target=0x%.4X pname=0x%.4X param=%f", target, pname, param);
-   glTexParameteri(target, pname, param);
-}
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params)
-{
-   CALL_GL_API(glTexParameterfv, target, pname, params);
-}
-void glTexParameteri(GLenum target, GLenum pname, GLint param)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("alg2: glTexParameteri target=0x%.0X pname=0x%.4X param=0x%.4X",
-//        target, pname, param);
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   switch (pname) {
-   case GL_TEXTURE_WRAP_S:
-   case GL_TEXTURE_WRAP_T:
-      GGLTexture::GGLTextureWrap wrap;
-      switch (param) {
-      case GL_REPEAT:
-         wrap = GGLTexture::GGL_REPEAT;
-         break;
-      case GL_CLAMP_TO_EDGE:
-         wrap = GGLTexture::GGL_CLAMP_TO_EDGE;
-         break;
-      case GL_MIRRORED_REPEAT:
-         wrap = GGLTexture::GGL_MIRRORED_REPEAT;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      if (GL_TEXTURE_WRAP_S == pname)
-         tex.wrapS = wrap;
-      else
-         tex.wrapT = wrap;
-      break;
-   case GL_TEXTURE_MIN_FILTER:
-      switch (param) {
-      case GL_NEAREST:
-         tex.minFilter = GGLTexture::GGL_NEAREST;
-         break;
-      case GL_LINEAR:
-         tex.minFilter = GGLTexture::GGL_LINEAR;
-         break;
-      case GL_NEAREST_MIPMAP_NEAREST:
-//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_NEAREST;
-         break;
-      case GL_NEAREST_MIPMAP_LINEAR:
-//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_LINEAR;
-         break;
-      case GL_LINEAR_MIPMAP_NEAREST:
-//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_NEAREST;
-         break;
-      case GL_LINEAR_MIPMAP_LINEAR:
-//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_LINEAR;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      break;
-   case GL_TEXTURE_MAG_FILTER:
-      switch (param) {
-      case GL_NEAREST:
-         tex.minFilter = GGLTexture::GGL_NEAREST;
-         break;
-      case GL_LINEAR:
-         tex.minFilter = GGLTexture::GGL_LINEAR;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   // implementation restriction
-   if (tex.magFilter != tex.minFilter)
-      tex.magFilter = tex.minFilter = GGLTexture::GGL_LINEAR;
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params)
-{
-   CALL_GL_API(glTexParameteriv, target, pname, params);
-}
-void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glTexSubImage2D target=0x%.4X level=%d xoffset=%d yoffset=%d width=%d height=%d format=0x%.4X type=0x%.4X pixels=%p",
-//        target, level, xoffset, yoffset, width, height, format, type, pixels);
-   assert(0 == level);
-   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-      break;
-   case GL_UNSIGNED_SHORT_5_6_5:
-      format = GL_UNSIGNED_SHORT_5_6_5;
-      assert(4 == ctx->tex.unpack);
-      break;
-   default:
-      assert(0);
-   }
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   unsigned bytesPerPixel = 0;
-   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
-   assert(texFormat == tex.format);
-   assert(GL_UNSIGNED_BYTE == type);
-   switch (target) {
-   case GL_TEXTURE_2D:
-      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, xoffset,
-                  yoffset, tex.width, width, height);
-      break;
-   default:
-      assert(0);
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
diff --git a/opengl/libagl2/src/vertex.cpp b/opengl/libagl2/src/vertex.cpp
deleted file mode 100644
index 021b82b..0000000
--- a/opengl/libagl2/src/vertex.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...)
-
-void GLES2Context::InitializeVertices()
-{
-   vert.vbos = std::map<GLuint, VBO *>(); // the entire struct has been zeroed in constructor
-   vert.free = 1;
-   vert.vbo = NULL;
-   vert.indices = NULL;
-   for (unsigned i = 0; i < GGL_MAXVERTEXATTRIBS; i++)
-      vert.defaultAttribs[i] = Vector4(0,0,0,1);
-}
-
-void GLES2Context::UninitializeVertices()
-{
-   for (std::map<GLuint, VBO *>::iterator it = vert.vbos.begin(); it != vert.vbos.end(); it++) {
-      if (!it->second)
-         continue;
-      free(it->second->data);
-      free(it->second);
-   }
-}
-
-static inline void FetchElement(const GLES2Context * ctx, const unsigned index,
-                                const unsigned maxAttrib, VertexInput * elem)
-{
-   for (unsigned i = 0; i < maxAttrib; i++) {
-      {
-         unsigned size = 0;
-         if (ctx->vert.attribs[i].enabled) {
-            const char * ptr = (const char *)ctx->vert.attribs[i].ptr;
-            ptr += ctx->vert.attribs[i].stride * index;
-            memcpy(elem->attributes + i, ptr, ctx->vert.attribs[i].size * sizeof(float));
-            size = ctx->vert.attribs[i].size;
-//            LOGD("agl2: FetchElement %d attribs size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
-//                 elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
-         } else {
-//            LOGD("agl2: FetchElement %d default %.2f,%.2f,%.2f,%.2f", i, ctx->vert.defaultAttribs[i].x,
-//                 ctx->vert.defaultAttribs[i].y, ctx->vert.defaultAttribs[i].z, ctx->vert.defaultAttribs[i].w);
-         }
-
-         switch (size) {
-         case 0: // fall through
-            elem->attributes[i].x = ctx->vert.defaultAttribs[i].x;
-         case 1: // fall through
-            elem->attributes[i].y = ctx->vert.defaultAttribs[i].y;
-         case 2: // fall through
-            elem->attributes[i].z = ctx->vert.defaultAttribs[i].z;
-         case 3: // fall through
-            elem->attributes[i].w = ctx->vert.defaultAttribs[i].w;
-         case 4:
-            break;
-         default:
-            assert(0);
-            break;
-         }
-//         LOGD("agl2: FetchElement %d size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
-//              elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
-      }
-   }
-}
-
-template<typename IndexT> static void DrawElementsTriangles(const GLES2Context * ctx,
-      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   if (ctx->vert.indices)
-      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
-   for (unsigned i = 0; i < count; i += 3) {
-      for (unsigned j = 0; j < 3; j++)
-         FetchElement(ctx, indices[i + j], maxAttrib, v + j);
-      ctx->iface->DrawTriangle(ctx->iface, v, v + 1, v + 2);
-   }
-}
-
-static void DrawArraysTriangles(const GLES2Context * ctx, const unsigned first,
-                                const unsigned count, const unsigned maxAttrib)
-{
-//   LOGD("agl: DrawArraysTriangles=%p", DrawArraysTriangles);
-   VertexInput v[3];
-   for (unsigned i = 2; i < count; i+=3) {
-      // TODO: fix order
-      FetchElement(ctx, first + i - 2, maxAttrib, v + 0);
-      FetchElement(ctx, first + i - 1, maxAttrib, v + 1);
-      FetchElement(ctx, first + i - 0, maxAttrib, v + 2);
-      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
-   }
-//   LOGD("agl: DrawArraysTriangles end");
-}
-
-template<typename IndexT> static void DrawElementsTriangleStrip(const GLES2Context * ctx,
-      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   if (ctx->vert.indices)
-      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
-      
-//   LOGD("agl2: DrawElementsTriangleStrip");
-//   for (unsigned i = 0; i < count; i++)
-//      LOGD("indices[%d] = %d", i, indices[i]);
-
-   FetchElement(ctx, indices[0], maxAttrib, v + 0);
-   FetchElement(ctx, indices[1], maxAttrib, v + 1);
-   for (unsigned i = 2; i < count; i ++) {
-      FetchElement(ctx, indices[i], maxAttrib, v + i % 3);
-      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
-   }
-
-//   for (unsigned i = 2; i < count; i++) {
-//      FetchElement(ctx, indices[i - 2], maxAttrib, v + 0);
-//      FetchElement(ctx, indices[i - 1], maxAttrib, v + 1);
-//      FetchElement(ctx, indices[i - 0], maxAttrib, v + 2);
-//      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
-//   }
-}
-
-static void DrawArraysTriangleStrip(const GLES2Context * ctx, const unsigned first,
-                                    const unsigned count, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   FetchElement(ctx, first, maxAttrib, v + 0);
-   FetchElement(ctx, first + 1, maxAttrib, v + 1);
-   for (unsigned i = 2; i < count; i++) {
-      // TODO: fix order
-      FetchElement(ctx, first + i, maxAttrib, v + i % 3);
-      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
-   }
-}
-
-void glBindBuffer(GLenum target, GLuint buffer)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   VBO * vbo = NULL;
-   if (0 != buffer) {
-      std::map<GLuint, VBO *>::iterator it = ctx->vert.vbos.find(buffer);
-      if (it != ctx->vert.vbos.end()) {
-         vbo = it->second;
-         if (!vbo)
-            vbo = (VBO *)calloc(1, sizeof(VBO));
-         it->second = vbo;
-      } else
-         assert(0);
-   }
-   if (GL_ARRAY_BUFFER == target)
-      ctx->vert.vbo = vbo;
-   else if (GL_ELEMENT_ARRAY_BUFFER == target)
-      ctx->vert.indices = vbo;
-   else
-      assert(0);
-   assert(vbo || buffer == 0);
-//   LOGD("\n*\n glBindBuffer 0x%.4X=%d ", target, buffer);
-}
-
-void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (GL_ARRAY_BUFFER == target) {
-      assert(ctx->vert.vbo);
-      ctx->vert.vbo->data = realloc(ctx->vert.vbo->data, size);
-      ctx->vert.vbo->size = size;
-      ctx->vert.vbo->usage = usage;
-      if (data)
-         memcpy(ctx->vert.vbo->data, data, size);
-   } else if (GL_ELEMENT_ARRAY_BUFFER == target) {
-      assert(ctx->vert.indices);
-      ctx->vert.indices->data = realloc(ctx->vert.indices->data, size);
-      ctx->vert.indices->size = size;
-      ctx->vert.indices->usage = usage;
-      if (data)
-         memcpy(ctx->vert.indices->data, data, size);
-   } else
-      assert(0);
-//   LOGD("\n*\n glBufferData target=0x%.4X size=%u data=%p usage=0x%.4X \n",
-//        target, size, data, usage);
-}
-
-void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (GL_ARRAY_BUFFER == target)
-   {
-      assert(ctx->vert.vbo);
-      assert(0 <= offset);
-      assert(0 <= size);
-      assert(offset + size <= ctx->vert.vbo->size);
-      memcpy((char *)ctx->vert.vbo->data + offset, data, size);
-   }
-   else
-      assert(0);
-}
-
-void glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      std::map<GLuint, VBO*>::iterator it = ctx->vert.vbos.find(buffers[i]);
-      if (it == ctx->vert.vbos.end())
-         continue;
-      ctx->vert.free = min(ctx->vert.free, buffers[i]);
-      if (it->second == ctx->vert.vbo)
-         ctx->vert.vbo = NULL;
-      else if (it->second == ctx->vert.indices)
-         ctx->vert.indices = NULL;
-      if (it->second) {
-         free(it->second->data);
-         free(it->second);
-      }
-   }
-}
-
-void glDisableVertexAttribArray(GLuint index)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GGL_MAXVERTEXATTRIBS > index);
-   ctx->vert.attribs[index].enabled = false;
-}
-
-void glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glDrawArrays=%p", glDrawArrays);
-   assert(ctx->rasterizer.CurrentProgram);
-   assert(0 <= first);
-   int maxAttrib = -1;
-   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
-   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
-   switch (mode) {
-   case GL_TRIANGLE_STRIP:
-      DrawArraysTriangleStrip(ctx, first, count, maxAttrib);
-      break;
-   case GL_TRIANGLES:
-      DrawArraysTriangles(ctx, first, count, maxAttrib);
-      break;
-   default:
-      LOGE("agl2: glDrawArrays unsupported mode: 0x%.4X \n", mode);
-      assert(0);
-      break;
-   }
-//   LOGD("agl2: glDrawArrays end");
-}
-
-void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glDrawElements=%p mode=0x%.4X count=%d type=0x%.4X indices=%p",
-//        glDrawElements, mode, count, type, indices);
-   if (!ctx->rasterizer.CurrentProgram)
-      return;
-
-   int maxAttrib = -1;
-   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
-   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
-//   LOGD("agl2: glDrawElements mode=0x%.4X type=0x%.4X count=%d program=%p indices=%p \n",
-//        mode, type, count, ctx->rasterizer.CurrentProgram, indices);
-   switch (mode) {
-   case GL_TRIANGLES:
-      if (GL_UNSIGNED_SHORT == type)
-         DrawElementsTriangles<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
-      else
-         assert(0);
-      break;
-   case GL_TRIANGLE_STRIP:
-      if (GL_UNSIGNED_SHORT == type)
-         DrawElementsTriangleStrip<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
-      else
-         assert(0);
-      break;
-   default:
-      assert(0);
-   }
-//   LOGD("agl2: glDrawElements end");
-}
-
-void glEnableVertexAttribArray(GLuint index)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->vert.attribs[index].enabled = true;
-//   LOGD("agl2: glEnableVertexAttribArray %d \n", index);
-}
-
-void glGenBuffers(GLsizei n, GLuint* buffers)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      buffers[i] = 0;
-      for (ctx->vert.free; ctx->vert.free < 0xffffffffu; ctx->vert.free++) {
-         if (ctx->vert.vbos.find(ctx->vert.free) == ctx->vert.vbos.end()) {
-            ctx->vert.vbos[ctx->vert.free] = NULL;
-            buffers[i] = ctx->vert.free;
-//            LOGD("glGenBuffers %d \n", buffers[i]);
-            ctx->vert.free++;
-            break;
-         }
-      }
-      assert(buffers[i]);
-   }
-}
-
-void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
-                           GLsizei stride, const GLvoid* ptr)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GL_FLOAT == type);
-   assert(0 < size && 4 >= size);
-   ctx->vert.attribs[index].size = size;
-   ctx->vert.attribs[index].type = type;
-   ctx->vert.attribs[index].normalized = normalized;
-   if (0 == stride)
-      ctx->vert.attribs[index].stride = size * sizeof(float);
-   else if (stride > 0)
-      ctx->vert.attribs[index].stride = stride;
-   else
-      assert(0);
-//   LOGD("\n*\n*\n* agl2: glVertexAttribPointer program=%u index=%d size=%d stride=%d ptr=%p \n*\n*",
-//        unsigned(ctx->rasterizer.CurrentProgram) ^ 0x04dc18f9, index, size, stride, ptr);
-   if (ctx->vert.vbo)
-      ctx->vert.attribs[index].ptr = (char *)ctx->vert.vbo->data + (long)ptr;
-   else
-      ctx->vert.attribs[index].ptr = ptr;
-//   const float * attrib = (const float *)ctx->vert.attribs[index].ptr;
-//   for (unsigned i = 0; i < 3; i++)
-//      if (3 == size)
-//         LOGD("%.2f %.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1], attrib[i * 3 + 2]);
-//      else if (2 == size)
-//         LOGD("%.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1]);
-   
-}
-
-void glVertexAttrib1f(GLuint indx, GLfloat x)
-{
-   glVertexAttrib4f(indx, x,0,0,1);
-}
-
-void glVertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],0,0,1);
-}
-
-void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
-   glVertexAttrib4f(indx, x,y,0,1);
-}
-
-void glVertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],values[1],0,1);
-}
-
-void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
-   glVertexAttrib4f(indx, x,y,z,1);
-}
-
-void glVertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],values[1],values[2],1);
-}
-
-void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-   assert(GGL_MAXVERTEXATTRIBS > indx);
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("\n*\n*\n agl2: glVertexAttrib4f %d %.2f,%.2f,%.2f,%.2f \n*\n*", indx, x, y, z, w);
-   ctx->vert.defaultAttribs[indx] = Vector4(x,y,z,w);
-   assert(0);
-}
-
-void glVertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0], values[1], values[2], values[3]);
-}
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 1e43195..6ad06af 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -212,16 +212,20 @@
 
 EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
 {
-    ImageRef _i(image);
-    if (!_i.get())
-        return EGL_NO_IMAGE_KHR;
-
     EGLContext context = egl_tls_t::getContext();
     if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
         return EGL_NO_IMAGE_KHR;
 
     egl_context_t const * const c = get_context(context);
-    if (c == NULL) // this should never happen
+    if (c == NULL) // this should never happen, by construction
+        return EGL_NO_IMAGE_KHR;
+
+    egl_display_t* display = egl_display_t::get(c->dpy);
+    if (display == NULL) // this should never happen, by construction
+        return EGL_NO_IMAGE_KHR;
+
+    ImageRef _i(display, image);
+    if (!_i.get())
         return EGL_NO_IMAGE_KHR;
 
     // here we don't validate the context because if it's been marked for
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 63f02e4..2237eb6 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,22 +49,6 @@
 
 // ----------------------------------------------------------------------------
 
-static char const * const sVendorString     = "Android";
-static char const * const sVersionString    = "1.4 Android META-EGL";
-static char const * const sClientApiString  = "OpenGL ES";
-static char const * const sExtensionString  =
-        "EGL_KHR_image "
-        "EGL_KHR_image_base "
-        "EGL_KHR_image_pixmap "
-        "EGL_KHR_gl_texture_2D_image "
-        "EGL_KHR_gl_texture_cubemap_image "
-        "EGL_KHR_gl_renderbuffer_image "
-        "EGL_KHR_fence_sync "
-        "EGL_ANDROID_image_native_buffer "
-        "EGL_ANDROID_swap_rectangle "
-        "EGL_NV_system_time "
-        ;
-
 struct extention_map_t {
     const char* name;
     __eglMustCastToProperFunctionPointerType address;
@@ -79,8 +63,6 @@
             (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
     { "eglDestroyImageKHR",
             (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-    { "eglSetSwapRectangleANDROID",
-            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
     { "eglGetSystemTimeFrequencyNV",
             (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
     { "eglGetSystemTimeNV",
@@ -451,7 +433,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -472,7 +454,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -541,7 +523,7 @@
     if (!dp)
         return EGL_FALSE;
 
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     
@@ -592,9 +574,9 @@
     }
 
     // get a reference to the object passed in
-    ContextRef _c(ctx);
-    SurfaceRef _d(draw);
-    SurfaceRef _r(read);
+    ContextRef _c(dp, ctx);
+    SurfaceRef _d(dp, draw);
+    SurfaceRef _r(dp, read);
 
     // validate the context (if not EGL_NO_CONTEXT)
     if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
@@ -696,7 +678,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
     egl_context_t * const c = get_context(ctx);
@@ -944,7 +926,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(draw);
+    SurfaceRef _s(dp, draw);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -960,7 +942,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -978,13 +960,13 @@
 
     switch (name) {
         case EGL_VENDOR:
-            return sVendorString;
+            return dp->getVendorString();
         case EGL_VERSION:
-            return sVersionString;
+            return dp->getVersionString();
         case EGL_EXTENSIONS:
-            return sExtensionString;
+            return dp->getExtensionString();
         case EGL_CLIENT_APIS:
-            return sClientApiString;
+            return dp->getClientApiString();
     }
     return setError(EGL_BAD_PARAMETER, (const char *)0);
 }
@@ -1002,7 +984,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1022,7 +1004,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1042,7 +1024,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1201,7 +1183,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1220,7 +1202,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1241,7 +1223,7 @@
     if (!dp) return EGL_NO_IMAGE_KHR;
 
     if (ctx != EGL_NO_CONTEXT) {
-        ContextRef _c(ctx);
+        ContextRef _c(dp, ctx);
         if (!_c.get())
             return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
         egl_context_t * const c = get_context(ctx);
@@ -1310,7 +1292,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    ImageRef _i(img);
+    ImageRef _i(dp, img);
     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     egl_image_t* image = get_image(img);
@@ -1349,7 +1331,7 @@
     if (!dp) return EGL_NO_SYNC_KHR;
 
     EGLContext ctx = eglGetCurrentContext();
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
 
@@ -1372,12 +1354,12 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     egl_sync_t* syncObject = get_sync(sync);
 
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1399,12 +1381,12 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     egl_sync_t* syncObject = get_sync(sync);
 
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1424,13 +1406,13 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get())
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     egl_sync_t* syncObject = get_sync(sync);
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1447,25 +1429,7 @@
 // ANDROID extensions
 // ----------------------------------------------------------------------------
 
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
-        EGLint left, EGLint top, EGLint width, EGLint height)
-{
-    clearError();
-
-    egl_display_t const * const dp = validate_display(dpy);
-    if (!dp) return EGL_FALSE;
-
-    SurfaceRef _s(draw);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
-    egl_surface_t const * const s = get_surface(draw);
-    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
-        return s->cnx->egl.eglSetSwapRectangleANDROID(
-                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
-    }
-    return setError(EGL_BAD_DISPLAY, NULL);
-}
+/* ANDROID extensions entry-point go here */
 
 // ----------------------------------------------------------------------------
 // NVIDIA extensions
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 558ca77..862b48d2 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -14,6 +14,8 @@
  ** limitations under the License.
  */
 
+#include <string.h>
+
 #include "egl_cache.h"
 #include "egl_display.h"
 #include "egl_object.h"
@@ -25,6 +27,36 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+static char const * const sVendorString     = "Android";
+static char const * const sVersionString    = "1.4 Android META-EGL";
+static char const * const sClientApiString  = "OpenGL ES";
+
+// this is the list of EGL extensions that are exposed to applications
+// some of them are mandatory because used by the ANDROID system.
+//
+// mandatory extensions are required per the CDD and not explicitly
+// checked during EGL initialization. the system *assumes* these extensions
+// are present. the system may not function properly if some mandatory
+// extensions are missing.
+//
+// NOTE: sExtensionString MUST be have a single space as the last character.
+//
+static char const * const sExtensionString  =
+        "EGL_KHR_image "                        // mandatory
+        "EGL_KHR_image_base "                   // mandatory
+        "EGL_KHR_image_pixmap "
+        "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_cubemap_image "
+        "EGL_KHR_gl_renderbuffer_image "
+        "EGL_KHR_fence_sync "
+        "EGL_NV_system_time "
+        "EGL_ANDROID_image_native_buffer "      // mandatory
+        ;
+
+// extensions not exposed to applications but used by the ANDROID system
+//      "EGL_ANDROID_recordable "               // mandatory
+//      "EGL_ANDROID_blob_cache "               // strongly recommended
+
 extern void initEglTraceLevel();
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 
@@ -62,11 +94,13 @@
     objects.remove(object);
 }
 
-bool egl_display_t::getObject(egl_object_t* object) {
+bool egl_display_t::getObject(egl_object_t* object) const {
     Mutex::Autolock _l(lock);
     if (objects.indexOf(object) >= 0) {
-        object->incRef();
-        return true;
+        if (object->getDisplay() == this) {
+            object->incRef();
+            return true;
+        }
     }
     return false;
 }
@@ -172,6 +206,36 @@
         }
     }
 
+    // the query strings are per-display
+    mVendorString.setTo(sVendorString);
+    mVersionString.setTo(sVersionString);
+    mClientApiString.setTo(sClientApiString);
+
+    // we only add extensions that exist in at least one implementation
+    char const* start = sExtensionString;
+    char const* end;
+    do {
+        // find the space separating this extension for the next one
+        end = strchr(start, ' ');
+        if (end) {
+            // length of the extension string
+            const size_t len = end - start;
+            // 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 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);
+                }
+            }
+            // process the next extension string, and skip the space.
+            start = end + 1;
+        }
+    } while (end);
+
     egl_cache_t::get()->initialize(this);
 
     EGLBoolean res = EGL_FALSE;
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index e0a367d..042ae07 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -29,6 +29,7 @@
 
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
+#include <utils/String8.h>
 
 #include "egldefs.h"
 #include "hooks.h"
@@ -81,7 +82,7 @@
     // remove object from this display's list
     void removeObject(egl_object_t* object);
     // add reference to this object. returns true if this is a valid object.
-    bool getObject(egl_object_t* object);
+    bool getObject(egl_object_t* object) const;
 
 
     static egl_display_t* get(EGLDisplay dpy);
@@ -91,6 +92,11 @@
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
 
+    char const * getVendorString() const { return mVendorString.string(); }
+    char const * getVersionString() const { return mVersionString.string(); }
+    char const * getClientApiString() const { return mClientApiString.string(); }
+    char const * getExtensionString() const { return mExtensionString.string(); }
+
     inline uint32_t getRefsCount() const { return refs; }
 
     struct strings_t {
@@ -119,9 +125,13 @@
     egl_config_t*   configs;
 
 private:
-    uint32_t        refs;
-    Mutex           lock;
-    SortedVector<egl_object_t*> objects;
+            uint32_t                    refs;
+    mutable Mutex                       lock;
+            SortedVector<egl_object_t*> objects;
+            String8 mVendorString;
+            String8 mVersionString;
+            String8 mClientApiString;
+            String8 mExtensionString;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index dbf9a01..20cdc7e 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -55,10 +55,10 @@
     }
 }
 
-bool egl_object_t::get() {
+bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) {
     // used by LocalRef, this does an incRef() atomically with
     // checking that the object is valid.
-    return display->getObject(this);
+    return display->getObject(object);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 46f7139..df1b261 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -52,10 +52,11 @@
 
     inline int32_t incRef() { return android_atomic_inc(&count); }
     inline int32_t decRef() { return android_atomic_dec(&count); }
+    inline egl_display_t* getDisplay() const { return display; }
 
 private:
     void terminate();
-    bool get();
+    static bool get(egl_display_t const* display, egl_object_t* object);
 
 public:
     template <typename N, typename T>
@@ -66,9 +67,9 @@
     public:
         ~LocalRef();
         explicit LocalRef(egl_object_t* rhs);
-        explicit LocalRef(T o) : ref(0) {
+        explicit LocalRef(egl_display_t const* display, T o) : ref(0) {
             egl_object_t* native = reinterpret_cast<N*>(o);
-            if (o && native->get()) {
+            if (o && egl_object_t::get(display, native)) {
                 ref = native;
             }
         }
diff --git a/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml b/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml
new file mode 100644
index 0000000..ce3372e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+    <item android:state_pressed="true"  android:drawable="@drawable/notification_item_background_color_pressed" />
+    <item android:state_pressed="false" android:drawable="@drawable/notification_item_background_legacy_color" />
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 3ee9e77..180f022 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -33,39 +33,29 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <LinearLayout android:id="@+id/recents_glow"
+        <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_gravity="bottom|right"
+            android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+            android:divider="@null"
+            android:stackFromBottom="true"
+            android:fadingEdge="horizontal"
+            android:scrollbars="none"
+            android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+            android:layout_gravity="bottom|left"
             android:orientation="horizontal"
             android:clipToPadding="false"
-            android:clipChildren="false"
-            >
-            <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
+            android:clipChildren="false">
+
+            <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
-                android:divider="@null"
-                android:stackFromBottom="true"
-                android:fadingEdge="horizontal"
-                android:scrollbars="none"
-                android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-                android:layout_gravity="bottom|left"
                 android:orientation="horizontal"
                 android:clipToPadding="false"
                 android:clipChildren="false">
+            </LinearLayout>
 
-                <LinearLayout android:id="@+id/recents_linear_layout"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    android:orientation="horizontal"
-                    android:clipToPadding="false"
-                    android:clipChildren="false">
-                </LinearLayout>
-
-            </com.android.systemui.recent.RecentsHorizontalScrollView>
-
-        </LinearLayout>
+        </com.android.systemui.recent.RecentsHorizontalScrollView>
 
     </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index d040544..e6a077a 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -31,39 +31,29 @@
         android:layout_height="match_parent"
         android:layout_alignParentBottom="true">
 
-        <LinearLayout android:id="@+id/recents_glow"
+        <com.android.systemui.recent.RecentsVerticalScrollView
+            android:id="@+id/recents_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="bottom"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:layout_marginTop="@*android:dimen/status_bar_height">
+            android:layout_marginRight="0dp"
+            android:divider="@null"
+            android:stackFromBottom="true"
+            android:fadingEdge="vertical"
+            android:scrollbars="none"
+            android:fadingEdgeLength="@*android:dimen/status_bar_height"
+            android:layout_gravity="bottom|left"
+            android:clipToPadding="false"
+            android:clipChildren="false">
 
-            <com.android.systemui.recent.RecentsVerticalScrollView
-                android:id="@+id/recents_container"
+            <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginRight="0dp"
-                android:divider="@null"
-                android:stackFromBottom="true"
-                android:fadingEdge="vertical"
-                android:scrollbars="none"
-                android:fadingEdgeLength="@*android:dimen/status_bar_height"
-                android:layout_gravity="bottom|left"
+                android:orientation="vertical"
                 android:clipToPadding="false"
                 android:clipChildren="false">
+            </LinearLayout>
 
-                <LinearLayout android:id="@+id/recents_linear_layout"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:orientation="vertical"
-                    android:clipToPadding="false"
-                    android:clipChildren="false">
-                </LinearLayout>
-
-            </com.android.systemui.recent.RecentsVerticalScrollView>
-
-        </LinearLayout>
+        </com.android.systemui.recent.RecentsVerticalScrollView>
 
     </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_no_recent_apps.xml
new file mode 100644
index 0000000..bc89281
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_no_recent_apps.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** 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.
+*/
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="20dp"
+        android:textColor="@android:color/holo_blue_light"
+        android:text="@string/status_bar_no_recent_apps"
+        android:gravity="left"
+        android:layout_gravity="bottom|left"
+    />
+</FrameLayout>
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 18a31f7..cb26db00 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -23,31 +23,6 @@
     android:layout_height="wrap_content"
     android:layout_width="wrap_content">
 
-    <FrameLayout android:id="@+id/app_thumbnail"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
-        android:scaleType="center"
-        android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_fg"
-        android:visibility="invisible">
-        <ImageView android:id="@+id/app_thumbnail_image"
-            android:layout_width="@dimen/status_bar_recents_thumbnail_width"
-            android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-        />
-        <ImageView android:id="@+id/app_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
-            android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-            android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
-            android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
-            android:adjustViewBounds="true"
-        />
-    </FrameLayout>
-
     <TextView android:id="@+id/app_label"
         android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="wrap_content"
@@ -64,6 +39,35 @@
         android:textColor="@color/status_bar_recents_app_label_color"
     />
 
+    <FrameLayout android:id="@+id/app_thumbnail"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/app_label"
+        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+        android:scaleType="center"
+        android:background="@drawable/recents_thumbnail_bg"
+        android:foreground="@drawable/recents_thumbnail_fg"
+        android:visibility="invisible">
+        <ImageView android:id="@+id/app_thumbnail_image"
+            android:layout_width="@dimen/status_bar_recents_thumbnail_width"
+            android:layout_height="@dimen/status_bar_recents_thumbnail_height"
+        />
+    </FrameLayout>
+
+
+    <ImageView android:id="@+id/app_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/app_label"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+        android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+        android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
+        android:scaleType="centerInside"
+        android:adjustViewBounds="true"
+    />
+
+
     <View android:id="@+id/recents_callout_line"
         android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="1dip"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 5dd101e..111f9a4 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -36,40 +36,36 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <LinearLayout android:id="@+id/recents_glow"
+        <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="-49dip"
-            android:layout_gravity="bottom"
-            android:background="@drawable/recents_blue_glow"
-            android:orientation="horizontal"
+            android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+            android:divider="@null"
+            android:stackFromBottom="true"
+            android:fadingEdge="vertical"
+            android:scrollbars="none"
+            android:fadingEdgeLength="20dip"
+            android:layout_gravity="bottom|left"
             android:clipToPadding="false"
-            android:clipChildren="false"
-            >
-            <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
+            android:clipChildren="false">
+
+            <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
-                android:divider="@null"
-                android:stackFromBottom="true"
-                android:fadingEdge="vertical"
-                android:scrollbars="none"
-                android:fadingEdgeLength="20dip"
-                android:layout_gravity="bottom|left"
+                android:orientation="vertical"
                 android:clipToPadding="false"
                 android:clipChildren="false">
+            </LinearLayout>
 
-                <LinearLayout android:id="@+id/recents_linear_layout"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:orientation="vertical"
-                    android:clipToPadding="false"
-                    android:clipChildren="false">
-                </LinearLayout>
+        </com.android.systemui.recent.RecentsVerticalScrollView>
 
-            </com.android.systemui.recent.RecentsVerticalScrollView>
-
-        </LinearLayout>
+        <include layout="@layout/status_bar_no_recent_apps"
+            android:id="@+id/recents_no_apps"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginLeft="58dip"
+            android:layout_marginBottom="36dip"
+            android:visibility="invisible" />
 
     </FrameLayout>
 
@@ -82,4 +78,5 @@
         android:contentDescription="@string/status_bar_accessibility_dismiss_recents"
     />
 
+
 </com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index af2c93c..b1aaade 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -31,21 +31,35 @@
     <LinearLayout android:id="@+id/icons"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:orientation="horizontal">
-            
-        <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
+        android:paddingLeft="6dip"
+        android:paddingRight="6dip"
+        android:orientation="horizontal"
+        >
+
+        <LinearLayout
             android:layout_width="0dip"
-            android:layout_weight="1"
             android:layout_height="match_parent"
-            android:layout_alignParentLeft="true"
-            android:paddingLeft="6dip"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"/>  
-            
+            android:layout_weight="1"
+            android:orientation="horizontal"
+            >
+            <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/moreIcon"
+                android:layout_width="@dimen/status_bar_icon_size"
+                android:layout_height="match_parent"
+                android:src="@drawable/stat_notify_more"
+                android:visibility="gone"
+                />
+
+            <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentLeft="true"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"/>  
+        </LinearLayout>
+
         <LinearLayout android:id="@+id/statusIcons"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_alignParentRight="true"
             android:gravity="center_vertical"
             android:orientation="horizontal"/>    
 
@@ -53,7 +67,7 @@
             android:id="@+id/signal_battery_cluster"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_marginRight="6dp"
+            android:paddingLeft="2dp"
             android:orientation="horizontal"
             android:gravity="center"
             >
@@ -66,7 +80,7 @@
                 android:id="@+id/battery"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
-                android:paddingLeft="6dip"
+                android:paddingLeft="4dip"
                 />
         </LinearLayout>
 
@@ -76,7 +90,7 @@
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:singleLine="true"
-            android:paddingRight="6dip"
+            android:paddingLeft="6dip"
             android:gravity="center_vertical|left"
             />
     </LinearLayout>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 3e2ec59..24185a4f 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -18,8 +18,11 @@
 -->
 
 <resources>
-
     <!-- Whether we're using the tablet-optimized recents interface (we use this
      value at runtime for some things) -->
     <bool name="config_recents_interface_for_tablets">true</bool>
+
+    <!-- Whether recents thumbnails should stretch in both x and y to fill their
+     ImageView -->
+    <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index fe9245d..f522285 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -31,15 +31,15 @@
 
     <!-- Recent Applications parameters -->
     <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">121dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_left_margin">28dp</dimen>
     <!-- Upper width limit for application icon -->
     <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
     <!-- Upper height limit for application icon -->
     <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
 
     <!-- Size of application icon -->
-    <dimen name="status_bar_recents_thumbnail_width">245dp</dimen>
-    <dimen name="status_bar_recents_thumbnail_height">144dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_width">208dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_height">130dp</dimen>
 
     <!-- Width of recents panel -->
     <dimen name="status_bar_recents_width">600dp</dimen>
@@ -59,8 +59,8 @@
     <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
 
     <!-- Where to place the app icon over the thumbnail -->
-    <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
-    <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
+    <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
+    <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
 
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">24dip</dimen>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ff67a7e..3a2ea65 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,4 +30,5 @@
     <drawable name="notification_tracking_bg">#d8000000</drawable>
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="recents_callout_line">#99ffffff</drawable>
+    <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1fe4ebb..1f22507 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -25,6 +25,10 @@
      value at runtime for some things) -->
     <bool name="config_recents_interface_for_tablets">false</bool>
 
+    <!-- Whether recents thumbnails should stretch in both x and y to fill their
+     ImageView -->
+    <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool>
+
     <!-- Control whether status bar should distinguish HSPA data icon form UMTS
     data icon on devices -->
     <bool name="config_hspa_data_distinguishable">false</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index 886a14d..ad38a11 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -120,8 +120,13 @@
 
         createAnimation(appearing);
 
-        mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        mContentView.buildLayer();
+        // isHardwareAccelerated() checks if we're attached to a window and if that
+        // window is HW accelerated-- we were sometimes not attached to a window
+        // and buildLayer was throwing an IllegalStateException
+        if (mContentView.isHardwareAccelerated()) {
+            mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            mContentView.buildLayer();
+        }
         mContentAnim.start();
 
         mVisible = appearing;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 6b8b65e..8bfd711 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -16,14 +16,13 @@
 
 package com.android.systemui.recent;
 
-import java.util.ArrayList;
-
 import android.animation.Animator;
 import android.animation.LayoutTransition;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Shader.TileMode;
@@ -42,15 +41,15 @@
 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.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;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView.ScaleType;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBar;
@@ -58,6 +57,8 @@
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
+import java.util.ArrayList;
+
 public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
         StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
     static final String TAG = "RecentsPanelView";
@@ -65,7 +66,6 @@
     private Context mContext;
     private StatusBar mBar;
     private View mRecentsScrim;
-    private View mRecentsGlowView;
     private View mRecentsNoApps;
     private ViewGroup mRecentsContainer;
 
@@ -79,6 +79,7 @@
     private boolean mRecentTasksDirty = true;
     private TaskDescriptionAdapter mListAdapter;
     private int mThumbnailWidth;
+    private boolean mFitThumbnailToXY;
 
     public void setRecentTasksLoader(RecentTasksLoader loader) {
         mRecentTasksLoader = loader;
@@ -174,9 +175,8 @@
         // use mRecentsContainer's exact bounds to determine horizontal position
         final int l = mRecentsContainer.getLeft();
         final int r = mRecentsContainer.getRight();
-        // use surrounding mRecentsGlowView's position in parent determine vertical bounds
-        final int t = mRecentsGlowView.getTop();
-        final int b = mRecentsGlowView.getBottom();
+        final int t = mRecentsContainer.getTop();
+        final int b = mRecentsContainer.getBottom();
         return x >= l && x < r && y >= t && y < b;
     }
 
@@ -194,7 +194,7 @@
             // if there are no apps, either bring up a "No recent apps" message, or just
             // quit early
             boolean noApps = (mRecentTaskDescriptions.size() == 0);
-            if (mRecentsNoApps != null) { // doesn't exist on large devices
+            if (mRecentsNoApps != null) {
                 mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
             } else {
                 if (noApps) {
@@ -325,8 +325,9 @@
     }
 
     public void updateValuesFromResources() {
-        mThumbnailWidth =
-            (int) mContext.getResources().getDimension(R.dimen.status_bar_recents_thumbnail_width);
+        final Resources res = mContext.getResources();
+        mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
+        mFitThumbnailToXY = res.getBoolean(R.bool.config_recents_thumbnail_image_fits_to_xy);
     }
 
     @Override
@@ -351,10 +352,9 @@
         }
 
 
-        mRecentsGlowView = findViewById(R.id.recents_glow);
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
-        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, mRecentsNoApps, this);
+        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
         mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
         if (mRecentsDismissButton != null) {
             mRecentsDismissButton.setOnClickListener(new OnClickListener() {
@@ -409,11 +409,15 @@
             if (h.thumbnailViewImageBitmap == null ||
                 h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
                 h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
-                Matrix scaleMatrix = new Matrix();
-                float scale = mThumbnailWidth / (float) thumbnail.getWidth();
-                scaleMatrix.setScale(scale, scale);
-                h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
-                h.thumbnailViewImage.setImageMatrix(scaleMatrix);
+                if (mFitThumbnailToXY) {
+                    h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
+                } else {
+                    Matrix scaleMatrix = new Matrix();
+                    float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+                    scaleMatrix.setScale(scale, scale);
+                    h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
+                    h.thumbnailViewImage.setImageMatrix(scaleMatrix);
+                }
             }
             if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
                 if (anim) {
@@ -444,7 +448,7 @@
                             // only fade in the thumbnail if recents is already visible-- we
                             // show it immediately otherwise
                             boolean animateShow = mShowing &&
-                                mRecentsGlowView.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
+                                mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
                             updateThumbnail(h, ad.getThumbnail(), true, animateShow);
                         }
                     }
@@ -516,7 +520,6 @@
         final int items = mRecentTaskDescriptions.size();
 
         mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
-        mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
 
         // Set description for accessibility
         int numRecentApps = mRecentTaskDescriptions.size();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index c259c28..ad37603 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -49,8 +49,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -131,8 +129,8 @@
         // Show the intermediate notification
         mTickerAddSpace = !mTickerAddSpace;
         mNotificationId = nId;
+        mNotificationManager = nManager;
         mNotificationBuilder = new Notification.Builder(context)
-            .setLargeIcon(croppedIcon)
             .setTicker(r.getString(R.string.screenshot_saving_ticker)
                     + (mTickerAddSpace ? " " : ""))
             .setContentTitle(r.getString(R.string.screenshot_saving_title))
@@ -141,9 +139,12 @@
             .setWhen(System.currentTimeMillis());
         Notification n = mNotificationBuilder.getNotification();
         n.flags |= Notification.FLAG_NO_CLEAR;
-
-        mNotificationManager = nManager;
         mNotificationManager.notify(nId, n);
+
+        // On the tablet, the large icon makes the notification appear as if it is clickable (and
+        // on small devices, the large icon is not shown) so defer showing the large icon until
+        // we compose the final post-save notification below.
+        mNotificationBuilder.setLargeIcon(croppedIcon);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6997837..8228df5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -25,6 +25,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.text.TextUtils;
+import android.util.AttributeSet;
 import android.util.Slog;
 import android.util.Log;
 import android.view.ViewDebug;
@@ -75,6 +76,18 @@
         setScaleType(ImageView.ScaleType.CENTER);
     }
 
+    public StatusBarIconView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Resources res = context.getResources();
+        final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
+        final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
+        final float scale = (float)imageBounds / (float)outerBounds;
+        setScaleX(scale);
+        setScaleY(scale);
+        final float alpha = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
+        setAlpha(alpha);
+    }
+
     private static boolean streq(String a, String b) {
         if (a == b) {
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index 20215bd..0640282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -30,113 +30,59 @@
 
 public class IconMerger extends LinearLayout {
     private static final String TAG = "IconMerger";
+    private static final boolean DEBUG = false;
 
     private int mIconSize;
-    private StatusBarIconView mMoreView;
-    private StatusBarIcon mMoreIcon = new StatusBarIcon(null, R.drawable.stat_notify_more, 0, 0,
-            null);
+    private View mMoreView;
 
     public IconMerger(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         mIconSize = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_icon_size);
+                R.dimen.status_bar_icon_size);
 
-        mMoreView = new StatusBarIconView(context, "more", null);
-        mMoreView.set(mMoreIcon);
-        super.addView(mMoreView, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+        if (DEBUG) {
+            setBackgroundColor(0x800099FF);
+        }
     }
 
-    public void addView(StatusBarIconView v, int index, LinearLayout.LayoutParams p) {
-        super.addView(v, index+1, p);
+    public void setOverflowIndicator(View v) {
+        mMoreView = v;
     }
 
-    public void addView(StatusBarIconView v, int index) {
-        super.addView(v, index+1, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        // we need to constrain this to an integral multiple of our children
+        int width = getMeasuredWidth();
+        setMeasuredDimension(width - (width % mIconSize), getMeasuredHeight());
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
+        checkOverflow(r - l);
+    }
 
-        final int maxWidth = r - l;
+    private void checkOverflow(int width) {
+        if (mMoreView == null) return;
+
         final int N = getChildCount();
-        int i;
-
-        // get the rightmost one, and see if we even need to do anything
-        int fitRight = -1;
-        for (i=N-1; i>=0; i--) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                fitRight = child.getRight();
-                break;
-            }
+        int visibleChildren = 0;
+        for (int i=0; i<N; i++) {
+            if (getChildAt(i).getVisibility() != GONE) visibleChildren++;
         }
-
-        // find the first visible one that isn't the more icon
-        final StatusBarIconView moreView = mMoreView;
-        int fitLeft = -1;
-        int startIndex = -1;
-        for (i=0; i<N; i++) {
-            final View child = getChildAt(i);
-            if (child == moreView) {
-                startIndex = i+1;
-            }
-            else if (child.getVisibility() != GONE) {
-                fitLeft = child.getLeft();
-                break;
-            }
-        }
-
-        if (moreView == null || startIndex < 0) {
-            return;
-            /*
-            throw new RuntimeException("Status Bar / IconMerger moreView == " + moreView
-                    + " startIndex=" + startIndex);
-            */
-        }
-        
-        // if it fits without the more icon, then hide the more icon and update fitLeft
-        // so everything gets pushed left
-        int adjust = 0;
-        if (fitRight - fitLeft <= maxWidth) {
-            adjust = fitLeft - moreView.getLeft();
-            fitLeft -= adjust;
-            fitRight -= adjust;
-            moreView.layout(0, moreView.getTop(), 0, moreView.getBottom());
-        }
-        int extra = fitRight - r;
-        int shift = -1;
-
-        int breakingPoint = fitLeft + extra + adjust;
-        int number = 0;
-        for (i=startIndex; i<N; i++) {
-            final StatusBarIconView child = (StatusBarIconView)getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                int childLeft = child.getLeft();
-                int childRight = child.getRight();
-                if (childLeft < breakingPoint) {
-                    // hide this one
-                    child.layout(0, child.getTop(), 0, child.getBottom());
-                    int n = child.getStatusBarIcon().number;
-                    if (n == 0) {
-                        number += 1;
-                    } else if (n > 0) {
-                        number += n;
-                    }
-                } else {
-                    // decide how much to shift by
-                    if (shift < 0) {
-                        shift = childLeft - fitLeft;
-                    }
-                    // shift this left by shift
-                    child.layout(childLeft-shift, child.getTop(),
-                                    childRight-shift, child.getBottom());
+        final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
+        // let's assume we have one more slot if the more icon is already showing
+        if (overflowShown) visibleChildren --;
+        final boolean moreRequired = visibleChildren * mIconSize > width;
+        if (moreRequired != overflowShown) {
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    mMoreView.setVisibility(moreRequired ? View.VISIBLE : View.GONE);
                 }
-            }
+            });
         }
-
-        mMoreIcon.number = number;
-        mMoreView.set(mMoreIcon);
     }
 }
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 51fb262..f0093d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -28,11 +28,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Handler;
@@ -149,6 +152,7 @@
     // icons
     LinearLayout mIcons;
     IconMerger mNotificationIcons;
+    View mMoreIcon;
     LinearLayout mStatusIcons;
 
     // expanded notifications
@@ -307,6 +311,8 @@
         mPixelFormat = PixelFormat.OPAQUE;
         mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);
+        mMoreIcon = sb.findViewById(R.id.moreIcon);
+        mNotificationIcons.setOverflowIndicator(mMoreIcon);
         mIcons = (LinearLayout)sb.findViewById(R.id.icons);
         mTickerView = sb.findViewById(R.id.ticker);
 
@@ -772,6 +778,8 @@
             row.setDrawingCacheEnabled(true);
         }
 
+        applyLegacyRowBackground(notification, content);
+
         return new View[] { row, content, expanded };
     }
 
@@ -945,6 +953,8 @@
             row.setDrawingCacheEnabled(true);
         }
 
+        applyLegacyRowBackground(sbn, content);
+
         entry.row = row;
         entry.content = content;
         entry.expanded = expanded;
@@ -953,6 +963,24 @@
         return true;
     }
 
+    void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
+        if (sbn.notification.contentView.getLayoutId() !=
+                com.android.internal.R.layout.status_bar_latest_event_content) {
+            int version = 0;
+            try {
+                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.pkg, 0);
+                version = info.targetSdkVersion;
+            } catch (NameNotFoundException ex) {
+                Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
+            }
+            if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) {
+                content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
+            } else {
+                content.setBackgroundResource(R.drawable.notification_row_bg);
+            }
+        }
+    }
+
     StatusBarNotification removeNotificationViews(IBinder key) {
         NotificationData.Entry entry = mNotificationData.remove(key);
         if (entry == null) {
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 5a52258..eb8c583 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -32,13 +32,17 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.inputmethodservice.InputMethodService;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -1741,8 +1745,10 @@
     }
 
     void workAroundBadLayerDrawableOpacity(View v) {
-        LayerDrawable d = (LayerDrawable)v.getBackground();
-        if (d == null) return;
+        Drawable bgd = v.getBackground();
+        if (!(bgd instanceof LayerDrawable)) return;
+
+        LayerDrawable d = (LayerDrawable) bgd;
         v.setBackgroundDrawable(null);
         d.setOpacity(PixelFormat.TRANSLUCENT);
         v.setBackgroundDrawable(d);
@@ -1808,6 +1814,8 @@
             row.setDrawingCacheEnabled(true);
         }
 
+        applyLegacyRowBackground(sbn, content);
+
         entry.row = row;
         entry.content = content;
         entry.expanded = expanded;
@@ -1816,6 +1824,24 @@
         return true;
     }
 
+    void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
+        if (sbn.notification.contentView.getLayoutId() !=
+                com.android.internal.R.layout.status_bar_latest_event_content) {
+            int version = 0;
+            try {
+                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.pkg, 0);
+                version = info.targetSdkVersion;
+            } catch (NameNotFoundException ex) {
+                Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
+            }
+            if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) {
+                content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
+            } else {
+                content.setBackgroundResource(R.drawable.notification_row_bg);
+            }
+        }
+    }
+
     public void clearAll() {
         try {
             mBarService.onClearAllNotifications();
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index a7da96e..ee54de1 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -168,7 +168,7 @@
                 boolean emergencyButtonEnabledInScreen) {
         if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()");
         mContainer = view;
-        mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year);
+        mDateFormatString = getContext().getString(R.string.abbrev_wday_month_day_no_year);
         mLockPatternUtils = lockPatternUtils;
         mUpdateMonitor = updateMonitor;
         mCallback = callback;
@@ -481,7 +481,14 @@
                 break;
 
             case SimMissing:
+                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
+                // has some connectivity. Otherwise, it should be null or empty and just show
+                // "No SIM card"
                 carrierText = getContext().getText(R.string.lockscreen_missing_sim_message_short);
+                if (mLockPatternUtils.isEmergencyCallCapable()) {
+                    carrierText = makeCarierString(carrierText, mPlmn);
+                }
                 carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
                 break;
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2bd89dd..1f13dab 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3113,7 +3113,7 @@
                 sensorRotation = lastRotation;
             }
 
-            int preferredRotation = -1;
+            final int preferredRotation;
             if (mHdmiPlugged) {
                 // Ignore sensor when plugged into HDMI.
                 preferredRotation = mHdmiRotation;
@@ -3162,28 +3162,39 @@
             } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
                 // Apply rotation lock.
                 preferredRotation = mUserRotation;
+            } else {
+                // No overriding preference.
+                // We will do exactly what the application asked us to do.
+                preferredRotation = -1;
             }
 
-            // TODO: Sometimes, we might want to override the application-requested
-            //       orientation, such as when HDMI is plugged in or when docked.
-            //       We can do that by modifying the appropriate cases above to return
-            //       the preferred orientation directly instead of continuing on down here.
-
             switch (orientation) {
                 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-                    // Always return portrait if orientation set to portrait.
+                    // Return portrait unless overridden.
+                    if (isAnyPortrait(preferredRotation)) {
+                        return preferredRotation;
+                    }
                     return mPortraitRotation;
 
                 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-                    // Always return landscape if orientation set to landscape.
+                    // Return landscape unless overridden.
+                    if (isLandscapeOrSeascape(preferredRotation)) {
+                        return preferredRotation;
+                    }
                     return mLandscapeRotation;
 
                 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-                    // Always return portrait if orientation set to portrait.
+                    // Return reverse portrait unless overridden.
+                    if (isAnyPortrait(preferredRotation)) {
+                        return preferredRotation;
+                    }
                     return mUpsideDownRotation;
 
                 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-                    // Always return seascape if orientation set to reverse landscape.
+                    // Return seascape unless overridden.
+                    if (isLandscapeOrSeascape(preferredRotation)) {
+                        return preferredRotation;
+                    }
                     return mSeascapeRotation;
 
                 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 790b395..52897417 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -507,6 +507,15 @@
     }
 }
 
+String8 EventHub::getKeyCharacterMapFile(int32_t deviceId) const {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device) {
+        return device->keyMap.keyCharacterMapFile;
+    }
+    return String8();
+}
+
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
     if (deviceId == 0) {
         deviceId = mBuiltInKeyboardId;
@@ -1013,16 +1022,12 @@
 
     // Configure the keyboard, gamepad or virtual keyboard.
     if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
-        // Set system properties for the keyboard.
-        setKeyboardPropertiesLocked(device, false);
-
         // Register the keyboard as a built-in keyboard if it is eligible.
         if (!keyMapStatus
                 && mBuiltInKeyboardId == -1
                 && isEligibleBuiltInKeyboard(device->identifier,
                         device->configuration, &device->keyMap)) {
             mBuiltInKeyboardId = device->id;
-            setKeyboardPropertiesLocked(device, true);
         }
 
         // 'Q' key support = cheap test of whether this is an alpha-capable kbd
@@ -1120,17 +1125,6 @@
     return device->keyMap.load(device->identifier, device->configuration);
 }
 
-void EventHub::setKeyboardPropertiesLocked(Device* device, bool builtInKeyboard) {
-    int32_t id = builtInKeyboard ? 0 : device->id;
-    android::setKeyboardProperties(id, device->identifier,
-            device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile);
-}
-
-void EventHub::clearKeyboardPropertiesLocked(Device* device, bool builtInKeyboard) {
-    int32_t id = builtInKeyboard ? 0 : device->id;
-    android::clearKeyboardProperties(id);
-}
-
 bool EventHub::isExternalDeviceLocked(Device* device) {
     if (device->configuration) {
         bool value;
@@ -1184,9 +1178,7 @@
         LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
                 device->path.string(), mBuiltInKeyboardId);
         mBuiltInKeyboardId = -1;
-        clearKeyboardPropertiesLocked(device, true);
     }
-    clearKeyboardPropertiesLocked(device, false);
 
     if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
         LOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index d37549a..9d8252e 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -208,6 +208,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
 
+    virtual String8 getKeyCharacterMapFile(int32_t deviceId) const = 0;
+
     /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
     virtual void requestReopenDevices() = 0;
 
@@ -264,6 +266,8 @@
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
             Vector<VirtualKeyDefinition>& outVirtualKeys) const;
 
+    virtual String8 getKeyCharacterMapFile(int32_t deviceId) const;
+
     virtual void requestReopenDevices();
 
     virtual void wake();
@@ -321,8 +325,6 @@
     void loadConfigurationLocked(Device* device);
     status_t loadVirtualKeyMapLocked(Device* device);
     status_t loadKeyMapLocked(Device* device);
-    void setKeyboardPropertiesLocked(Device* device, bool builtInKeyboard);
-    void clearKeyboardPropertiesLocked(Device* device, bool builtInKeyboard);
 
     bool isExternalDeviceLocked(Device* device);
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 88c19a4..b34ff25 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1775,6 +1775,7 @@
     InputMapper::populateDeviceInfo(info);
 
     info->setKeyboardType(mKeyboardType);
+    info->setKeyCharacterMapFile(getEventHub()->getKeyCharacterMapFile(getDeviceId()));
 }
 
 void KeyboardInputMapper::dump(String8& dump) {
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index a086208..08efe7d 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -609,6 +609,10 @@
         }
     }
 
+    virtual String8 getKeyCharacterMapFile(int32_t deviceId) const {
+        return String8();
+    }
+
     virtual bool isExternal(int32_t deviceId) const {
         return false;
     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c6b8247..098f138 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1224,8 +1224,8 @@
                 }
                 synchronized (ActivityManagerService.this) {
                     long now = SystemClock.uptimeMillis();
-                    if (now < (mLastMemUsageReportTime+10000)) {
-                        // Don't report more than every 10 seconds to somewhat
+                    if (now < (mLastMemUsageReportTime+5*60*1000)) {
+                        // Don't report more than every 5 minutes to somewhat
                         // avoid spamming.
                         return;
                     }
@@ -1261,15 +1261,25 @@
                         PrintWriter pw = new PrintWriter(sw);
                         StringWriter catSw = new StringWriter();
                         PrintWriter catPw = new PrintWriter(catSw);
-                        dumpApplicationMemoryUsage(null, pw, "  ", new String[] { }, true, catPw);
+                        String[] emptyArgs = new String[] { };
+                        StringBuilder tag = new StringBuilder(128);
+                        synchronized (ActivityManagerService.this) {
+                            dumpProcessesLocked(null, catPw, emptyArgs, 0, false);
+                            catPw.println();
+                            dumpServicesLocked(null, catPw, emptyArgs, 0, false, false);
+                            catPw.println();
+                            dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false);
+                            catPw.println();
+                        }
+                        tag.append("Low on memory -- ");
+                        dumpApplicationMemoryUsage(null, pw, "  ", emptyArgs, true, catPw, tag);
                         String memUsage = sw.toString();
                         dropBuilder.append('\n');
                         dropBuilder.append(memUsage);
                         dropBuilder.append(catSw.toString());
                         logBuilder.append(memUsage);
-                        addErrorToDropBox("watchdog", null, "system_server", null,
-                                null, "Low on memory -- no more background processes",
-                                dropBuilder.toString(), null, null);
+                        addErrorToDropBox("lowmem", null, "system_server", null,
+                                null, tag.toString(), dropBuilder.toString(), null, null);
                         Slog.i(TAG, logBuilder.toString());
                         synchronized (ActivityManagerService.this) {
                             long now = SystemClock.uptimeMillis();
@@ -1422,7 +1432,8 @@
                 return;
             }
 
-            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
+            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args,
+                    false, null, null);
         }
     }
 
@@ -8812,6 +8823,20 @@
                         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:");
@@ -8931,18 +8956,21 @@
                     continue;
                 }
                 pw.print("  * "); pw.print(cls); pw.print(" (");
-                        pw.print(comp.flattenToShortString()); pw.print(")");
+                        pw.print(comp.flattenToShortString()); pw.println(")");
                 if (dumpAll) {
-                    pw.println();
                     r.dump(pw, "      ");
                 } else {
-                    pw.print("  * "); pw.print(e.getKey().flattenToShortString());
                     if (r.proc != null) {
-                        pw.println(":");
                         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);
+                        }
+                    }
                 }
             }
             needSep = true;
@@ -8960,8 +8988,8 @@
                     if (!matcher.match(r, r.name)) {
                         continue;
                     }
-                    pw.print("  "); pw.print(e.getKey()); pw.print(": ");
-                            pw.println(r);
+                    pw.print("  "); pw.print(e.getKey()); pw.println(":");
+                    pw.print("    "); pw.println(r);
                 }
                 needSep = true;
             }
@@ -9345,16 +9373,20 @@
 
     final static class MemItem {
         final String label;
+        final String shortLabel;
         final long pss;
+        final int id;
         ArrayList<MemItem> subitems;
 
-        public MemItem(String _label, long _pss) {
+        public MemItem(String _label, String _shortLabel, long _pss, int _id) {
             label = _label;
+            shortLabel = _shortLabel;
             pss = _pss;
+            id = _id;
         }
     }
 
-    final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items,
+    static final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items,
             boolean sort) {
         if (sort) {
             Collections.sort(items, new Comparator<MemItem>() {
@@ -9372,16 +9404,56 @@
 
         for (int i=0; i<items.size(); i++) {
             MemItem mi = items.get(i);
-            pw.print(prefix); pw.printf("%7d Kb: ", mi.pss); pw.println(mi.label);
+            pw.print(prefix); pw.printf("%7d kB: ", mi.pss); pw.println(mi.label);
             if (mi.subitems != null) {
                 dumpMemItems(pw, prefix + "           ", mi.subitems, true);
             }
         }
     }
 
+    // These are in KB.
+    static final long[] DUMP_MEM_BUCKETS = new long[] {
+        5*1024, 7*1024, 10*1024, 15*1024, 20*1024, 30*1024, 40*1024, 80*1024,
+        120*1024, 160*1024, 200*1024,
+        250*1024, 300*1024, 350*1024, 400*1024, 500*1024, 600*1024, 800*1024,
+        1*1024*1024, 2*1024*1024, 5*1024*1024, 10*1024*1024, 20*1024*1024
+    };
+
+    static final void appendMemBucket(StringBuilder out, long memKB, String label) {
+        int start = label.lastIndexOf('.');
+        if (start >= 0) start++;
+        else start = 0;
+        int end = label.length();
+        for (int i=0; i<DUMP_MEM_BUCKETS.length; i++) {
+            if (DUMP_MEM_BUCKETS[i] >= memKB) {
+                long bucket = DUMP_MEM_BUCKETS[i]/1024;
+                out.append(bucket);
+                out.append("MB ");
+                out.append(label, start, end);
+                return;
+            }
+        }
+        out.append(memKB/1024);
+        out.append("MB ");
+        out.append(label, start, end);
+    }
+
+    static final int[] DUMP_MEM_OOM_ADJ = new int[] {
+            ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
+            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+            ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
+            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
+    };
+    static final String[] DUMP_MEM_OOM_LABEL = new String[] {
+            "System", "Persistent", "Foreground",
+            "Visible", "Perceptible", "Heavy Weight",
+            "Backup", "A Services", "Home", "Previous",
+            "B Services", "Background"
+    };
+
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args, boolean brief,
-            PrintWriter categoryPw) {
+            PrintWriter categoryPw, StringBuilder outTag) {
         boolean dumpAll = false;
         boolean oomOnly = false;
         
@@ -9437,20 +9509,9 @@
         long nativePss=0, dalvikPss=0, otherPss=0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
-        final int[] oomAdj = new int[] {
-            ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
-            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
-            ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
-            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ
-        };
-        final String[] oomLabel = new String[] {
-                "System", "Persistent", "Foreground",
-                "Visible", "Perceptible", "Heavy Weight",
-                "Backup", "A Services", "Home", "Previous",
-                "B Services", "Background"
-        };
-        long oomPss[] = new long[oomLabel.length];
-        ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])new ArrayList[oomLabel.length];
+        long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
+        ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
+                new ArrayList[DUMP_MEM_OOM_LABEL.length];
 
         long totalPss = 0;
 
@@ -9480,7 +9541,7 @@
                     long myTotalPss = mi.getTotalPss();
                     totalPss += myTotalPss;
                     MemItem pssItem = new MemItem(r.processName + " (pid " + r.pid + ")",
-                            myTotalPss);
+                            r.processName, myTotalPss, 0);
                     procMems.add(pssItem);
 
                     nativePss += mi.nativePss;
@@ -9493,7 +9554,8 @@
                     }
 
                     for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
-                        if (r.setAdj <= oomAdj[oomIndex] || oomIndex == (oomPss.length-1)) {
+                        if (r.setAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
+                                || oomIndex == (oomPss.length-1)) {
                             oomPss[oomIndex] += myTotalPss;
                             if (oomProcs[oomIndex] == null) {
                                 oomProcs[oomIndex] = new ArrayList<MemItem>();
@@ -9509,22 +9571,47 @@
         if (!isCheckinRequest && procs.size() > 1) {
             ArrayList<MemItem> catMems = new ArrayList<MemItem>();
 
-            catMems.add(new MemItem("Native", nativePss));
-            catMems.add(new MemItem("Dalvik", dalvikPss));
-            catMems.add(new MemItem("Unknown", otherPss));
+            catMems.add(new MemItem("Native", "Native", nativePss, -1));
+            catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, -2));
+            catMems.add(new MemItem("Unknown", "Unknown", otherPss, -3));
             for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
-                catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
+                String label = Debug.MemoryInfo.getOtherLabel(j);
+                catMems.add(new MemItem(label, label, miscPss[j], j));
             }
 
             ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
             for (int j=0; j<oomPss.length; j++) {
                 if (oomPss[j] != 0) {
-                    MemItem item = new MemItem(oomLabel[j], oomPss[j]);
+                    String label = DUMP_MEM_OOM_LABEL[j];
+                    MemItem item = new MemItem(label, label, oomPss[j],
+                            DUMP_MEM_OOM_ADJ[j]);
                     item.subitems = oomProcs[j];
                     oomMems.add(item);
                 }
             }
 
+            if (outTag != null) {
+                appendMemBucket(outTag, totalPss, "total");
+                for (int i=0; i<oomMems.size(); i++) {
+                    MemItem miCat = oomMems.get(i);
+                    if (miCat.subitems == null || miCat.subitems.size() < 1) {
+                        continue;
+                    }
+                    if (miCat.id < ProcessList.SERVICE_ADJ
+                            || miCat.id == ProcessList.HOME_APP_ADJ
+                            || miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
+                        outTag.append(" / ");
+                        for (int j=0; j<miCat.subitems.size(); j++) {
+                            MemItem mi = miCat.subitems.get(j);
+                            if (j > 0) {
+                                outTag.append(" ");
+                            }
+                            appendMemBucket(outTag, mi.pss, mi.shortLabel);
+                        }
+                    }
+                }
+            }
+
             if (!brief && !oomOnly) {
                 pw.println();
                 pw.println("Total PSS by process:");
@@ -9540,7 +9627,7 @@
                 dumpMemItems(out, "  ", catMems, true);
             }
             pw.println();
-            pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");
+            pw.print("Total PSS: "); pw.print(totalPss); pw.println(" kB");
         }
     }
 
@@ -14010,7 +14097,6 @@
         // application processes based on their current state.
         int i = mLruProcesses.size();
         int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
-        int numBg = 0;
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
@@ -14034,12 +14120,7 @@
                                 app.processName, app.setAdj, "too many background");
                         app.killedBackground = true;
                         Process.killProcessQuiet(app.pid);
-                    } else {
-                        numBg++;
                     }
-                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ
-                        && app.curAdj != ProcessList.SERVICE_B_ADJ) {
-                    numBg++;
                 }
             }
         }
@@ -14054,12 +14135,18 @@
         // memory they want.
         if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) {
             final int N = mLruProcesses.size();
-            factor = numBg/3;
+            factor = numHidden/3;
+            int minFactor = 2;
+            if (mHomeProcess != null) minFactor++;
+            if (mPreviousProcess != null) minFactor++;
+            if (factor < minFactor) factor = minFactor;
             step = 0;
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+                if (app.curAdj >= ProcessList.HOME_APP_ADJ
+                        && app.curAdj != ProcessList.SERVICE_B_ADJ
+                        && !app.killedBackground) {
                     if (app.trimMemoryLevel < curLevel && app.thread != null) {
                         try {
                             app.thread.scheduleTrimMemory(curLevel);
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 9c55597..38355537 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -73,12 +73,15 @@
                     pw.print("multiprocess="); pw.print(info.multiprocess);
                     pw.print(" initOrder="); pw.println(info.initOrder);
         }
-        if (clients.size() > 0) {
-            pw.print(prefix); pw.print("clients="); pw.println(clients);
-        }
         if (externals != 0) {
             pw.print(prefix); pw.print("externals="); pw.println(externals);
         }
+        if (clients.size() > 0) {
+            pw.print(prefix); pw.println("Clients:");
+            for (ProcessRecord cproc : clients) {
+                pw.print(prefix); pw.print("  - "); pw.println(cproc.toShortString());
+            }
+        }
     }
 
     public String toString() {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 6365525..28cb983 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -1243,7 +1243,8 @@
 
         // trim any history beyond max
         if (mTime.hasCache()) {
-            final long currentTime = mTime.currentTimeMillis();
+            final long currentTime = Math.min(
+                    System.currentTimeMillis(), mTime.currentTimeMillis());
             final long maxHistory = mSettings.getNetworkMaxHistory();
             for (NetworkStatsHistory history : input.values()) {
                 history.removeBucketsBefore(currentTime - maxHistory);
@@ -1287,7 +1288,8 @@
 
         // trim any history beyond max
         if (mTime.hasCache()) {
-            final long currentTime = mTime.currentTimeMillis();
+            final long currentTime = Math.min(
+                    System.currentTimeMillis(), mTime.currentTimeMillis());
             final long maxUidHistory = mSettings.getUidMaxHistory();
             final long maxTagHistory = mSettings.getTagMaxHistory();
             for (UidStatsKey key : mUidStats.keySet()) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index da6cf32..31d32d4 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5096,10 +5096,22 @@
 
             // Constrain thumbnail to smaller of screen width or height. Assumes aspect
             // of thumbnail is the same as the screen (in landscape) or square.
+            float targetWidthScale = width / (float) fw;
+            float targetHeightScale = height / (float) fh;
             if (dw <= dh) {
-                scale = width / (float) fw; // portrait
+                scale = targetWidthScale;
+                // If aspect of thumbnail is the same as the screen (in landscape),
+                // select the slightly larger value so we fill the entire bitmap
+                if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
+                    scale = targetHeightScale;
+                }
             } else {
-                scale = height / (float) fh; // landscape
+                scale = targetHeightScale;
+                // If aspect of thumbnail is the same as the screen (in landscape),
+                // select the slightly larger value so we fill the entire bitmap
+                if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
+                    scale = targetWidthScale;
+                }
             }
 
             // The screen shot will contain the entire screen.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 7e9fba8..f259883 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -98,6 +98,7 @@
     jfieldID mName;
     jfieldID mSources;
     jfieldID mKeyboardType;
+    jfieldID mKeyCharacterMapFile;
 } gInputDeviceClassInfo;
 
 static struct {
@@ -1231,10 +1232,16 @@
         return NULL;
     }
 
+    jstring fileStr = env->NewStringUTF(deviceInfo.getKeyCharacterMapFile());
+    if (!fileStr) {
+        return NULL;
+    }
+
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId());
     env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj);
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
+    env->SetObjectField(deviceObj, gInputDeviceClassInfo.mKeyCharacterMapFile, fileStr);
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -1516,6 +1523,9 @@
     GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz,
             "mKeyboardType", "I");
 
+    GET_FIELD_ID(gInputDeviceClassInfo.mKeyCharacterMapFile, gInputDeviceClassInfo.clazz,
+            "mKeyCharacterMapFile", "Ljava/lang/String;");
+
     // Configuration
 
     FIND_CLASS(clazz, "android/content/res/Configuration");
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 329c052..f94d321 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -284,22 +284,6 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
-
-#ifdef EGL_ANDROID_swap_rectangle
-    if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
-        if (eglSetSwapRectangleANDROID(display, surface,
-                0, 0, mWidth, mHeight) == EGL_TRUE) {
-            // This could fail if this extension is not supported by this
-            // specific surface (of config)
-            mFlags |= SWAP_RECTANGLE;
-        }
-    }
-    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
-    // choose PARTIAL_UPDATES, which should be more efficient
-    if (mFlags & PARTIAL_UPDATES)
-        mFlags &= ~SWAP_RECTANGLE;
-#endif
-
     LOGI("EGL informations:");
     LOGI("# of configs : %d", numConfigs);
     LOGI("vendor    : %s", extensions.getEglVendor());
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 368595f..0618374 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -80,7 +80,6 @@
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
-import org.easymock.IExpectationSetters;
 
 import java.io.File;
 import java.util.LinkedHashSet;
@@ -537,6 +536,7 @@
                 .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
         expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
                 .andReturn(stats).atLeastOnce();
+        expectPolicyDataEnable(TYPE_WIFI, true);
 
         // TODO: consider making strongly ordered mock
         expectRemoveInterfaceQuota(TEST_IFACE);
@@ -580,7 +580,7 @@
         NetworkState[] state = null;
         NetworkStats stats = null;
         Future<Void> future;
-        Capture<String> tag;
+        Future<String> tagFuture;
 
         final long TIME_FEB_15 = 1171497600000L;
         final long TIME_MAR_10 = 1173484800000L;
@@ -598,6 +598,7 @@
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
             expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
                     .andReturn(stats).atLeastOnce();
+            expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectClearNotifications();
             future = expectMeteredIfacesChanged();
@@ -620,6 +621,7 @@
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
             expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
                     .andReturn(stats).atLeastOnce();
+            expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectRemoveInterfaceQuota(TEST_IFACE);
             expectSetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES);
@@ -642,14 +644,15 @@
             expectCurrentTime();
             expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
                     .andReturn(stats).atLeastOnce();
+            expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectForceUpdate();
             expectClearNotifications();
-            tag = expectEnqueueNotification();
+            tagFuture = expectEnqueueNotification();
 
             replay();
             mNetworkObserver.limitReached(null, TEST_IFACE);
-            assertNotificationType(TYPE_WARNING, tag.getValue());
+            assertNotificationType(TYPE_WARNING, tagFuture.get());
             verifyAndReset();
         }
 
@@ -662,15 +665,15 @@
             expectCurrentTime();
             expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
                     .andReturn(stats).atLeastOnce();
-            expectPolicyDataEnable(TYPE_WIFI, false).atLeastOnce();
+            expectPolicyDataEnable(TYPE_WIFI, false);
 
             expectForceUpdate();
             expectClearNotifications();
-            tag = expectEnqueueNotification();
+            tagFuture = expectEnqueueNotification();
 
             replay();
             mNetworkObserver.limitReached(null, TEST_IFACE);
-            assertNotificationType(TYPE_LIMIT, tag.getValue());
+            assertNotificationType(TYPE_LIMIT, tagFuture.get());
             verifyAndReset();
         }
 
@@ -682,21 +685,20 @@
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
             expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
                     .andReturn(stats).atLeastOnce();
-            expectPolicyDataEnable(TYPE_WIFI, true).atLeastOnce();
+            expectPolicyDataEnable(TYPE_WIFI, true);
 
             // snoozed interface still has high quota so background data is
             // still restricted.
             expectRemoveInterfaceQuota(TEST_IFACE);
             expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
+            expectMeteredIfacesChanged(TEST_IFACE);
 
             expectClearNotifications();
-            tag = expectEnqueueNotification();
-            future = expectMeteredIfacesChanged(TEST_IFACE);
+            tagFuture = expectEnqueueNotification();
 
             replay();
             mService.snoozePolicy(sTemplateWifi);
-            future.get();
-            assertNotificationType(TYPE_LIMIT_SNOOZED, tag.getValue());
+            assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
             verifyAndReset();
         }
     }
@@ -737,9 +739,9 @@
         expectLastCall().anyTimes();
     }
 
-    private Capture<String> expectEnqueueNotification() throws Exception {
-        final Capture<String> tag = new Capture<String>();
-        mNotifManager.enqueueNotificationWithTag(isA(String.class), capture(tag), anyInt(),
+    private Future<String> expectEnqueueNotification() throws Exception {
+        final FutureCapture<String> tag = new FutureCapture<String>();
+        mNotifManager.enqueueNotificationWithTag(isA(String.class), capture(tag.capture), anyInt(),
                 isA(Notification.class), isA(int[].class));
         return tag;
     }
@@ -789,22 +791,25 @@
         return future;
     }
 
-    private <T> IExpectationSetters<T> expectPolicyDataEnable(int type, boolean enabled)
-            throws Exception {
+    private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception {
+        final FutureAnswer future = new FutureAnswer();
         mConnManager.setPolicyDataEnable(type, enabled);
-        return expectLastCall();
+        expectLastCall().andAnswer(future);
+        return future;
     }
 
-    private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> {
+    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
         @Override
-        public Void get() throws InterruptedException, ExecutionException {
+        public T get() throws InterruptedException, ExecutionException {
             try {
                 return get(5, TimeUnit.SECONDS);
             } catch (TimeoutException e) {
                 throw new RuntimeException(e);
             }
         }
+    }
 
+    private static class FutureAnswer extends TestAbstractFuture<Void> implements IAnswer<Void> {
         @Override
         public Void answer() {
             set(null);
@@ -812,6 +817,16 @@
         }
     }
 
+    private static class FutureCapture<T> extends TestAbstractFuture<T> {
+        public Capture<T> capture = new Capture<T>() {
+            @Override
+            public void setValue(T value) {
+                super.setValue(value);
+                set(value);
+            }
+        };
+    }
+
     private static class IdleFuture extends AbstractFuture<Void> implements IdleHandler {
         @Override
         public Void get() throws InterruptedException, ExecutionException {
diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java
index 9492e0e..c32388f 100644
--- a/telephony/java/com/android/internal/telephony/SmsHeader.java
+++ b/telephony/java/com/android/internal/telephony/SmsHeader.java
@@ -190,7 +190,9 @@
     public static byte[] toByteArray(SmsHeader smsHeader) {
         if ((smsHeader.portAddrs == null) &&
             (smsHeader.concatRef == null) &&
-            (smsHeader.miscEltList.size() == 0)) {
+            (smsHeader.miscEltList.isEmpty()) &&
+            (smsHeader.languageShiftTable == 0) &&
+            (smsHeader.languageTable == 0)) {
             return null;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index d29e488..8a75f51 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -239,7 +239,11 @@
             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, destPort, data, (deliveryIntent != null));
-        sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        if (pdu != null) {
+            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        } else {
+            Log.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null");
+        }
     }
 
     /** {@inheritDoc} */
@@ -248,7 +252,11 @@
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, text, (deliveryIntent != null));
-        sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        if (pdu != null) {
+            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        } else {
+            Log.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
+        }
     }
 
     /** {@inheritDoc} */
@@ -266,7 +274,11 @@
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
                 message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
                 encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
-        sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        if (pdu != null) {
+            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
+        } else {
+            Log.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");
+        }
     }
 
     /** {@inheritDoc} */
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 677923f..da60584 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -16,22 +16,22 @@
 
 package com.android.internal.telephony.gsm;
 
-import android.os.Parcel;
 import android.telephony.PhoneNumberUtils;
 import android.text.format.Time;
 import android.util.Log;
-import com.android.internal.telephony.IccUtils;
+
 import com.android.internal.telephony.EncodeException;
 import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
 
 import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
 
+import static android.telephony.SmsMessage.ENCODING_16BIT;
 import static android.telephony.SmsMessage.ENCODING_7BIT;
 import static android.telephony.SmsMessage.ENCODING_8BIT;
-import static android.telephony.SmsMessage.ENCODING_16BIT;
 import static android.telephony.SmsMessage.ENCODING_KSC5601;
 import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
 import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
@@ -240,18 +240,43 @@
             return null;
         }
 
+        if (encoding == ENCODING_UNKNOWN) {
+            // Find the best encoding to use
+            TextEncodingDetails ted = calculateLength(message, false);
+            encoding = ted.codeUnitSize;
+            languageTable = ted.languageTable;
+            languageShiftTable = ted.languageShiftTable;
+
+            if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) {
+                if (header != null) {
+                    SmsHeader smsHeader = SmsHeader.fromByteArray(header);
+                    if (smsHeader.languageTable != languageTable
+                            || smsHeader.languageShiftTable != languageShiftTable) {
+                        Log.w(LOG_TAG, "Updating language table in SMS header: "
+                                + smsHeader.languageTable + " -> " + languageTable + ", "
+                                + smsHeader.languageShiftTable + " -> " + languageShiftTable);
+                        smsHeader.languageTable = languageTable;
+                        smsHeader.languageShiftTable = languageShiftTable;
+                        header = SmsHeader.toByteArray(smsHeader);
+                    }
+                } else {
+                    SmsHeader smsHeader = new SmsHeader();
+                    smsHeader.languageTable = languageTable;
+                    smsHeader.languageShiftTable = languageShiftTable;
+                    header = SmsHeader.toByteArray(smsHeader);
+                }
+            }
+        }
+
         SubmitPdu ret = new SubmitPdu();
         // MTI = SMS-SUBMIT, UDHI = header != null
         byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
         ByteArrayOutputStream bo = getSubmitPduHead(
                 scAddress, destinationAddress, mtiByte,
                 statusReportRequested, ret);
+
         // User Data (and length)
         byte[] userData;
-        if (encoding == ENCODING_UNKNOWN) {
-            // First, try encoding it with the GSM alphabet
-            encoding = ENCODING_7BIT;
-        }
         try {
             if (encoding == ENCODING_7BIT) {
                 userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
@@ -283,6 +308,7 @@
         if (encoding == ENCODING_7BIT) {
             if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
                 // Message too long
+                Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
                 return null;
             }
             // TP-Data-Coding-Scheme
@@ -297,6 +323,7 @@
         } else { // assume UCS-2
             if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
                 // Message too long
+                Log.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
                 return null;
             }
             // TP-Data-Coding-Scheme