Add OpenGL backend to ImageWallpaper
Bug #5204874

Currently disabled.

Change-Id: I5e7b35dce2981b0691f107e39c6394b260466543
diff --git a/api/current.txt b/api/current.txt
index 8a643fd..e432436 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13947,6 +13947,7 @@
   }
 
   public final class GLUtils {
+    method public static java.lang.String getEGLErrorString(int);
     method public static int getInternalFormat(android.graphics.Bitmap);
     method public static int getType(android.graphics.Bitmap);
     method public static void texImage2D(int, int, int, android.graphics.Bitmap, int);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index ff04757..f81ea81 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -107,19 +107,22 @@
         private final int mHeight;
         private int mDrawLeft;
         private int mDrawTop;
+        private final Paint mPaint;
 
         private FastBitmapDrawable(Bitmap bitmap) {
             mBitmap = bitmap;
             mWidth = bitmap.getWidth();
             mHeight = bitmap.getHeight();
+
             setBounds(0, 0, mWidth, mHeight);
+
+            mPaint = new Paint();
+            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
         }
 
         @Override
         public void draw(Canvas canvas) {
-            Paint paint = new Paint();
-            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, paint);
+            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, mPaint);
         }
 
         @Override
@@ -134,33 +137,23 @@
         }
 
         @Override
-        public void setBounds(Rect bounds) {
-            // TODO Auto-generated method stub
-            super.setBounds(bounds);
-        }
-
-        @Override
         public void setAlpha(int alpha) {
-            throw new UnsupportedOperationException(
-                    "Not supported with this drawable");
+            throw new UnsupportedOperationException("Not supported with this drawable");
         }
 
         @Override
         public void setColorFilter(ColorFilter cf) {
-            throw new UnsupportedOperationException(
-                    "Not supported with this drawable");
+            throw new UnsupportedOperationException("Not supported with this drawable");
         }
 
         @Override
         public void setDither(boolean dither) {
-            throw new UnsupportedOperationException(
-                    "Not supported with this drawable");
+            throw new UnsupportedOperationException("Not supported with this drawable");
         }
 
         @Override
         public void setFilterBitmap(boolean filter) {
-            throw new UnsupportedOperationException(
-                    "Not supported with this drawable");
+            throw new UnsupportedOperationException("Not supported with this drawable");
         }
 
         @Override
@@ -230,7 +223,7 @@
                 }
                 mWallpaper = null;
                 try {
-                    mWallpaper = getCurrentWallpaperLocked(context);
+                    mWallpaper = getCurrentWallpaperLocked();
                 } catch (OutOfMemoryError e) {
                     Log.w(TAG, "No memory load current wallpaper", e);
                 }
@@ -253,7 +246,7 @@
             }
         }
 
-        private Bitmap getCurrentWallpaperLocked(Context context) {
+        private Bitmap getCurrentWallpaperLocked() {
             try {
                 Bundle params = new Bundle();
                 ParcelFileDescriptor fd = mService.getWallpaper(this, params);
@@ -265,17 +258,19 @@
                         BitmapFactory.Options options = new BitmapFactory.Options();
                         Bitmap bm = BitmapFactory.decodeFileDescriptor(
                                 fd.getFileDescriptor(), null, options);
-                        return generateBitmap(context, bm, width, height);
+                        return generateBitmap(bm, width, height);
                     } catch (OutOfMemoryError e) {
                         Log.w(TAG, "Can't decode file", e);
                     } finally {
                         try {
                             fd.close();
                         } catch (IOException e) {
+                            // Ignore
                         }
                     }
                 }
             } catch (RemoteException e) {
+                // Ignore
             }
             return null;
         }
@@ -291,27 +286,29 @@
                     try {
                         BitmapFactory.Options options = new BitmapFactory.Options();
                         Bitmap bm = BitmapFactory.decodeStream(is, null, options);
-                        return generateBitmap(context, bm, width, height);
+                        return generateBitmap(bm, width, height);
                     } catch (OutOfMemoryError e) {
                         Log.w(TAG, "Can't decode stream", e);
                     } finally {
                         try {
                             is.close();
                         } catch (IOException e) {
+                            // Ignore
                         }
                     }
                 }
             } catch (RemoteException e) {
+                // Ignore
             }
             return null;
         }
     }
     
-    private static Object mSync = new Object();
+    private static final Object sSync = new Object[0];
     private static Globals sGlobals;
 
     static void initGlobals(Looper looper) {
-        synchronized (mSync) {
+        synchronized (sSync) {
             if (sGlobals == null) {
                 sGlobals = new Globals(looper);
             }
@@ -390,8 +387,7 @@
     public Drawable getFastDrawable() {
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);
         if (bm != null) {
-            Drawable dr = new FastBitmapDrawable(bm);
-            return dr;
+            return new FastBitmapDrawable(bm);
         }
         return null;
     }
@@ -406,13 +402,21 @@
     public Drawable peekFastDrawable() {
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
         if (bm != null) {
-            Drawable dr = new FastBitmapDrawable(bm);
-            return dr;
+            return new FastBitmapDrawable(bm);
         }
         return null;
     }
 
     /**
+     * Like {@link #getDrawable()} but returns a Bitmap.
+     * 
+     * @hide
+     */
+    public Bitmap getBitmap() {
+        return sGlobals.peekWallpaperBitmap(mContext, true);
+    }
+
+    /**
      * Remove all internal references to the last loaded wallpaper.  Useful
      * for apps that want to reduce memory usage when they only temporarily
      * need to have the wallpaper.  After calling, the next request for the
@@ -464,6 +468,7 @@
                 }
             }
         } catch (RemoteException e) {
+            // Ignore
         }
     }
     
@@ -493,6 +498,7 @@
                 }
             }
         } catch (RemoteException e) {
+            // Ignore
         }
     }
 
@@ -524,6 +530,7 @@
                 }
             }
         } catch (RemoteException e) {
+            // Ignore
         }
     }
 
@@ -594,6 +601,7 @@
         try {
             sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
         } catch (RemoteException e) {
+            // Ignore
         }
     }
     
@@ -690,7 +698,7 @@
         setResource(com.android.internal.R.drawable.default_wallpaper);
     }
     
-    static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
+    static Bitmap generateBitmap(Bitmap bm, int width, int height) {
         if (bm == null) {
             return null;
         }
@@ -717,7 +725,7 @@
 
             if (deltaw > 0 || deltah > 0) {
                 // We need to scale up so it covers the entire area.
-                float scale = 1.0f;
+                float scale;
                 if (deltaw > deltah) {
                     scale = width / (float)targetRect.right;
                 } else {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a05637d..926d424 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -21,6 +21,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -402,51 +403,6 @@
         }
 
         /**
-         * Return a string for the EGL error code, or the hex representation
-         * if the error is unknown.
-         * 
-         * @param error The EGL error to convert into a String.
-         * 
-         * @return An error string correponding to the EGL error code.
-         */
-        static String getEGLErrorString(int error) {
-            switch (error) {
-                case EGL_SUCCESS:
-                    return "EGL_SUCCESS";
-                case EGL_NOT_INITIALIZED:
-                    return "EGL_NOT_INITIALIZED";
-                case EGL_BAD_ACCESS:
-                    return "EGL_BAD_ACCESS";
-                case EGL_BAD_ALLOC:
-                    return "EGL_BAD_ALLOC";
-                case EGL_BAD_ATTRIBUTE:
-                    return "EGL_BAD_ATTRIBUTE";
-                case EGL_BAD_CONFIG:
-                    return "EGL_BAD_CONFIG";
-                case EGL_BAD_CONTEXT:
-                    return "EGL_BAD_CONTEXT";
-                case EGL_BAD_CURRENT_SURFACE:
-                    return "EGL_BAD_CURRENT_SURFACE";
-                case EGL_BAD_DISPLAY:
-                    return "EGL_BAD_DISPLAY";
-                case EGL_BAD_MATCH:
-                    return "EGL_BAD_MATCH";
-                case EGL_BAD_NATIVE_PIXMAP:
-                    return "EGL_BAD_NATIVE_PIXMAP";
-                case EGL_BAD_NATIVE_WINDOW:
-                    return "EGL_BAD_NATIVE_WINDOW";
-                case EGL_BAD_PARAMETER:
-                    return "EGL_BAD_PARAMETER";
-                case EGL_BAD_SURFACE:
-                    return "EGL_BAD_SURFACE";
-                case EGL11.EGL_CONTEXT_LOST:
-                    return "EGL_CONTEXT_LOST";
-                default:
-                    return "0x" + Integer.toHexString(error);
-            }
-        }
-
-        /**
          * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
          * is invoked and the requested flag is turned off. The error code is
          * also logged as a warning.
@@ -458,7 +414,7 @@
                     // something bad has happened revert to
                     // normal rendering.
                     fallback(error != EGL11.EGL_CONTEXT_LOST);
-                    Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error));
+                    Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
                 }
             }
         }
@@ -523,14 +479,14 @@
                     
                     if (sEglDisplay == EGL_NO_DISPLAY) {
                         throw new RuntimeException("eglGetDisplay failed "
-                                + getEGLErrorString(sEgl.eglGetError()));
+                                + GLUtils.getEGLErrorString(sEgl.eglGetError()));
                     }
                     
                     // We can now initialize EGL for that display
                     int[] version = new int[2];
                     if (!sEgl.eglInitialize(sEglDisplay, version)) {
                         throw new RuntimeException("eglInitialize failed " +
-                                getEGLErrorString(sEgl.eglGetError()));
+                                GLUtils.getEGLErrorString(sEgl.eglGetError()));
                     }
         
                     sEglConfig = chooseEglConfig();
@@ -579,7 +535,7 @@
 
             if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
                 throw new IllegalArgumentException("eglChooseConfig failed " +
-                        getEGLErrorString(sEgl.eglGetError()));
+                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
             } else if (configsCount[0] > 0) {
                 if ("choice".equalsIgnoreCase(debug)) {
                     printConfig(configs[0]);
@@ -647,7 +603,7 @@
              */
             if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                 throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
-                        + getEGLErrorString(sEgl.eglGetError()));
+                        + GLUtils.getEGLErrorString(sEgl.eglGetError()));
             }
 
             // If mDirtyRegions is set, this means we have an EGL configuration
@@ -734,7 +690,7 @@
                     return false;
                 }
                 throw new RuntimeException("createWindowSurface failed "
-                        + getEGLErrorString(error));
+                        + GLUtils.getEGLErrorString(error));
             }
             return true;
         }
@@ -856,7 +812,7 @@
                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                     fallback(true);
                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
-                            getEGLErrorString(sEgl.eglGetError()));
+                            GLUtils.getEGLErrorString(sEgl.eglGetError()));
                     return SURFACE_STATE_ERROR;
                 } else {
                     return SURFACE_STATE_UPDATED;
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index f30a4cd4..125c56e 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -16,9 +16,11 @@
 
 package android.opengl;
 
-import javax.microedition.khronos.opengles.GL10;
 import android.graphics.Bitmap;
 
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+
 /**
  *
  * Utility class to help bridging OpenGL ES and Android APIs.
@@ -222,6 +224,51 @@
         }
     }
 
+    /**
+     * Return a string for the EGL error code, or the hex representation
+     * if the error is unknown.
+     * 
+     * @param error The EGL error to convert into a String.
+     * 
+     * @return An error string corresponding to the EGL error code.
+     */
+    public static String getEGLErrorString(int error) {
+        switch (error) {
+            case EGL10.EGL_SUCCESS:
+                return "EGL_SUCCESS";
+            case EGL10.EGL_NOT_INITIALIZED:
+                return "EGL_NOT_INITIALIZED";
+            case EGL10.EGL_BAD_ACCESS:
+                return "EGL_BAD_ACCESS";
+            case EGL10.EGL_BAD_ALLOC:
+                return "EGL_BAD_ALLOC";
+            case EGL10.EGL_BAD_ATTRIBUTE:
+                return "EGL_BAD_ATTRIBUTE";
+            case EGL10.EGL_BAD_CONFIG:
+                return "EGL_BAD_CONFIG";
+            case EGL10.EGL_BAD_CONTEXT:
+                return "EGL_BAD_CONTEXT";
+            case EGL10.EGL_BAD_CURRENT_SURFACE:
+                return "EGL_BAD_CURRENT_SURFACE";
+            case EGL10.EGL_BAD_DISPLAY:
+                return "EGL_BAD_DISPLAY";
+            case EGL10.EGL_BAD_MATCH:
+                return "EGL_BAD_MATCH";
+            case EGL10.EGL_BAD_NATIVE_PIXMAP:
+                return "EGL_BAD_NATIVE_PIXMAP";
+            case EGL10.EGL_BAD_NATIVE_WINDOW:
+                return "EGL_BAD_NATIVE_WINDOW";
+            case EGL10.EGL_BAD_PARAMETER:
+                return "EGL_BAD_PARAMETER";
+            case EGL10.EGL_BAD_SURFACE:
+                return "EGL_BAD_SURFACE";
+            case EGL11.EGL_CONTEXT_LOST:
+                return "EGL_CONTEXT_LOST";
+            default:
+                return "0x" + Integer.toHexString(error);
+        }
+    }
+
     native private static void nativeClassInit();
 
     native private static int native_getInternalFormat(Bitmap bitmap);
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index e1231a5..5a3850d 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -16,41 +16,65 @@
 
 package com.android.systemui;
 
-import java.io.IOException;
-
+import android.app.ActivityManager;
 import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.Region.Op;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
+import android.opengl.GLUtils;
+import android.renderscript.Matrix4f;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
-import android.util.Slog;
+import android.view.Display;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
-import android.content.Context;
-import android.content.IntentFilter;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
+import android.view.WindowManager;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import static android.opengl.GLES20.*;
+import static javax.microedition.khronos.egl.EGL10.*;
 
 /**
  * Default built-in wallpaper that simply shows a static image.
  */
+@SuppressWarnings({"UnusedDeclaration"})
 public class ImageWallpaper extends WallpaperService {
     private static final String TAG = "ImageWallpaper";
+    private static final String GL_LOG_TAG = "ImageWallpaperGL";
     private static final boolean DEBUG = false;
 
     static final boolean FIXED_SIZED_SURFACE = true;
+    static final boolean USE_OPENGL = false;
 
     WallpaperManager mWallpaperManager;
-    private Handler mHandler;
+
+    boolean mIsHwAccelerated;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
-        mHandler = new Handler();
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (FIXED_SIZED_SURFACE && USE_OPENGL) {
+            WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+            Display display = windowManager.getDefaultDisplay();
+            mIsHwAccelerated = ActivityManager.isHighEndGfx(display);
+        }
     }
 
     public Engine onCreateEngine() {
@@ -58,9 +82,16 @@
     }
 
     class DrawableEngine extends Engine {
-        private final Object mLock = new Object();
+        static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        static final int EGL_OPENGL_ES2_BIT = 4;
+
+        private final Object mLock = new Object[0];
+
+        // TODO: Not currently used, keeping around until we know we don't need it
+        @SuppressWarnings({"UnusedDeclaration"})
         private WallpaperObserver mReceiver;
-        Drawable mBackground;
+
+        Bitmap mBackground;
         int mBackgroundWidth = -1, mBackgroundHeight = -1;
         float mXOffset;
         float mYOffset;
@@ -71,6 +102,35 @@
         int mLastXTranslation;
         int mLastYTranslation;
 
+        private EGL10 mEgl;
+        private EGLDisplay mEglDisplay;
+        private EGLConfig mEglConfig;
+        private EGLContext mEglContext;
+        private EGLSurface mEglSurface;
+        private GL mGL;
+
+        private static final String sSimpleVS =
+                "attribute vec4 position;\n" +
+                "attribute vec2 texCoords;\n" +
+                "varying vec2 outTexCoords;\n" +
+                "uniform mat4 projection;\n" +
+                "\nvoid main(void) {\n" +
+                "    outTexCoords = texCoords;\n" +
+                "    gl_Position = projection * position;\n" +
+                "}\n\n";
+        private static final String sSimpleFS =
+                "precision mediump float;\n\n" +
+                "varying vec2 outTexCoords;\n" +
+                "uniform sampler2D texture;\n" +
+                "\nvoid main(void) {\n" +
+                "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
+                "}\n\n";
+    
+        private static final int FLOAT_SIZE_BYTES = 4;
+        private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+        private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+        private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+
         class WallpaperObserver extends BroadcastReceiver {
             public void onReceive(Context context, Intent intent) {
                 if (DEBUG) {
@@ -94,7 +154,7 @@
 
             super.onCreate(surfaceHolder);
             
-            // Don't need this currently because the wallpaper service
+            // TODO: Don't need this currently because the wallpaper service
             // will restart the image wallpaper whenever the image changes.
             //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
             //mReceiver = new WallpaperObserver();
@@ -221,8 +281,7 @@
             int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);
 
             mOffsetsChanged = false;
-            if (!mRedrawNeeded
-                    && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
+            if (!mRedrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
                 if (DEBUG) {
                     Log.d(TAG, "Suppressed drawFrame since the image has not "
                             + "actually moved an integral number of pixels.");
@@ -240,27 +299,10 @@
                 updateWallpaperLocked();
             }
 
-            //Slog.i(TAG, "************** DRAWING WALLAPER ******************");
-            Canvas c = sh.lockCanvas();
-            if (c != null) {
-                try {
-                    if (DEBUG) {
-                        Log.d(TAG, "Redrawing: xPixels=" + xPixels + ", yPixels=" + yPixels);
-                    }
-
-                    c.translate(xPixels, yPixels);
-                    if (availw < 0 || availh < 0) {
-                        c.save(Canvas.CLIP_SAVE_FLAG);
-                        c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE);
-                        c.drawColor(0xff000000);
-                        c.restore();
-                    }
-                    if (mBackground != null) {
-                        mBackground.draw(c);
-                    }
-                } finally {
-                    sh.unlockCanvasAndPost(c);
-                }
+            if (mIsHwAccelerated) {
+                drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels);
+            } else {
+                drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
             }
 
             if (FIXED_SIZED_SURFACE) {
@@ -274,15 +316,15 @@
         }
 
         void updateWallpaperLocked() {
-            //Slog.i(TAG, "************** LOADING WALLAPER ******************");
             Throwable exception = null;
             try {
-                mBackground = mWallpaperManager.getFastDrawable();
+                mBackground = mWallpaperManager.getBitmap();
             } catch (RuntimeException e) {
                 exception = e;
             } catch (OutOfMemoryError e) {
                 exception = e;
             }
+
             if (exception != null) {
                 mBackground = null;
                 // Note that if we do fail at this, and the default wallpaper can't
@@ -296,8 +338,277 @@
                     Log.w(TAG, "Unable reset to default wallpaper!", ex);
                 }
             }
-            mBackgroundWidth = mBackground != null ? mBackground.getIntrinsicWidth() : 0;
-            mBackgroundHeight = mBackground != null ? mBackground.getIntrinsicHeight() : 0;
+
+            mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0;
+            mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0;
+        }
+
+        private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) {
+            Canvas c = sh.lockCanvas();
+            if (c != null) {
+                try {
+                    if (DEBUG) {
+                        Log.d(TAG, "Redrawing: x=" + x + ", y=" + y);
+                    }
+
+                    c.translate(x, y);
+                    if (w < 0 || h < 0) {
+                        c.save(Canvas.CLIP_SAVE_FLAG);
+                        c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE);
+                        c.drawColor(0xff000000);
+                        c.restore();
+                    }
+                    if (mBackground != null) {
+                        c.drawBitmap(mBackground, 0, 0, null);
+                    }
+                } finally {
+                    sh.unlockCanvasAndPost(c);
+                }
+            }
+        }
+
+        private void drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
+            initGL(sh);
+
+            final float right = left + mBackgroundWidth;
+            final float bottom = top + mBackgroundHeight;
+
+            final Rect frame = sh.getSurfaceFrame();
+
+            final Matrix4f ortho = new Matrix4f();
+            ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
+
+            final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
+
+            final int texture = loadTexture(mBackground);
+            final int program = buildProgram(sSimpleVS, sSimpleFS);
+    
+            final int attribPosition = glGetAttribLocation(program, "position");
+            final int attribTexCoords = glGetAttribLocation(program, "texCoords");
+            final int uniformTexture = glGetUniformLocation(program, "texture");
+            final int uniformProjection = glGetUniformLocation(program, "projection");
+
+            checkGlError();
+
+            glViewport(0, 0, frame.width(), frame.height());
+            glBindTexture(GL_TEXTURE_2D, texture);
+
+            glUseProgram(program);
+            glEnableVertexAttribArray(attribPosition);
+            glEnableVertexAttribArray(attribTexCoords);
+            glUniform1i(uniformTexture, 0);
+            glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
+
+            checkGlError();
+
+            if (w < 0 || h < 0) {
+                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+            }
+    
+            // drawQuad
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+            glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+            glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+
+            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    
+            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                throw new RuntimeException("Cannot swap buffers");
+            }
+            checkEglError();
+    
+            finishGL();
+        }
+
+        private FloatBuffer createMesh(int left, int top, float right, float bottom) {
+            final float[] verticesData = {
+                    // X, Y, Z, U, V
+                     left,  bottom, 0.0f, 0.0f, 1.0f,
+                     right, bottom, 0.0f, 1.0f, 1.0f,
+                     left,  top,    0.0f, 0.0f, 0.0f,
+                     right, top,    0.0f, 1.0f, 0.0f,
+            };
+
+            final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
+            final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
+                    ByteOrder.nativeOrder()).asFloatBuffer();
+            triangleVertices.put(verticesData).position(0);
+            return triangleVertices;
+        }
+
+        private int loadTexture(Bitmap bitmap) {
+            int[] textures = new int[1];
+    
+            glActiveTexture(GL_TEXTURE0);
+            glGenTextures(1, textures, 0);
+            checkGlError();
+    
+            int texture = textures[0];
+            glBindTexture(GL_TEXTURE_2D, texture);
+            checkGlError();
+            
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+            GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
+            checkGlError();
+
+            bitmap.recycle();
+    
+            return texture;
+        }
+        
+        private int buildProgram(String vertex, String fragment) {
+            int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+            if (vertexShader == 0) return 0;
+    
+            int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+            if (fragmentShader == 0) return 0;
+    
+            int program = glCreateProgram();
+            glAttachShader(program, vertexShader);
+            checkGlError();
+    
+            glAttachShader(program, fragmentShader);
+            checkGlError();
+    
+            glLinkProgram(program);
+            checkGlError();
+    
+            int[] status = new int[1];
+            glGetProgramiv(program, GL_LINK_STATUS, status, 0);
+            if (status[0] != GL_TRUE) {
+                String error = glGetProgramInfoLog(program);
+                Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
+                glDeleteShader(vertexShader);
+                glDeleteShader(fragmentShader);
+                glDeleteProgram(program);
+                return 0;
+            }
+    
+            return program;
+        }
+        
+        private int buildShader(String source, int type) {
+            int shader = glCreateShader(type);
+    
+            glShaderSource(shader, source);
+            checkGlError();
+    
+            glCompileShader(shader);
+            checkGlError();
+    
+            int[] status = new int[1];
+            glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
+            if (status[0] != GL_TRUE) {
+                String error = glGetShaderInfoLog(shader);
+                Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
+                glDeleteShader(shader);
+                return 0;
+            }
+            
+            return shader;
+        }
+    
+        private void checkEglError() {
+            int error = mEgl.eglGetError();
+            if (error != EGL_SUCCESS) {
+                Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error));
+            }
+        }
+    
+        private void checkGlError() {
+            int error = glGetError();
+            if (error != GL_NO_ERROR) {
+                Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable());
+            }
+        }
+    
+        private void finishGL() {
+            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+        }
+        
+        private void initGL(SurfaceHolder surfaceHolder) {
+            mEgl = (EGL10) EGLContext.getEGL();
+    
+            mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+            if (mEglDisplay == EGL_NO_DISPLAY) {
+                throw new RuntimeException("eglGetDisplay failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+            
+            int[] version = new int[2];
+            if (!mEgl.eglInitialize(mEglDisplay, version)) {
+                throw new RuntimeException("eglInitialize failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+    
+            mEglConfig = chooseEglConfig();
+            if (mEglConfig == null) {
+                throw new RuntimeException("eglConfig not initialized");
+            }
+            
+            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+    
+            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
+    
+            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
+                int error = mEgl.eglGetError();
+                if (error == EGL_BAD_NATIVE_WINDOW) {
+                    Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                    return;
+                }
+                throw new RuntimeException("createWindowSurface failed " +
+                        GLUtils.getEGLErrorString(error));
+            }
+    
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+    
+            mGL = mEglContext.getGL();
+        }
+        
+    
+        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+            return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);            
+        }
+    
+        private EGLConfig chooseEglConfig() {
+            int[] configsCount = new int[1];
+            EGLConfig[] configs = new EGLConfig[1];
+            int[] configSpec = getConfig();
+            if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+                throw new IllegalArgumentException("eglChooseConfig failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            } else if (configsCount[0] > 0) {
+                return configs[0];
+            }
+            return null;
+        }
+
+        private int[] getConfig() {
+            return new int[] {
+                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                    EGL_RED_SIZE, 8,
+                    EGL_GREEN_SIZE, 8,
+                    EGL_BLUE_SIZE, 8,
+                    EGL_ALPHA_SIZE, 0,
+                    EGL_DEPTH_SIZE, 0,
+                    EGL_STENCIL_SIZE, 0,
+                    EGL_NONE
+            };
         }
     }
 }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 9765f2a..565063a 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -75,7 +75,7 @@
     static final String TAG = "WallpaperService";
     static final boolean DEBUG = false;
 
-    Object mLock = new Object();
+    final Object mLock = new Object[0];
 
     /**
      * Minimum time between crashes of a wallpaper service for us to consider
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index e77178d..3232eedc 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -33,7 +33,6 @@
 import android.widget.FrameLayout;
 
 import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.egl.EGLContext;
 import javax.microedition.khronos.egl.EGLDisplay;
@@ -207,7 +206,7 @@
             glEnableVertexAttribArray(attribTexCoords);
             checkGlError();
 
-            glUniform1i(texture, 0);
+            glUniform1i(uniformTexture, texture);
             checkGlError();
             
             while (!mFinished) {
@@ -350,7 +349,7 @@
                     !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
                 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                     throw new RuntimeException("eglMakeCurrent failed "
-                            + getEGLErrorString(mEgl.eglGetError()));
+                            + GLUtils.getEGLErrorString(mEgl.eglGetError()));
                 }
             }
         }
@@ -361,13 +360,13 @@
             mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
             if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
                 throw new RuntimeException("eglGetDisplay failed "
-                        + getEGLErrorString(mEgl.eglGetError()));
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
             }
             
             int[] version = new int[2];
             if (!mEgl.eglInitialize(mEglDisplay, version)) {
                 throw new RuntimeException("eglInitialize failed " +
-                        getEGLErrorString(mEgl.eglGetError()));
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
             }
 
             mEglConfig = chooseEglConfig();
@@ -386,12 +385,12 @@
                     return;
                 }
                 throw new RuntimeException("createWindowSurface failed "
-                        + getEGLErrorString(error));
+                        + GLUtils.getEGLErrorString(error));
             }
 
             if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                 throw new RuntimeException("eglMakeCurrent failed "
-                        + getEGLErrorString(mEgl.eglGetError()));
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
             }
 
             mGL = mEglContext.getGL();
@@ -409,7 +408,7 @@
             int[] configSpec = getConfig();
             if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
                 throw new IllegalArgumentException("eglChooseConfig failed " +
-                        getEGLErrorString(mEgl.eglGetError()));
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
             } else if (configsCount[0] > 0) {
                 return configs[0];
             }
@@ -429,43 +428,6 @@
             };
         }
 
-        static String getEGLErrorString(int error) {
-            switch (error) {
-                case EGL10.EGL_SUCCESS:
-                    return "EGL_SUCCESS";
-                case EGL10.EGL_NOT_INITIALIZED:
-                    return "EGL_NOT_INITIALIZED";
-                case EGL10.EGL_BAD_ACCESS:
-                    return "EGL_BAD_ACCESS";
-                case EGL10.EGL_BAD_ALLOC:
-                    return "EGL_BAD_ALLOC";
-                case EGL10.EGL_BAD_ATTRIBUTE:
-                    return "EGL_BAD_ATTRIBUTE";
-                case EGL10.EGL_BAD_CONFIG:
-                    return "EGL_BAD_CONFIG";
-                case EGL10.EGL_BAD_CONTEXT:
-                    return "EGL_BAD_CONTEXT";
-                case EGL10.EGL_BAD_CURRENT_SURFACE:
-                    return "EGL_BAD_CURRENT_SURFACE";
-                case EGL10.EGL_BAD_DISPLAY:
-                    return "EGL_BAD_DISPLAY";
-                case EGL10.EGL_BAD_MATCH:
-                    return "EGL_BAD_MATCH";
-                case EGL10.EGL_BAD_NATIVE_PIXMAP:
-                    return "EGL_BAD_NATIVE_PIXMAP";
-                case EGL10.EGL_BAD_NATIVE_WINDOW:
-                    return "EGL_BAD_NATIVE_WINDOW";
-                case EGL10.EGL_BAD_PARAMETER:
-                    return "EGL_BAD_PARAMETER";
-                case EGL10.EGL_BAD_SURFACE:
-                    return "EGL_BAD_SURFACE";
-                case EGL11.EGL_CONTEXT_LOST:
-                    return "EGL_CONTEXT_LOST";
-                default:
-                    return "0x" + Integer.toHexString(error);
-            }
-        }
-
         void finish() {
             mFinished = true;
         }