OSDN Git Service

Add SurfaceHolder#lockHardwareCanvas()
authorJohn Reck <jreck@google.com>
Wed, 26 Oct 2016 23:49:17 +0000 (16:49 -0700)
committerJohn Reck <jreck@google.com>
Thu, 27 Oct 2016 21:13:44 +0000 (14:13 -0700)
Bug: 26988043
Test: SurfaceViewTests#testSurfaceHolderHardwareCanvas CTS test
Change-Id: I3e5352d498dbe2fc56a18ca27360d129a14c7784

api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/service/wallpaper/WallpaperService.java
core/java/android/view/SurfaceHolder.java
core/java/android/view/SurfaceView.java
core/java/com/android/internal/view/BaseSurfaceHolder.java
tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java

index 564653a..1dd7118 100644 (file)
@@ -42341,6 +42341,7 @@ package android.view {
     method public abstract boolean isCreating();
     method public abstract android.graphics.Canvas lockCanvas();
     method public abstract android.graphics.Canvas lockCanvas(android.graphics.Rect);
+    method public default android.graphics.Canvas lockHardwareCanvas();
     method public abstract void removeCallback(android.view.SurfaceHolder.Callback);
     method public abstract void setFixedSize(int, int);
     method public abstract void setFormat(int);
index fd51a6a..ecf67f7 100644 (file)
@@ -45519,6 +45519,7 @@ package android.view {
     method public abstract boolean isCreating();
     method public abstract android.graphics.Canvas lockCanvas();
     method public abstract android.graphics.Canvas lockCanvas(android.graphics.Rect);
+    method public default android.graphics.Canvas lockHardwareCanvas();
     method public abstract void removeCallback(android.view.SurfaceHolder.Callback);
     method public abstract void setFixedSize(int, int);
     method public abstract void setFormat(int);
index 150fbfe..c42ef69 100644 (file)
@@ -42577,6 +42577,7 @@ package android.view {
     method public abstract boolean isCreating();
     method public abstract android.graphics.Canvas lockCanvas();
     method public abstract android.graphics.Canvas lockCanvas(android.graphics.Rect);
+    method public default android.graphics.Canvas lockHardwareCanvas();
     method public abstract void removeCallback(android.view.SurfaceHolder.Callback);
     method public abstract void setFixedSize(int, int);
     method public abstract void setFormat(int);
index 06d87f8..64f0222 100644 (file)
@@ -232,8 +232,7 @@ public abstract class WallpaperService extends Service {
                         "Wallpapers do not support keep screen on");
             }
 
-            @Override
-            public Canvas lockCanvas() {
+            private void prepareToDraw() {
                 if (mDisplayState == Display.STATE_DOZE
                         || mDisplayState == Display.STATE_DOZE_SUSPEND) {
                     try {
@@ -242,8 +241,25 @@ public abstract class WallpaperService extends Service {
                         // System server died, can be ignored.
                     }
                 }
+            }
+
+            @Override
+            public Canvas lockCanvas() {
+                prepareToDraw();
                 return super.lockCanvas();
             }
+
+            @Override
+            public Canvas lockCanvas(Rect dirty) {
+                prepareToDraw();
+                return super.lockCanvas(dirty);
+            }
+
+            @Override
+            public Canvas lockHardwareCanvas() {
+                prepareToDraw();
+                return super.lockHardwareCanvas();
+            }
         };
 
         final class WallpaperInputEventReceiver extends InputEventReceiver {
index 99fa2a4..a3e8312 100644 (file)
@@ -24,7 +24,7 @@ import android.graphics.Rect;
  * control the surface size and format, edit the pixels in the surface, and
  * monitor changes to the surface.  This interface is typically available
  * through the {@link SurfaceView} class.
- * 
+ *
  * <p>When using this interface from a thread other than the one running
  * its {@link SurfaceView}, you will want to carefully read the
  * methods
@@ -73,7 +73,7 @@ public interface SurfaceHolder {
          * they desire.  Note that only one thread can ever draw into
          * a {@link Surface}, so you should not draw into the Surface here
          * if your normal rendering will be in another thread.
-         * 
+         *
          * @param holder The SurfaceHolder whose surface is being created.
          */
         public void surfaceCreated(SurfaceHolder holder);
@@ -83,7 +83,7 @@ public interface SurfaceHolder {
          * size) have been made to the surface.  You should at this point update
          * the imagery in the surface.  This method is always called at least
          * once, after {@link #surfaceCreated}.
-         * 
+         *
          * @param holder The SurfaceHolder whose surface has changed.
          * @param format The new PixelFormat of the surface.
          * @param width The new width of the surface.
@@ -96,9 +96,9 @@ public interface SurfaceHolder {
          * This is called immediately before a surface is being destroyed. After
          * returning from this call, you should no longer try to access this
          * surface.  If you have a rendering thread that directly accesses
-         * the surface, you must ensure that thread is no longer touching the 
+         * the surface, you must ensure that thread is no longer touching the
          * Surface before returning from this function.
-         * 
+         *
          * @param holder The SurfaceHolder whose surface is being destroyed.
          */
         public void surfaceDestroyed(SurfaceHolder holder);
@@ -124,14 +124,14 @@ public interface SurfaceHolder {
     /**
      * Add a Callback interface for this holder.  There can several Callback
      * interfaces associated with a holder.
-     * 
+     *
      * @param callback The new Callback interface.
      */
     public void addCallback(Callback callback);
 
     /**
      * Removes a previously added Callback interface from this holder.
-     * 
+     *
      * @param callback The Callback interface to remove.
      */
     public void removeCallback(Callback callback);
@@ -140,14 +140,14 @@ public interface SurfaceHolder {
      * Use this method to find out if the surface is in the process of being
      * created from Callback methods. This is intended to be used with
      * {@link Callback#surfaceChanged}.
-     * 
+     *
      * @return true if the surface is in the process of being created.
      */
     public boolean isCreating();
-    
+
     /**
      * Sets the surface's type.
-     *  
+     *
      * @deprecated this is ignored, this value is set automatically when needed.
      */
     @Deprecated
@@ -157,7 +157,7 @@ public interface SurfaceHolder {
      * Make the surface a fixed size.  It will never change from this size.
      * When working with a {@link SurfaceView}, this must be called from the
      * same thread running the SurfaceView's window.
-     * 
+     *
      * @param width The surface's width.
      * @param height The surface's height.
      */
@@ -176,9 +176,9 @@ public interface SurfaceHolder {
      * Set the desired PixelFormat of the surface.  The default is OPAQUE.
      * When working with a {@link SurfaceView}, this must be called from the
      * same thread running the SurfaceView's window.
-     * 
+     *
      * @param format A constant from PixelFormat.
-     * 
+     *
      * @see android.graphics.PixelFormat
      */
     public void setFormat(int format);
@@ -187,30 +187,30 @@ public interface SurfaceHolder {
      * Enable or disable option to keep the screen turned on while this
      * surface is displayed.  The default is false, allowing it to turn off.
      * This is safe to call from any thread.
-     * 
+     *
      * @param screenOn Set to true to force the screen to stay on, false
      * to allow it to turn off.
      */
     public void setKeepScreenOn(boolean screenOn);
-    
+
     /**
      * Start editing the pixels in the surface.  The returned Canvas can be used
      * to draw into the surface's bitmap.  A null is returned if the surface has
      * not been created or otherwise cannot be edited.  You will usually need
      * to implement {@link Callback#surfaceCreated Callback.surfaceCreated}
      * to find out when the Surface is available for use.
-     * 
+     *
      * <p>The content of the Surface is never preserved between unlockCanvas() and
      * lockCanvas(), for this reason, every pixel within the Surface area
      * must be written. The only exception to this rule is when a dirty
      * rectangle is specified, in which case, non-dirty pixels will be
      * preserved.
-     * 
+     *
      * <p>If you call this repeatedly when the Surface is not ready (before
      * {@link Callback#surfaceCreated Callback.surfaceCreated} or after
      * {@link Callback#surfaceDestroyed Callback.surfaceDestroyed}), your calls
      * will be throttled to a slow rate in order to avoid consuming CPU.
-     * 
+     *
      * <p>If null is not returned, this function internally holds a lock until
      * the corresponding {@link #unlockCanvasAndPost} call, preventing
      * {@link SurfaceView} from creating, destroying, or modifying the surface
@@ -218,31 +218,45 @@ public interface SurfaceHolder {
      * the Surface directly, as you do not need to do special synchronization
      * with a drawing thread in {@link Callback#surfaceDestroyed
      * Callback.surfaceDestroyed}.
-     * 
+     *
      * @return Canvas Use to draw into the surface.
      */
     public Canvas lockCanvas();
 
-    
+
     /**
      * Just like {@link #lockCanvas()} but allows specification of a dirty rectangle.
      * Every
      * pixel within that rectangle must be written; however pixels outside
      * the dirty rectangle will be preserved by the next call to lockCanvas().
-     * 
+     *
      * @see android.view.SurfaceHolder#lockCanvas
-     * 
+     *
      * @param dirty Area of the Surface that will be modified.
      * @return Canvas Use to draw into the surface.
      */
     public Canvas lockCanvas(Rect dirty);
 
     /**
+     * <p>Just like {@link #lockCanvas()} but the returned canvas is hardware-accelerated.
+     *
+     * <p>See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+     * unsupported drawing operations</a> for a list of what is and isn't
+     * supported in a hardware-accelerated canvas.
+     *
+     * @return Canvas Use to draw into the surface.
+     * @throws IllegalStateException If the canvas cannot be locked.
+     */
+    default Canvas lockHardwareCanvas() {
+        throw new IllegalStateException("This SurfaceHolder doesn't support lockHardwareCanvas");
+    }
+
+    /**
      * Finish editing pixels in the surface.  After this call, the surface's
      * current pixels will be shown on the screen, but its content is lost,
      * in particular there is no guarantee that the content of the Surface
      * will remain unchanged when lockCanvas() is called again.
-     * 
+     *
      * @see #lockCanvas()
      *
      * @param canvas The Canvas previously returned by lockCanvas().
@@ -254,7 +268,7 @@ public interface SurfaceHolder {
      * returned Rect.  This is only safe to call from the thread of
      * {@link SurfaceView}'s window, or while inside of
      * {@link #lockCanvas()}.
-     * 
+     *
      * @return Rect The surface's dimensions.  The left and top are always 0.
      */
     public Rect getSurfaceFrame();
@@ -267,17 +281,17 @@ public interface SurfaceHolder {
      * and screen position of the Surface.    You will thus usually need
      * to implement {@link Callback#surfaceCreated Callback.surfaceCreated}
      * to find out when the Surface is available for use.
-     * 
+     *
      * <p>Note that if you directly access the Surface from another thread,
      * it is critical that you correctly implement
      * {@link Callback#surfaceCreated Callback.surfaceCreated} and
      * {@link Callback#surfaceDestroyed Callback.surfaceDestroyed} to ensure
      * that thread only accesses the Surface while it is valid, and that the
      * Surface does not get destroyed while the thread is using it.
-     * 
+     *
      * <p>This method is intended to be used by frameworks which often need
      * direct access to the Surface object (usually to pass it to native code).
-     * 
+     *
      * @return Surface The surface.
      */
     public Surface getSurface();
index 80f447e..5c56ebc 100644 (file)
@@ -957,7 +957,7 @@ public class SurfaceView extends View {
          */
         @Override
         public Canvas lockCanvas() {
-            return internalLockCanvas(null);
+            return internalLockCanvas(null, false);
         }
 
         /**
@@ -977,10 +977,15 @@ public class SurfaceView extends View {
          */
         @Override
         public Canvas lockCanvas(Rect inOutDirty) {
-            return internalLockCanvas(inOutDirty);
+            return internalLockCanvas(inOutDirty, false);
         }
 
-        private final Canvas internalLockCanvas(Rect dirty) {
+        @Override
+        public Canvas lockHardwareCanvas() {
+            return internalLockCanvas(null, true);
+        }
+
+        private Canvas internalLockCanvas(Rect dirty, boolean hardware) {
             mSurfaceLock.lock();
 
             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
@@ -989,7 +994,11 @@ public class SurfaceView extends View {
             Canvas c = null;
             if (!mDrawingStopped && mWindow != null) {
                 try {
-                    c = mSurface.lockCanvas(dirty);
+                    if (hardware) {
+                        c = mSurface.lockHardwareCanvas();
+                    } else {
+                        c = mSurface.lockCanvas(dirty);
+                    }
                 } catch (Exception e) {
                     Log.e(LOG_TAG, "Exception locking surface", e);
                 }
index f9f94be..b41ef29 100644 (file)
@@ -153,15 +153,22 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder {
         }
     }
 
+    @Override
     public Canvas lockCanvas() {
-        return internalLockCanvas(null);
+        return internalLockCanvas(null, false);
     }
 
+    @Override
     public Canvas lockCanvas(Rect dirty) {
-        return internalLockCanvas(dirty);
+        return internalLockCanvas(dirty, false);
     }
 
-    private final Canvas internalLockCanvas(Rect dirty) {
+    @Override
+    public Canvas lockHardwareCanvas() {
+        return internalLockCanvas(null, true);
+    }
+
+    private final Canvas internalLockCanvas(Rect dirty, boolean hardware) {
         if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
             throw new BadSurfaceTypeException(
                     "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
@@ -181,7 +188,11 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder {
             }
 
             try {
-                c = mSurface.lockCanvas(dirty);
+                if (hardware) {
+                    c = mSurface.lockHardwareCanvas();
+                } else {
+                    c = mSurface.lockCanvas(dirty);
+                }
             } catch (Exception e) {
                 Log.e(TAG, "Exception locking surface", e);
             }
index 086a8f0..2bfe994 100644 (file)
@@ -88,7 +88,7 @@ public class HardwareCanvasSurfaceViewActivity extends Activity implements Callb
 
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
-        mThread = new RenderingThread(holder.getSurface());
+        mThread = new RenderingThread(holder);
         mThread.start();
     }
 
@@ -103,11 +103,11 @@ public class HardwareCanvasSurfaceViewActivity extends Activity implements Callb
     }
 
     private static class RenderingThread extends Thread {
-        private final Surface mSurface;
+        private final SurfaceHolder mSurface;
         private volatile boolean mRunning = true;
         private int mWidth, mHeight;
 
-        public RenderingThread(Surface surface) {
+        public RenderingThread(SurfaceHolder surface) {
             mSurface = surface;
         }