1 /* 2 * Copyright (C) 2016 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.compatibility.common.util; 18 19 import static org.junit.Assert.fail; 20 21 import android.graphics.Bitmap; 22 import android.graphics.Rect; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.SystemClock; 26 import android.view.PixelCopy; 27 import android.view.PixelCopy.OnPixelCopyFinishedListener; 28 import android.view.Surface; 29 import android.view.SurfaceView; 30 import android.view.View; 31 import android.view.Window; 32 33 import java.util.function.Consumer; 34 35 public class SynchronousPixelCopy implements OnPixelCopyFinishedListener { 36 private static final long TIMEOUT_MILLIS = 1000; 37 private static Handler sHandler; 38 static { 39 HandlerThread thread = new HandlerThread("PixelCopyHelper"); thread.start()40 thread.start(); 41 sHandler = new Handler(thread.getLooper()); 42 } 43 44 private int mStatus = -1; 45 request(Surface source, Bitmap dest)46 public int request(Surface source, Bitmap dest) { 47 synchronized (this) { 48 mStatus = -1; 49 PixelCopy.request(source, dest, this, sHandler); 50 return getResultLocked(); 51 } 52 } 53 request(Surface source, Rect srcRect, Bitmap dest)54 public int request(Surface source, Rect srcRect, Bitmap dest) { 55 synchronized (this) { 56 mStatus = -1; 57 PixelCopy.request(source, srcRect, dest, this, sHandler); 58 return getResultLocked(); 59 } 60 } 61 request(SurfaceView source, Bitmap dest)62 public int request(SurfaceView source, Bitmap dest) { 63 synchronized (this) { 64 mStatus = -1; 65 PixelCopy.request(source, dest, this, sHandler); 66 return getResultLocked(); 67 } 68 } 69 request(SurfaceView source, Rect srcRect, Bitmap dest)70 public int request(SurfaceView source, Rect srcRect, Bitmap dest) { 71 synchronized (this) { 72 mStatus = -1; 73 PixelCopy.request(source, srcRect, dest, this, sHandler); 74 return getResultLocked(); 75 } 76 } 77 request(Window source, Bitmap dest)78 public int request(Window source, Bitmap dest) { 79 synchronized (this) { 80 mStatus = -1; 81 PixelCopy.request(source, dest, this, sHandler); 82 return getResultLocked(); 83 } 84 } 85 request(Window source, Rect srcRect, Bitmap dest)86 public int request(Window source, Rect srcRect, Bitmap dest) { 87 synchronized (this) { 88 mStatus = -1; 89 PixelCopy.request(source, srcRect, dest, this, sHandler); 90 return getResultLocked(); 91 } 92 } 93 getResultLocked()94 private int getResultLocked() { 95 long now = SystemClock.uptimeMillis(); 96 final long end = now + TIMEOUT_MILLIS; 97 while (mStatus == -1 && now <= end) { 98 try { 99 this.wait(end - now); 100 } catch (InterruptedException e) { } 101 now = SystemClock.uptimeMillis(); 102 } 103 if (mStatus == -1) { 104 fail("PixelCopy request didn't complete within " + TIMEOUT_MILLIS + "ms"); 105 } 106 return mStatus; 107 } 108 109 @Override onPixelCopyFinished(int copyResult)110 public void onPixelCopyFinished(int copyResult) { 111 synchronized (this) { 112 mStatus = copyResult; 113 this.notify(); 114 } 115 } 116 117 private static final class BlockingResult implements Consumer<PixelCopy.Result> { 118 private PixelCopy.Result mResult; 119 getResult()120 public PixelCopy.Result getResult() { 121 synchronized (this) { 122 long now = SystemClock.uptimeMillis(); 123 final long end = now + TIMEOUT_MILLIS; 124 while (mResult == null && now <= end) { 125 try { 126 this.wait(end - now); 127 } catch (InterruptedException e) { } 128 now = SystemClock.uptimeMillis(); 129 } 130 if (mResult == null) { 131 fail("PixelCopy request didn't complete within " + TIMEOUT_MILLIS + "ms"); 132 } 133 return mResult; 134 } 135 } 136 137 @Override accept(PixelCopy.Result copyResult)138 public void accept(PixelCopy.Result copyResult) { 139 synchronized (this) { 140 mResult = copyResult; 141 this.notify(); 142 } 143 } 144 } 145 146 /** happy lint */ requestSync(PixelCopy.Request request)147 public static PixelCopy.Result requestSync(PixelCopy.Request request) { 148 BlockingResult resultWaiter = new BlockingResult(); 149 PixelCopy.request(request, Runnable::run, resultWaiter); 150 return resultWaiter.getResult(); 151 } 152 153 /** happy lint */ copySurface(Surface source, Consumer<PixelCopy.Request.Builder> func)154 public static PixelCopy.Result copySurface(Surface source, 155 Consumer<PixelCopy.Request.Builder> func) { 156 PixelCopy.Request.Builder request = PixelCopy.Request.Builder.ofSurface(source); 157 if (func != null) { 158 func.accept(request); 159 } 160 return requestSync(request.build()); 161 } 162 163 /** happy lint */ copySurface(Surface source)164 public static PixelCopy.Result copySurface(Surface source) { 165 return copySurface(source, null); 166 } 167 168 /** happy lint */ copySurface(SurfaceView source, Consumer<PixelCopy.Request.Builder> func)169 public static PixelCopy.Result copySurface(SurfaceView source, 170 Consumer<PixelCopy.Request.Builder> func) { 171 PixelCopy.Request.Builder request = PixelCopy.Request.Builder.ofSurface(source); 172 if (func != null) { 173 func.accept(request); 174 } 175 return requestSync(request.build()); 176 } 177 178 /** happy lint */ copySurface(SurfaceView source)179 public static PixelCopy.Result copySurface(SurfaceView source) { 180 return copySurface(source, null); 181 } 182 183 /** happy lint */ copyWindow(View source, Consumer<PixelCopy.Request.Builder> func)184 public static PixelCopy.Result copyWindow(View source, 185 Consumer<PixelCopy.Request.Builder> func) { 186 PixelCopy.Request.Builder request = PixelCopy.Request.Builder.ofWindow(source); 187 if (func != null) { 188 func.accept(request); 189 } 190 return requestSync(request.build()); 191 } 192 193 /** happy lint */ copyWindow(View source)194 public static PixelCopy.Result copyWindow(View source) { 195 return copyWindow(source, null); 196 } 197 198 /** happy lint */ copyWindow(Window source, Consumer<PixelCopy.Request.Builder> func)199 public static PixelCopy.Result copyWindow(Window source, 200 Consumer<PixelCopy.Request.Builder> func) { 201 PixelCopy.Request.Builder request = PixelCopy.Request.Builder.ofWindow(source); 202 if (func != null) { 203 func.accept(request); 204 } 205 return requestSync(request.build()); 206 } 207 208 /** happy lint */ copyWindow(Window source)209 public static PixelCopy.Result copyWindow(Window source) { 210 return copyWindow(source, null); 211 } 212 } 213