Add new hardwareAccelerated manifest attribute to enable HW drawing.
Change-Id: I2bb0252f3699cb720e7f5b6868419c9904e4fb35
diff --git a/api/current.xml b/api/current.xml
index b72db98..2b31a64 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4563,6 +4563,17 @@
visibility="public"
>
</field>
+<field name="hardwareAccelerated"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843540"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="hasCode"
type="int"
transient="false"
@@ -48600,6 +48611,17 @@
visibility="public"
>
</field>
+<field name="FLAG_HARDWARE_ACCELERATED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_HAS_CODE"
type="int"
transient="false"
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7047113..27eeb69 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -273,6 +273,12 @@
public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
/**
+ * Value for {@link #flags}: true when the application's rendering should
+ * be hardware accelerated.
+ */
+ public static final int FLAG_HARDWARE_ACCELERATED = 1<<20;
+
+ /**
* Value for {@link #flags}: this is true if the application has set
* its android:neverEncrypt to true, false otherwise. It is used to specify
* that this package specifically "opts-out" of a secured file system solution,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4ddc124..1b657f6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1536,6 +1536,12 @@
}
if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
+ false)) {
+ ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+ }
+
+ if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
true)) {
ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 527b4f4..3461cbf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8594,13 +8594,12 @@
if (mAttachInfo == null) {
return false;
}
- if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+ if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
&& !isHapticFeedbackEnabled()) {
return false;
}
- return mAttachInfo.mRootCallbacks.performHapticFeedback(
- feedbackConstant,
- (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
+ return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
+ (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
}
/**
@@ -8671,8 +8670,7 @@
ViewConfiguration.getLongPressTimeout() - delayOffset);
}
- private static int[] stateSetUnion(final int[] stateSet1,
- final int[] stateSet2) {
+ private static int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2) {
final int stateSet1Length = stateSet1.length;
final int stateSet2Length = stateSet2.length;
final int[] newSet = new int[stateSet1Length + stateSet2Length];
@@ -8710,7 +8708,7 @@
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
-
+
/**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9329d94..1fc0251 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1566,7 +1566,8 @@
boolean scalingRequired = false;
Bitmap cache = null;
- if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+ if (canvas.getGL() == null &&
+ (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
(flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
cache = child.getDrawingCache(true);
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
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
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b4c4811..4c32ec9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -235,6 +235,10 @@
the safe mode. -->
<attr name="vmSafeMode" format="boolean" />
+ <!-- Flag indicating whether the application's rendering should be hardware
+ accelerated if possible. -->
+ <attr name="hardwareAccelerated" format="boolean" />
+
<!-- Flag indicating whether the given application component is available
to other applications. If false, it can only be accessed by
applications with its same user id (which usually means only by
@@ -730,6 +734,7 @@
<attr name="enabled" />
<attr name="debuggable" />
<attr name="vmSafeMode" />
+ <attr name="hardwareAccelerated" />
<!-- Name of activity to be launched for managing the application's space on the device. -->
<attr name="manageSpaceActivity" />
<attr name="allowClearUserData" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9055970..1aa55e2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1281,6 +1281,7 @@
<public type="attr" name="displayOptions" />
<public type="attr" name="subtitle" />
<public type="attr" name="customNavigationLayout" />
+ <public type="attr" name="hardwareAccelerated" />
<public type="id" name="home" />