• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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