OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.media; | |
6 | |
7 import android.app.Activity; | |
8 import android.app.Fragment; | |
9 import android.app.FragmentManager; | |
10 import android.app.FragmentTransaction; | |
11 import android.content.Context; | |
12 import android.content.Intent; | |
13 import android.graphics.PixelFormat; | |
14 import android.hardware.display.DisplayManager; | |
15 import android.hardware.display.VirtualDisplay; | |
16 import android.media.Image; | |
17 import android.media.ImageReader; | |
18 //import android.media.projection.MediaProjection.Callback; | |
whywhat
2015/08/17 13:58:46
nit: Uncomment or remove?
| |
19 import android.media.projection.MediaProjection; | |
20 import android.media.projection.MediaProjectionManager; | |
21 import android.os.Handler; | |
22 import android.os.HandlerThread; | |
23 import android.util.DisplayMetrics; | |
24 import android.view.Display; | |
25 import android.view.Surface; | |
26 | |
27 import org.chromium.base.BaseChromiumApplication; | |
28 import org.chromium.base.CalledByNative; | |
29 import org.chromium.base.JNINamespace; | |
30 import org.chromium.base.Log; | |
31 | |
32 import java.nio.ByteBuffer; | |
33 | |
34 /** | |
35 * This class implements Screen Capture using projection API, introduced in Andr oid | |
36 * API 21 (L Release). Capture takes place in the current Looper, while pixel | |
37 * download takes place in another thread used by ImageReader. | |
38 **/ | |
39 @JNINamespace("media") | |
40 public class ScreenCapture extends Fragment { | |
41 | |
42 // Internal class implementing the ImageReader listener. Gets pinged when a | |
43 // new frame is been captured and downloaded to memory-backed buffers. | |
44 private class CrImageReaderListener implements ImageReader.OnImageAvailableL istener { | |
45 @Override | |
46 public void onImageAvailable(ImageReader reader) { | |
47 Image image = null; | |
48 try { | |
49 image = reader.acquireLatestImage(); | |
50 if (image == null) return; | |
51 if (image.getFormat() != PixelFormat.RGBA_8888) { | |
52 Log.e(TAG, "Unexpected image format: " + image.getFormat() | |
53 + " or #planes: " + image.getPlanes().length); | |
54 return; | |
55 } | |
56 | |
57 Image.Plane[] planes = image.getPlanes(); | |
58 ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer(); | |
59 buffer.get(mCapturedData); | |
60 | |
61 nativeOnFrameAvailable(mNativeScreenCaptureMachineAndroid, | |
62 mCapturedData, | |
63 image.getCropRect().width(), | |
64 image.getCropRect().height(), | |
65 image.getTimestamp()); | |
66 | |
67 } catch (IllegalStateException ex) { | |
68 Log.e(TAG, "acquireLatestImage():" + ex); | |
69 return; | |
70 } finally { | |
71 if (image != null) { | |
whywhat
2015/08/17 13:58:46
nit: a one liner
| |
72 image.close(); | |
73 } | |
74 } | |
75 } | |
76 }; | |
77 | |
78 private class MediaProjectionCallback extends MediaProjection.Callback { | |
79 @Override | |
80 public void onStop() { | |
81 mMediaProjection = null; | |
82 if (mVirtualDisplay == null) { | |
whywhat
2015/08/17 13:58:46
nit: one liner
| |
83 return; | |
84 } | |
85 mVirtualDisplay.release(); | |
86 mVirtualDisplay = null; | |
87 } | |
88 } | |
89 | |
90 private byte[] mCapturedData; | |
91 private final Context mContext; | |
92 | |
93 private MediaProjection mMediaProjection; | |
94 private MediaProjectionManager mMediaProjectionManager; | |
95 private VirtualDisplay mVirtualDisplay; | |
96 private static final int REQUEST_MEDIA_PROJECTION = 1; | |
97 | |
98 private Surface mSurface; | |
99 private ImageReader mImageReader = null; | |
100 private int mScreenDensity; | |
101 private int mWidth; | |
102 private int mHeight; | |
103 private int mResultCode; | |
104 private Intent mResultData; | |
105 | |
106 // Native callback context variable. | |
107 private final long mNativeScreenCaptureMachineAndroid; | |
108 | |
109 private static final String TAG = "ScreenCaptureMachine"; | |
110 | |
111 ScreenCapture(Context context, long nativeScreenCaptureMachineAndroid) { | |
112 mContext = context; | |
113 mNativeScreenCaptureMachineAndroid = nativeScreenCaptureMachineAndroid; | |
114 try { | |
115 BaseChromiumApplication ba = (BaseChromiumApplication) mContext; | |
116 Activity activity = ba.getActivity(); | |
117 if (activity == null) { | |
118 Log.e(TAG, "activity is null"); | |
119 return; | |
120 } | |
121 | |
122 FragmentManager fragmentManager = activity.getFragmentManager(); | |
123 FragmentTransaction fragmentTransaction = fragmentManager.beginTrans action(); | |
124 fragmentTransaction.add(this, "screencapture"); | |
125 fragmentTransaction.commit(); | |
126 | |
127 DisplayMetrics metrics = new DisplayMetrics(); | |
128 Display display = activity.getWindowManager().getDefaultDisplay(); | |
129 display.getMetrics(metrics); | |
130 mScreenDensity = metrics.densityDpi; | |
131 } catch (Exception e) { | |
132 Log.e(TAG, "ScreenCaptureExcaption " + e); | |
133 } | |
134 } | |
135 | |
136 @Override | |
137 public void onDetach() { | |
138 super.onDetach(); | |
139 Log.i(TAG, "onDetach"); | |
140 stopCapture(); | |
141 } | |
142 | |
143 @CalledByNative | |
144 public boolean startPrompt(int width, int height) { | |
145 Log.i(TAG, "startPrompt"); | |
146 try { | |
147 if (!isAdded()) { | |
148 Log.e(TAG, "the fragment hasn't been added to an activity"); | |
149 return false; | |
150 } | |
151 mWidth = width; | |
152 mHeight = height; | |
153 int expectedFrameSize = mWidth * mHeight * 4; | |
154 mCapturedData = new byte[expectedFrameSize]; | |
155 | |
156 mMediaProjectionManager = (MediaProjectionManager) | |
157 mContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE); | |
158 if (mMediaProjectionManager == null) { | |
159 Log.e(TAG, "mMediaProjectionManager is null"); | |
160 return false; | |
161 } | |
162 | |
163 startActivityForResult(mMediaProjectionManager.createScreenCaptureIn tent(), | |
164 REQUEST_MEDIA_PROJECTION); | |
165 } catch (Exception e) { | |
166 Log.e(TAG, "ScreenCaptureExcaption " + e); | |
167 return false; | |
168 } | |
169 return true; | |
170 } | |
171 | |
172 @Override | |
173 public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
174 if (requestCode == REQUEST_MEDIA_PROJECTION) { | |
175 int result; | |
176 if (resultCode != Activity.RESULT_OK) { | |
177 result = 0; | |
178 } else { | |
179 result = 1; | |
180 mResultCode = resultCode; | |
181 mResultData = data; | |
182 } | |
183 nativeOnActivityResult(mNativeScreenCaptureMachineAndroid, result); | |
184 } | |
185 } | |
186 | |
187 // start screen capture. | |
whywhat
2015/08/17 13:58:46
nit: follow Javadoc style for public/protected cla
| |
188 @CalledByNative | |
189 public void startCapture() { | |
190 Log.i(TAG, "startCapture"); | |
whywhat
2015/08/17 13:58:46
nit: s/Log.i/Log.d?
| |
191 mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCod e, mResultData); | |
192 if (mMediaProjection == null) { | |
193 Log.i(TAG, "mMediaProjection is null"); | |
194 return; | |
195 } | |
196 mMediaProjection.registerCallback(new MediaProjectionCallback(), null); | |
197 | |
198 final int maxImages = 2; | |
199 mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA _8888, maxImages); | |
200 mSurface = mImageReader.getSurface(); | |
201 HandlerThread thread = new HandlerThread("Screen"); | |
202 thread.start(); | |
203 final Handler backgroundHandler = new Handler(thread.getLooper()); | |
204 final CrImageReaderListener imageReaderListener = new CrImageReaderListe ner(); | |
205 mImageReader.setOnImageAvailableListener(imageReaderListener, | |
206 backgroundHandler); | |
207 | |
208 mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture", | |
209 mWidth, mHeight, mScreenDensity, | |
210 DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, | |
211 mSurface, null, null); | |
212 } | |
213 | |
214 // Stops screen capture. | |
215 @CalledByNative | |
216 public void stopCapture() { | |
217 Log.i(TAG, "stopCapture"); | |
whywhat
2015/08/17 13:58:46
ditto
| |
218 if (mMediaProjection != null) { | |
219 mMediaProjection.stop(); | |
whywhat
2015/08/17 13:58:46
nit: fits on one line
| |
220 } | |
221 } | |
222 | |
223 // Method for ScreenCapture implementations to call back native code. | |
224 public native void nativeOnFrameAvailable(long nativeScreenCaptureMachineAnd roid, | |
225 byte[] data, | |
226 int cropWidth, | |
227 int cropHeight, | |
228 long timestamp); | |
229 | |
230 // Method for ScreenCapture implementations to call back native code. | |
231 public native void nativeOnActivityResult(long nativeScreenCaptureMachineAnd roid, | |
whywhat
2015/08/17 13:58:46
Do these or @CalledByNative methdos have to be pub
| |
232 int result); | |
233 | |
234 } | |
OLD | NEW |