1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.test.hwui; 18 19 import android.app.Activity; 20 import android.graphics.Bitmap; 21 import android.graphics.Canvas; 22 import android.graphics.Color; 23 import android.graphics.Paint; 24 import android.graphics.Picture; 25 import android.os.Bundle; 26 import android.view.SurfaceHolder; 27 import android.view.SurfaceView; 28 import android.view.View; 29 import android.view.ViewDebug; 30 import android.webkit.WebChromeClient; 31 import android.webkit.WebView; 32 import android.webkit.WebViewClient; 33 import android.widget.ImageView; 34 import android.widget.LinearLayout; 35 import android.widget.LinearLayout.LayoutParams; 36 import android.widget.ProgressBar; 37 38 import java.io.PipedInputStream; 39 import java.io.PipedOutputStream; 40 import java.util.Random; 41 import java.util.concurrent.ExecutorService; 42 import java.util.concurrent.Executors; 43 import java.util.concurrent.Future; 44 45 public class PictureCaptureDemo extends Activity { 46 @Override onCreate(Bundle savedInstanceState)47 protected void onCreate(Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 50 final LinearLayout layout = new LinearLayout(this); 51 layout.setOrientation(LinearLayout.VERTICAL); 52 53 final LinearLayout inner = new LinearLayout(this); 54 inner.setOrientation(LinearLayout.HORIZONTAL); 55 ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge); 56 inner.addView(spinner, 57 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 58 59 inner.addView(new View(this), new LayoutParams(50, 1)); 60 61 Picture picture = new Picture(); 62 Canvas canvas = picture.beginRecording(100, 100); 63 canvas.drawColor(Color.RED); 64 Paint paint = new Paint(); 65 paint.setTextSize(32); 66 paint.setColor(Color.BLACK); 67 canvas.drawText("Hello", 0, 50, paint); 68 picture.endRecording(); 69 70 ImageView iv1 = new ImageView(this); 71 iv1.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.ARGB_8888)); 72 inner.addView(iv1, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 73 74 inner.addView(new View(this), new LayoutParams(50, 1)); 75 76 ImageView iv2 = new ImageView(this); 77 iv2.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.HARDWARE)); 78 inner.addView(iv2, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 79 80 layout.addView(inner, 81 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 82 // For testing with a functor in the tree 83 WebView wv = new WebView(this); 84 wv.setWebViewClient(new WebViewClient()); 85 wv.setWebChromeClient(new WebChromeClient()); 86 wv.loadUrl("https://google.com"); 87 layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 400)); 88 89 SurfaceView mySurfaceView = new SurfaceView(this); 90 layout.addView(mySurfaceView, 91 new LayoutParams(LayoutParams.MATCH_PARENT, 600)); 92 93 setContentView(layout); 94 95 mySurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { 96 private AutoCloseable mStopCapture; 97 98 @Override 99 public void surfaceCreated(SurfaceHolder holder) { 100 final Random rand = new Random(); 101 mStopCapture = ViewDebug.startRenderingCommandsCapture(mySurfaceView, 102 mCaptureThread, (picture) -> { 103 if (rand.nextInt(20) == 0) { 104 try { 105 Thread.sleep(100); 106 } catch (InterruptedException e) { 107 } 108 } 109 Canvas canvas = holder.lockCanvas(); 110 if (canvas == null) { 111 return false; 112 } 113 canvas.drawPicture(picture); 114 holder.unlockCanvasAndPost(canvas); 115 picture.close(); 116 return true; 117 }); 118 } 119 120 @Override 121 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 122 123 } 124 125 @Override 126 public void surfaceDestroyed(SurfaceHolder holder) { 127 if (mStopCapture != null) { 128 try { 129 mStopCapture.close(); 130 } catch (Exception e) { 131 } 132 mStopCapture = null; 133 } 134 } 135 }); 136 } 137 138 ExecutorService mCaptureThread = Executors.newSingleThreadExecutor(); 139 ExecutorService mExecutor = Executors.newSingleThreadExecutor(); 140 deepCopy(Picture src)141 Picture deepCopy(Picture src) { 142 try { 143 PipedInputStream inputStream = new PipedInputStream(); 144 PipedOutputStream outputStream = new PipedOutputStream(inputStream); 145 Future<Picture> future = mExecutor.submit(() -> Picture.createFromStream(inputStream)); 146 src.writeToStream(outputStream); 147 outputStream.close(); 148 return future.get(); 149 } catch (Exception ex) { 150 throw new RuntimeException(ex); 151 } 152 } 153 } 154