Add new hardwareAccelerated manifest attribute to enable HW drawing.

Change-Id: I2bb0252f3699cb720e7f5b6868419c9904e4fb35
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index aa124e6..15c6910 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.content.pm.ApplicationInfo;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
@@ -33,7 +34,6 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.EventLog;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
@@ -52,7 +52,6 @@
 import android.media.AudioManager;
 
 import java.lang.ref.WeakReference;
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -68,14 +67,12 @@
  *
  * {@hide}
  */
-@SuppressWarnings({"EmptyCatchBlock"})
-public final class ViewRoot extends Handler implements ViewParent,
-        View.AttachInfo.Callbacks {
+@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
+public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks {
     private static final String TAG = "ViewRoot";
     private static final boolean DBG = false;
     private static final boolean SHOW_FPS = false;
-    @SuppressWarnings({"ConstantConditionalExpression"})
-    private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV;
+    private static final boolean LOCAL_LOGV = false;
     /** @noinspection PointlessBooleanExpression*/
     private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
     private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
@@ -202,14 +199,7 @@
     int mCurScrollY;
     Scroller mScroller;
 
-    EGL10 mEgl;
-    EGLDisplay mEglDisplay;
-    EGLContext mEglContext;
-    EGLSurface mEglSurface;
-    GL11 mGL;
-    Canvas mGlCanvas;
-    boolean mUseGL;
-    boolean mGlWanted;
+    HardwareRenderer mHwRenderer;
 
     final ViewConfiguration mViewConfiguration;
 
@@ -239,8 +229,10 @@
     public ViewRoot(Context context) {
         super();
 
-        if (MEASURE_LATENCY && lt == null) {
-            lt = new LatencyTimer(100, 1000);
+        if (MEASURE_LATENCY) {
+            if (lt == null) {
+                lt = new LatencyTimer(100, 1000);
+            }
         }
 
         // For debug only
@@ -270,6 +262,12 @@
         mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
+
+        // Try to enable hardware acceleration if requested
+        if ((context.getApplicationInfo().flags &
+                ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+            mHwRenderer = new HardwareRenderer();
+        }
     }
 
     // For debug only
@@ -328,112 +326,6 @@
         return false;
     }
 
-    private void initializeGL() {
-        initializeGLInner();
-        int err = mEgl.eglGetError();
-        if (err != EGL10.EGL_SUCCESS) {
-            // give-up on using GL
-            destroyGL();
-            mGlWanted = false;
-        }
-    }
-
-    private void initializeGLInner() {
-        final EGL10 egl = (EGL10) EGLContext.getEGL();
-        mEgl = egl;
-
-        /*
-         * Get to the default display.
-         */
-        final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-        mEglDisplay = eglDisplay;
-
-        /*
-         * We can now initialize EGL for that display
-         */
-        int[] version = new int[2];
-        egl.eglInitialize(eglDisplay, version);
-
-        /*
-         * Specify a configuration for our opengl session
-         * and grab the first configuration that matches is
-         */
-        final int[] configSpec = {
-                EGL10.EGL_RED_SIZE,      5,
-                EGL10.EGL_GREEN_SIZE,    6,
-                EGL10.EGL_BLUE_SIZE,     5,
-                EGL10.EGL_DEPTH_SIZE,    0,
-                EGL10.EGL_NONE
-        };
-        final EGLConfig[] configs = new EGLConfig[1];
-        final int[] num_config = new int[1];
-        egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, num_config);
-        final EGLConfig config = configs[0];
-
-        /*
-         * Create an OpenGL ES context. This must be done only once, an
-         * OpenGL context is a somewhat heavy object.
-         */
-        final EGLContext context = egl.eglCreateContext(eglDisplay, config,
-                EGL10.EGL_NO_CONTEXT, null);
-        mEglContext = context;
-
-        /*
-         * Create an EGL surface we can render into.
-         */
-        final EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
-        mEglSurface = surface;
-
-        /*
-         * Before we can issue GL commands, we need to make sure
-         * the context is current and bound to a surface.
-         */
-        egl.eglMakeCurrent(eglDisplay, surface, surface, context);
-
-        /*
-         * Get to the appropriate GL interface.
-         * This is simply done by casting the GL context to either
-         * GL10 or GL11.
-         */
-        final GL11 gl = (GL11) context.getGL();
-        mGL = gl;
-        mGlCanvas = new Canvas(gl);
-        mUseGL = true;
-    }
-
-    private void destroyGL() {
-        // inform skia that the context is gone
-        nativeAbandonGlCaches();
-
-        mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
-                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
-        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-        mEgl.eglTerminate(mEglDisplay);
-        mEglContext = null;
-        mEglSurface = null;
-        mEglDisplay = null;
-        mEgl = null;
-        mGlCanvas = null;
-        mGL = null;
-        mUseGL = false;
-    }
-
-    private void checkEglErrors() {
-        if (mUseGL) {
-            int err = mEgl.eglGetError();
-            if (err != EGL10.EGL_SUCCESS) {
-                // something bad has happened revert to
-                // normal rendering.
-                destroyGL();
-                if (err != EGL11.EGL_CONTEXT_LOST) {
-                    // we'll try again if it was context lost
-                    mGlWanted = false;
-                }
-            }
-        }
-    }
-
     // fd [0] is the receiver, [1] is the sender
     private native int[] makeInputChannel();
 
@@ -490,10 +382,10 @@
 
                 // Set up the input event channel
                 if (false) {
-                int[] fds = makeInputChannel();
-                if (DEBUG_INPUT) {
-                    Log.v(TAG, "makeInputChannel() returned " + fds);
-                }
+                    int[] fds = makeInputChannel();
+                    if (DEBUG_INPUT) {
+                        Log.v(TAG, "makeInputChannel() returned " + java.util.Arrays.toString(fds));
+                    }
                 }
 
                 // Schedule the first layout -before- adding to the window
@@ -772,8 +664,8 @@
             attachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
-                if (mUseGL) {
-                    destroyGL();
+                if (mHwRenderer != null) {
+                    mHwRenderer.destroyGL();
                 }
             }
             if (viewVisibility == View.GONE) {
@@ -889,10 +781,12 @@
 
         final boolean computesInternalInsets =
                 attachInfo.mTreeObserver.hasComputeInternalInsetsListeners();
+
         boolean insetsPending = false;
         int relayoutResult = 0;
-        if (mFirst || windowShouldResize || insetsChanged
-                || viewVisibilityChanged || params != null) {
+
+        if (mFirst || windowShouldResize || insetsChanged ||
+                viewVisibilityChanged || params != null) {
 
             if (viewVisibility == View.VISIBLE) {
                 // If this window is giving internal insets to the window
@@ -904,15 +798,7 @@
                 // window, waiting until we can finish laying out this window
                 // and get back to the window manager with the ultimately
                 // computed insets.
-                insetsPending = computesInternalInsets
-                        && (mFirst || viewVisibilityChanged);
-
-                if (mWindowAttributes.memoryType == WindowManager.LayoutParams.MEMORY_TYPE_GPU) {
-                    if (params == null) {
-                        params = mWindowAttributes;
-                    }
-                    mGlWanted = true;
-                }
+                insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
             }
 
             if (mSurfaceHolder != null) {
@@ -921,11 +807,12 @@
                 lp.format = mSurfaceHolder.getRequestedFormat();
                 lp.type = mSurfaceHolder.getRequestedType();
             }
-            
-            boolean initialized = false;
+
+            boolean hwIntialized = false;
             boolean contentInsetsChanged = false;
             boolean visibleInsetsChanged;
             boolean hadSurface = mSurface.isValid();
+
             try {
                 int fl = 0;
                 if (params != null) {
@@ -985,9 +872,8 @@
                         fullRedrawNeeded = true;
                         mPreviousTransparentRegion.setEmpty();
 
-                        if (mGlWanted && !mUseGL) {
-                            initializeGL();
-                            initialized = mGlCanvas != null;
+                        if (mHwRenderer != null) {
+                            hwIntialized = mHwRenderer.initialize();
                         }
                     }
                 } else if (!mSurface.isValid()) {
@@ -1065,9 +951,8 @@
                 }
             }
             
-            if (initialized) {
-                mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
-                        (int) (mHeight * appScale + 0.5f));
+            if (hwIntialized) {
+                mHwRenderer.setup(appScale);
             }
 
             boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1328,7 +1213,8 @@
         if (!sFirstDrawComplete) {
             synchronized (sFirstDrawHandlers) {
                 sFirstDrawComplete = true;
-                for (int i=0; i<sFirstDrawHandlers.size(); i++) {
+                final int count = sFirstDrawHandlers.size();
+                for (int i = 0; i< count; i++) {
                     post(sFirstDrawHandlers.get(i));
                 }
             }
@@ -1362,53 +1248,16 @@
             return;
         }
         
-        if (mUseGL) {
+        if (mHwRenderer != null && mHwRenderer.mEnabled) {
             if (!dirty.isEmpty()) {
-                Canvas canvas = mGlCanvas;
-                if (mGL != null && canvas != null) {
-                    mGL.glDisable(GL_SCISSOR_TEST);
-                    mGL.glClearColor(0, 0, 0, 0);
-                    mGL.glClear(GL_COLOR_BUFFER_BIT);
-                    mGL.glEnable(GL_SCISSOR_TEST);
-
-                    mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
-                    mAttachInfo.mIgnoreDirtyState = true;
-                    mView.mPrivateFlags |= View.DRAWN;
-
-                    int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                    try {
-                        canvas.translate(0, -yoff);
-                        if (mTranslator != null) {
-                            mTranslator.translateCanvas(canvas);
-                        }
-                        canvas.setScreenDensity(scalingRequired
-                                ? DisplayMetrics.DENSITY_DEVICE : 0);
-                        mView.draw(canvas);
-                        if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
-                            mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
-                        }
-                    } finally {
-                        canvas.restoreToCount(saveCount);
-                    }
-
-                    mAttachInfo.mIgnoreDirtyState = false;
-
-                    mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
-                    checkEglErrors();
-
-                    if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {
-                        int now = (int)SystemClock.elapsedRealtime();
-                        if (sDrawTime != 0) {
-                            nativeShowFPS(canvas, now - sDrawTime);
-                        }
-                        sDrawTime = now;
-                    }
-                }
+                mHwRenderer.draw(yoff, scalingRequired);
             }
+
             if (scrolling) {
                 mFullRedrawNeeded = true;
                 scheduleTraversals();
             }
+
             return;
         }
 
@@ -1720,8 +1569,6 @@
     }
 
     void dispatchDetachedFromWindow() {
-        if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);
-
         if (mView != null) {
             mView.dispatchDetachedFromWindow();
         }
@@ -1730,8 +1577,8 @@
         mAttachInfo.mRootView = null;
         mAttachInfo.mSurface = null;
 
-        if (mUseGL) {
-            destroyGL();
+        if (mHwRenderer != null) {
+            mHwRenderer.destroyGL();
         }
         mSurface.release();
 
@@ -1850,8 +1697,10 @@
                     event = sWindowSession.getPendingPointerMove(mWindow);
 
                     if (MEASURE_LATENCY && event != null) {
-                        lt.sample("9 Client got events      ", System.nanoTime() - event.getEventTimeNano());
-                        lt.sample("8 Client getting events  ", timeBeforeGettingEvents - event.getEventTimeNano());
+                        lt.sample("9 Client got events      ",
+                                System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("8 Client getting events  ",
+                                timeBeforeGettingEvents - event.getEventTimeNano());
                     }
                 } catch (RemoteException e) {
                 }
@@ -1876,11 +1725,13 @@
                         event.offsetLocation(0, mCurScrollY);
                     }
                     if (MEASURE_LATENCY) {
-                        lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("A Dispatching TouchEvents",
+                                System.nanoTime() - event.getEventTimeNano());
                     }
                     handled = mView.dispatchTouchEvent(event);
                     if (MEASURE_LATENCY) {
-                        lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+                        lt.sample("B Dispatched TouchEvents ",
+                                System.nanoTime() - event.getEventTimeNano());
                     }
                     if (!handled && isDown) {
                         int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
@@ -1990,18 +1841,8 @@
                     boolean inTouchMode = msg.arg2 != 0;
                     ensureTouchModeLocally(inTouchMode);
 
-                    if (mGlWanted) {
-                        checkEglErrors();
-                        // we lost the gl context, so recreate it.
-                        if (mGlWanted && !mUseGL) {
-                            initializeGL();
-                            if (mGlCanvas != null) {
-                                float appScale = mAttachInfo.mApplicationScale;
-                                mGlCanvas.setViewport(
-                                        (int) (mWidth * appScale + 0.5f),
-                                        (int) (mHeight * appScale + 0.5f));
-                            }
-                        }
+                    if (mHwRenderer != null) {
+                        mHwRenderer.initializeAndSetup();
                     }
                 }
 
@@ -2051,8 +1892,7 @@
             if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
                 // The IME is trying to say this event is from the
                 // system!  Bad bad bad!
-                event = KeyEvent.changeFlags(event,
-                        event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
+                event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
             }
             deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
         } break;
@@ -2497,8 +2337,7 @@
     private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
         // If mView is null, we just consume the key event because it doesn't
         // make sense to do anything else with it.
-        boolean handled = mView != null
-                ? mView.dispatchKeyEventPreIme(event) : true;
+        boolean handled = mView == null || mView.dispatchKeyEventPreIme(event);
         if (handled) {
             if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
@@ -2535,7 +2374,6 @@
             final boolean sendDone = seq >= 0;
             if (!handled) {
                 deliverKeyEventToViewHierarchy(event, sendDone);
-                return;
             } else if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
                         "ViewRoot", "Telling window manager key is finished");
@@ -2742,7 +2580,7 @@
 
     void doDie() {
         checkThread();
-        if (Config.LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
+        if (LOCAL_LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
         synchronized (this) {
             if (mAdded && !mFirst) {
                 int viewVisibility = mView.getVisibility();
@@ -2803,13 +2641,12 @@
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             //noinspection ConstantConditions
             if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
-                if (Config.LOGD) Log.d("keydisp",
-                        "===================================================");
-                if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
+                if (DBG) Log.d("keydisp", "===================================================");
+                if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
+
                 debug();
 
-                if (Config.LOGD) Log.d("keydisp",
-                        "===================================================");
+                if (DBG) Log.d("keydisp", "===================================================");
             }
         }
 
@@ -3476,6 +3313,180 @@
         }
     }
 
+    class HardwareRenderer {
+        private EGL10 mEgl;
+        private EGLDisplay mEglDisplay;
+        private EGLContext mEglContext;
+        private EGLSurface mEglSurface;
+        private GL11 mGL;
+
+        private Canvas mGlCanvas;
+
+        boolean mEnabled;
+        boolean mRequested = true;
+
+        private void initializeGL() {
+            initializeGLInner();
+            int err = mEgl.eglGetError();
+            if (err != EGL10.EGL_SUCCESS) {
+                destroyGL();
+                mRequested = false;
+            }
+        }
+
+        private void initializeGLInner() {
+            final EGL10 egl = (EGL10) EGLContext.getEGL();
+            mEgl = egl;
+    
+            final EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+            mEglDisplay = eglDisplay;
+    
+            int[] version = new int[2];
+            egl.eglInitialize(eglDisplay, version);
+    
+            final int[] configSpec = {
+                    EGL10.EGL_RED_SIZE,      8,
+                    EGL10.EGL_GREEN_SIZE,    8,
+                    EGL10.EGL_BLUE_SIZE,     8,
+                    EGL10.EGL_DEPTH_SIZE,    0,
+                    EGL10.EGL_NONE
+            };
+            final EGLConfig[] configs = new EGLConfig[1];
+            final int[] numConfig = new int[1];
+            egl.eglChooseConfig(eglDisplay, configSpec, configs, 1, numConfig);
+            final EGLConfig config = configs[0];
+
+            /*
+             * Create an OpenGL ES context. This must be done only once, an
+             * OpenGL context is a somewhat heavy object.
+             */
+            final EGLContext context = egl.eglCreateContext(eglDisplay, config,
+                    EGL10.EGL_NO_CONTEXT, null);
+            mEglContext = context;
+    
+            /*
+             * Create an EGL surface we can render into.
+             */
+            EGLSurface surface = egl.eglCreateWindowSurface(eglDisplay, config, mHolder, null);
+            mEglSurface = surface;
+    
+            /*
+             * Before we can issue GL commands, we need to make sure
+             * the context is current and bound to a surface.
+             */
+            egl.eglMakeCurrent(eglDisplay, surface, surface, context);
+    
+            /*
+             * Get to the appropriate GL interface.
+             * This is simply done by casting the GL context to either
+             * GL10 or GL11.
+             */
+            final GL11 gl = (GL11) context.getGL();
+            mGL = gl;
+            mGlCanvas = new Canvas(gl);
+            mEnabled = true;
+        }
+
+        void destroyGL() {
+            if (!mEnabled) return;
+            
+            // inform skia that the context is gone
+            nativeAbandonGlCaches();
+    
+            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+                    EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+            mEgl.eglTerminate(mEglDisplay);
+
+            mEglContext = null;
+            mEglSurface = null;
+            mEglDisplay = null;
+            mEgl = null;
+            mGlCanvas = null;
+            mGL = null;
+
+            mEnabled = false;
+        }
+    
+        private void checkErrors() {
+            if (mEnabled) {
+                int err = mEgl.eglGetError();
+                if (err != EGL10.EGL_SUCCESS) {
+                    // something bad has happened revert to
+                    // normal rendering.
+                    destroyGL();
+                    if (err != EGL11.EGL_CONTEXT_LOST) {
+                        // we'll try again if it was context lost
+                        mRequested = false;
+                    }
+                }
+            }
+        }
+
+        boolean initialize() {
+            if (mRequested && !mEnabled) {
+                initializeGL();
+                return mGlCanvas != null;
+            }
+            return false;
+        }
+
+        void setup(float appScale) {
+            mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+                    (int) (mHeight * appScale + 0.5f));
+        }
+
+        void draw(int yoff, boolean scalingRequired) {
+            Canvas canvas = mGlCanvas;
+            if (mGL != null && canvas != null) {
+                mGL.glDisable(GL_SCISSOR_TEST);
+                mGL.glClearColor(0, 0, 0, 0);
+                mGL.glClear(GL_COLOR_BUFFER_BIT);
+                mGL.glEnable(GL_SCISSOR_TEST);
+    
+                mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
+                mAttachInfo.mIgnoreDirtyState = true;
+                mView.mPrivateFlags |= View.DRAWN;
+    
+                int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                try {
+                    canvas.translate(0, -yoff);
+                    if (mTranslator != null) {
+                        mTranslator.translateCanvas(canvas);
+                    }
+                    canvas.setScreenDensity(scalingRequired ?
+                            DisplayMetrics.DENSITY_DEVICE : 0);
+    
+                    mView.draw(canvas);
+    
+                } finally {
+                    canvas.restoreToCount(saveCount);
+                }
+    
+                mAttachInfo.mIgnoreDirtyState = false;
+    
+                mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
+                checkErrors();
+            }
+        }
+
+        void initializeAndSetup() {
+            if (mRequested) {
+                checkErrors();
+                // we lost the gl context, so recreate it.
+                if (mRequested && !mEnabled) {
+                    initializeGL();
+                    if (mGlCanvas != null) {
+                        float appScale = mAttachInfo.mApplicationScale;
+                        mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f),
+                                (int) (mHeight * appScale + 0.5f));
+                    }
+                }
+            }
+        }
+    }
+    
     private static native void nativeShowFPS(Canvas canvas, int durationMillis);
 
     // inform skia to just abandon its texture cache IDs