Remove native calls to HWUI from Surface and use the public API instead

Test: CtsGraphicsTestCases and CtsWindowManagerDeviceTestCases
Bug: 137655431
Change-Id: I8427f96e4f33905e8cabb6d48a0cc29443b9ed63
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 17f07b5..dac6282 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -23,6 +23,7 @@
 import android.graphics.Canvas;
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
+import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
@@ -925,7 +926,7 @@
 
     private final class HwuiContext {
         private final RenderNode mRenderNode;
-        private long mHwuiRenderer;
+        private HardwareRenderer mHardwareRenderer;
         private RecordingCanvas mCanvas;
         private final boolean mIsWideColorGamut;
 
@@ -934,8 +935,13 @@
             mRenderNode.setClipToBounds(false);
             mRenderNode.setForceDarkAllowed(false);
             mIsWideColorGamut = isWideColorGamut;
-            mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
-                    isWideColorGamut);
+
+            mHardwareRenderer = new HardwareRenderer();
+            mHardwareRenderer.setContentRoot(mRenderNode);
+            mHardwareRenderer.setSurface(Surface.this, true);
+            mHardwareRenderer.setWideGamut(isWideColorGamut);
+            mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
+            mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
         }
 
         Canvas lockCanvas(int width, int height) {
@@ -953,27 +959,21 @@
             }
             mRenderNode.endRecording();
             mCanvas = null;
-            nHwuiDraw(mHwuiRenderer);
+            mHardwareRenderer.createRenderRequest()
+                    .setVsyncTime(System.nanoTime())
+                    .syncAndDraw();
         }
 
         void updateSurface() {
-            nHwuiSetSurface(mHwuiRenderer, mNativeObject);
+            mHardwareRenderer.setSurface(Surface.this, true);
         }
 
         void destroy() {
-            if (mHwuiRenderer != 0) {
-                nHwuiDestroy(mHwuiRenderer);
-                mHwuiRenderer = 0;
-            }
+            mHardwareRenderer.destroy();
         }
 
         boolean isWideColorGamut() {
             return mIsWideColorGamut;
         }
     }
-
-    private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
-    private static native void nHwuiSetSurface(long renderer, long surface);
-    private static native void nHwuiDraw(long renderer);
-    private static native void nHwuiDestroy(long renderer);
 }
diff --git a/core/jni/android/graphics/apex/android_canvas.cpp b/core/jni/android/graphics/apex/android_canvas.cpp
index 527a745..2a939ef 100644
--- a/core/jni/android/graphics/apex/android_canvas.cpp
+++ b/core/jni/android/graphics/apex/android_canvas.cpp
@@ -23,46 +23,66 @@
 #include <utils/Color.h>
 
 #include <SkBitmap.h>
+#include <SkSurface.h>
 
 using namespace android;
 
+/*
+ * Converts a buffer and dataspace into an SkBitmap only if the resulting bitmap can be treated as a
+ * rendering destination for a Canvas.  If the buffer is null or the format is one that we cannot
+ * render into with a Canvas then false is returned and the outBitmap param is unmodified.
+ */
+static bool convert(const ANativeWindow_Buffer* buffer,
+                    int32_t /*android_dataspace_t*/ dataspace,
+                    SkBitmap* outBitmap) {
+    if (buffer == nullptr) {
+        return false;
+    }
+
+    sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
+    SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
+    size_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
+
+    // If SkSurface::MakeRasterDirect fails then we should as well as we will not be able to
+    // draw into the canvas.
+    sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(imageInfo, buffer->bits, rowBytes);
+    if (surface.get() != nullptr) {
+        if (outBitmap) {
+            outBitmap->setInfo(imageInfo, rowBytes);
+            outBitmap->setPixels(buffer->bits);
+        }
+        return true;
+    }
+    return false;
+}
+
 bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) {
-    ANativeWindow_Buffer buffer { 0, 0, 0, bufferFormat, nullptr, {0} };
-    const SkColorType colorType = uirenderer::ANativeWindowToImageInfo(buffer, nullptr).colorType();
-    return kUnknown_SkColorType != colorType;
+    char pixels[8];
+    ANativeWindow_Buffer buffer { 1, 1, 1, bufferFormat, pixels, {0} };
+    return convert(&buffer, HAL_DATASPACE_UNKNOWN, nullptr);
 }
 
 ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {
     return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
 }
 
-static SkBitmap convert(const ANativeWindow_Buffer* buffer,
-                        int32_t /*android_dataspace_t*/ dataspace) {
-    SkBitmap bitmap;
-    if (buffer != nullptr && buffer->width > 0 && buffer->height > 0) {
-        sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
-        SkImageInfo imageInfo = uirenderer::ANativeWindowToImageInfo(*buffer, cs);
-        ssize_t rowBytes = buffer->stride * imageInfo.bytesPerPixel();
-        bitmap.setInfo(imageInfo, rowBytes);
-        bitmap.setPixels(buffer->bits);
-    }
-    return bitmap;
-}
-
 ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
                               int32_t /*android_dataspace_t*/ dataspace) {
-    return TypeCast::toACanvas(Canvas::create_canvas(convert(buffer, dataspace)));
+    SkBitmap bitmap;
+    bool isValidBuffer = convert(buffer, dataspace, &bitmap);
+    return isValidBuffer ? TypeCast::toACanvas(Canvas::create_canvas(bitmap)) : nullptr;
 }
 
 void ACanvas_destroyCanvas(ACanvas* canvas) {
     delete TypeCast::toCanvas(canvas);
 }
 
-void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
+bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                        int32_t /*android_dataspace_t*/ dataspace) {
-
-
-    TypeCast::toCanvas(canvas)->setBitmap(convert(buffer, dataspace));
+    SkBitmap bitmap;
+    bool isValidBuffer = (buffer == nullptr) ? false : convert(buffer, dataspace, &bitmap);
+    TypeCast::toCanvas(canvas)->setBitmap(bitmap);
+    return isValidBuffer;
 }
 
 void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) {
diff --git a/core/jni/android/graphics/apex/include/android/graphics/canvas.h b/core/jni/android/graphics/apex/include/android/graphics/canvas.h
index 190aba4..6fd6b06 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/canvas.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/canvas.h
@@ -42,7 +42,7 @@
 /**
  * Creates a canvas that wraps the buffer
  *
- * @param buffer required
+ * @param buffer is a required param.  If no buffer is provided a nullptr will be returned.
  */
 ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
                               int32_t /*android_dataspace_t*/ dataspace);
@@ -56,8 +56,11 @@
  *               remain valid until the this method is called again with either another active
  *               buffer or nullptr.  If nullptr is given the canvas will release the previous buffer
  *               and set an empty backing store.
+ * @return A boolean value indicating whether or not the buffer was successfully set. If false the
+ *         method will behave as if nullptr were passed as the input buffer and the previous buffer
+ *         will still be released.
  */
-void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
+bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                        int32_t /*android_dataspace_t*/ dataspace);
 
 /**
@@ -110,9 +113,9 @@
             }
         }
 
-        void setBuffer(const ANativeWindow_Buffer* buffer,
+        bool setBuffer(const ANativeWindow_Buffer* buffer,
                        int32_t /*android_dataspace_t*/ dataspace) {
-            ACanvas_setBuffer(mCanvas, buffer, dataspace);
+            return ACanvas_setBuffer(mCanvas, buffer, dataspace);
         }
 
         void clipRect(const ARect& clipRect, bool doAntiAlias = false) {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 058a4c8..01b5920 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -45,11 +45,6 @@
 
 #include <nativehelper/ScopedUtfChars.h>
 
-#include <AnimationContext.h>
-#include <FrameInfo.h>
-#include <RenderNode.h>
-#include <renderthread/RenderProxy.h>
-
 // ----------------------------------------------------------------------------
 
 namespace android {
@@ -189,21 +184,6 @@
     return value;
 }
 
-static inline SkColorType convertPixelFormat(PixelFormat format) {
-    /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
-        we can map to kN32_SkColorType, and optionally call
-        bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
-        (as an accelerator)
-    */
-    switch (format) {
-    case PIXEL_FORMAT_RGBX_8888:    return kN32_SkColorType;
-    case PIXEL_FORMAT_RGBA_8888:    return kN32_SkColorType;
-    case PIXEL_FORMAT_RGBA_FP16:    return kRGBA_F16_SkColorType;
-    case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
-    default:                        return kUnknown_SkColorType;
-    }
-}
-
 static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
         jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
@@ -213,7 +193,7 @@
         return 0;
     }
 
-    if (convertPixelFormat(ANativeWindow_getFormat(surface.get())) == kUnknown_SkColorType) {
+    if (!ACanvas_isSupportedPixelFormat(ANativeWindow_getFormat(surface.get()))) {
         native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888);
     }
 
@@ -433,62 +413,8 @@
     return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled));
 }
 
-namespace uirenderer {
-
-using namespace android::uirenderer::renderthread;
-
-class ContextFactory : public IContextFactory {
-public:
-    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
-        return new AnimationContext(clock);
-    }
-};
-
-static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr,
-        jboolean isWideColorGamut) {
-    RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
-    sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
-    ContextFactory factory;
-    RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
-    proxy->loadSystemProperties();
-    if (isWideColorGamut) {
-        proxy->setWideGamut(true);
-    }
-    proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
-    proxy->setSurface(surface);
-    // Shadows can't be used via this interface, so just set the light source
-    // to all 0s.
-    proxy->setLightAlpha(0, 0);
-    proxy->setLightGeometry((Vector3){0, 0, 0}, 0);
-    return (jlong) proxy;
-}
-
-static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
-    proxy->setSurface(surface);
-}
-
-static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
-    UiFrameInfoBuilder(proxy->frameInfo())
-            .setVsync(vsync, vsync)
-            .addFlag(FrameInfoFlags::SurfaceCanvas);
-    proxy->syncAndDrawFrame();
-}
-
-static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    delete proxy;
-}
-
-} // uirenderer
-
 // ----------------------------------------------------------------------------
 
-namespace hwui = android::uirenderer;
-
 static const JNINativeMethod gSurfaceMethods[] = {
     {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
             (void*)nativeCreateFromSurfaceTexture },
@@ -521,12 +447,6 @@
             (void*)nativeAttachAndQueueBufferWithColorSpace},
     {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
     {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
-
-    // HWUI context
-    {"nHwuiCreate", "(JJZ)J", (void*) hwui::create },
-    {"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface },
-    {"nHwuiDraw", "(J)V", (void*) hwui::draw },
-    {"nHwuiDestroy", "(J)V", (void*) hwui::destroy },
 };
 
 int register_android_view_Surface(JNIEnv* env)
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index dd3a4d0..7350396 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -174,12 +174,15 @@
 }
 
 static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jobject jsurface) {
+        jlong proxyPtr, jobject jsurface, jboolean discardBuffer) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<Surface> surface;
     if (jsurface) {
         surface = android_view_Surface_getSurface(env, jsurface);
     }
+    if (discardBuffer) {
+        proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
+    }
     proxy->setSurface(surface);
 }
 
@@ -632,7 +635,7 @@
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
     { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
-    { "nSetSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_setSurface },
+    { "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface },
     { "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause },
     { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
     { "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha },
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index b6b2d4e..3f3ad57 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -286,10 +286,24 @@
      *                non-null then {@link Surface#isValid()} must be true.
      */
     public void setSurface(@Nullable Surface surface) {
+        setSurface(surface, false);
+    }
+
+    /**
+     * See {@link #setSurface(Surface)}
+     *
+     * @hide
+     * @param discardBuffer determines whether the surface will attempt to preserve its contents
+     *                      between frames.  If set to true the renderer will attempt to preserve
+     *                      the contents of the buffer between frames if the implementation allows
+     *                      it.  If set to false no attempt will be made to preserve the buffer's
+     *                      contents between frames.
+     */
+    public void setSurface(@Nullable Surface surface, boolean discardBuffer) {
         if (surface != null && !surface.isValid()) {
             throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false.");
         }
-        nSetSurface(mNativeProxy, surface);
+        nSetSurface(mNativeProxy, surface, discardBuffer);
     }
 
     /**
@@ -1084,7 +1098,7 @@
 
     private static native void nSetName(long nativeProxy, String name);
 
-    private static native void nSetSurface(long nativeProxy, Surface window);
+    private static native void nSetSurface(long nativeProxy, Surface window, boolean discardBuffer);
 
     private static native boolean nPause(long nativeProxy);