1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org
.mozilla
.gecko
.gfx
;
9 import android
.content
.Context
;
10 import android
.content
.res
.Resources
;
11 import android
.graphics
.Bitmap
;
12 import android
.graphics
.BitmapFactory
;
13 import android
.graphics
.PixelFormat
;
14 import android
.util
.AttributeSet
;
15 import android
.util
.Log
;
16 import android
.view
.KeyEvent
;
17 import android
.view
.MotionEvent
;
18 import android
.view
.SurfaceHolder
;
19 import android
.view
.SurfaceView
;
20 import android
.view
.View
;
21 import android
.view
.ViewGroup
;
22 import android
.view
.inputmethod
.EditorInfo
;
23 import android
.view
.inputmethod
.InputConnection
;
24 import android
.widget
.FrameLayout
;
26 import org
.libreoffice
.LOEvent
;
27 import org
.libreoffice
.LOKitShell
;
28 import org
.libreoffice
.LibreOfficeMainActivity
;
29 import org
.libreoffice
.R
;
30 import org
.mozilla
.gecko
.OnInterceptTouchListener
;
31 import org
.mozilla
.gecko
.OnSlideSwipeListener
;
34 * A view rendered by the layer compositor.
36 * This view delegates to LayerRenderer to actually do the drawing. Its role is largely that of a
37 * mediator between the LayerRenderer and the LayerController.
39 public class LayerView
extends FrameLayout
{
40 private static String LOGTAG
= LayerView
.class.getName();
42 private GeckoLayerClient mLayerClient
;
43 private PanZoomController mPanZoomController
;
44 private GLController mGLController
;
45 private InputConnectionHandler mInputConnectionHandler
;
46 private LayerRenderer mRenderer
;
48 private SurfaceView mSurfaceView
;
50 private Listener mListener
;
51 private OnInterceptTouchListener mTouchIntercepter
;
52 private LibreOfficeMainActivity mContext
;
54 public LayerView(Context context
, AttributeSet attrs
) {
55 super(context
, attrs
);
56 mContext
= (LibreOfficeMainActivity
) context
;
58 mSurfaceView
= new SurfaceView(context
);
59 addView(mSurfaceView
, ViewGroup
.LayoutParams
.MATCH_PARENT
, ViewGroup
.LayoutParams
.MATCH_PARENT
);
61 SurfaceHolder holder
= mSurfaceView
.getHolder();
62 holder
.addCallback(new SurfaceListener());
63 holder
.setFormat(PixelFormat
.RGB_565
);
65 mGLController
= new GLController(this);
68 void connect(GeckoLayerClient layerClient
) {
69 mLayerClient
= layerClient
;
70 mPanZoomController
= mLayerClient
.getPanZoomController();
71 mRenderer
= new LayerRenderer(this);
72 mInputConnectionHandler
= null;
75 setFocusableInTouchMode(true);
78 setOnTouchListener(new OnSlideSwipeListener(getContext(), mLayerClient
));
82 // Fix this if TextureView support is turned back on above
83 mSurfaceView
.setVisibility(View
.VISIBLE
);
87 // Fix this if TextureView support is turned back on above
88 mSurfaceView
.setVisibility(View
.INVISIBLE
);
91 public void destroy() {
92 if (mLayerClient
!= null) {
93 mLayerClient
.destroy();
95 if (mRenderer
!= null) {
100 public void setTouchIntercepter(final OnInterceptTouchListener touchIntercepter
) {
101 // this gets run on the gecko thread, but for thread safety we want the assignment
103 post(new Runnable() {
105 mTouchIntercepter
= touchIntercepter
;
110 public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler
) {
111 mInputConnectionHandler
= inputConnectionHandler
;
115 public boolean onTouchEvent(MotionEvent event
) {
116 if (event
.getActionMasked() == MotionEvent
.ACTION_DOWN
) {
120 if (mTouchIntercepter
!= null && mTouchIntercepter
.onInterceptTouchEvent(this, event
)) {
123 if (mPanZoomController
!= null && mPanZoomController
.onTouchEvent(event
)) {
126 if (mTouchIntercepter
!= null && mTouchIntercepter
.onTouch(this, event
)) {
133 public boolean onHoverEvent(MotionEvent event
) {
134 return mTouchIntercepter
!= null && mTouchIntercepter
.onTouch(this, event
);
138 public boolean onGenericMotionEvent(MotionEvent event
) {
139 return mPanZoomController
!= null && mPanZoomController
.onMotionEvent(event
);
142 public GeckoLayerClient
getLayerClient() { return mLayerClient
; }
143 public PanZoomController
getPanZoomController() { return mPanZoomController
; }
145 public ImmutableViewportMetrics
getViewportMetrics() {
146 return mLayerClient
.getViewportMetrics();
150 public InputConnection
onCreateInputConnection(EditorInfo outAttrs
) {
151 if (mInputConnectionHandler
!= null)
152 return mInputConnectionHandler
.onCreateInputConnection(outAttrs
);
157 public boolean onKeyPreIme(int keyCode
, KeyEvent event
) {
158 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyPreIme(keyCode
, event
);
162 public boolean onKeyDown(int keyCode
, KeyEvent event
) {
163 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyDown(keyCode
, event
);
167 public boolean onKeyLongPress(int keyCode
, KeyEvent event
) {
168 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyLongPress(keyCode
, event
);
172 public boolean onKeyMultiple(int keyCode
, int repeatCount
, KeyEvent event
) {
173 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyMultiple(keyCode
, repeatCount
, event
);
177 public boolean onKeyUp(int keyCode
, KeyEvent event
) {
178 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyUp(keyCode
, event
);
181 public void requestRender() {
182 if (mListener
!= null) {
183 mListener
.renderRequested();
187 public void addLayer(Layer layer
) {
188 mRenderer
.addLayer(layer
);
191 public void removeLayer(Layer layer
) {
192 mRenderer
.removeLayer(layer
);
195 public int getMaxTextureSize() {
196 return mRenderer
.getMaxTextureSize();
199 public void setLayerRenderer(LayerRenderer renderer
) {
200 mRenderer
= renderer
;
203 public LayerRenderer
getLayerRenderer() {
207 public LayerRenderer
getRenderer() {
211 public void setListener(Listener listener
) {
212 mListener
= listener
;
215 Listener
getListener() {
219 public GLController
getGLController() {
220 return mGLController
;
223 public Bitmap
getDrawable(String name
) {
224 Context context
= getContext();
225 Resources resources
= context
.getResources();
226 String packageName
= resources
.getResourcePackageName(R
.id
.dummy_id_for_package_name_resolution
);
227 int resourceID
= resources
.getIdentifier(name
, "drawable", packageName
);
228 BitmapFactory
.Options options
= new BitmapFactory
.Options();
229 options
.inScaled
= false;
230 return BitmapFactory
.decodeResource(context
.getResources(), resourceID
, options
);
233 Bitmap
getBackgroundPattern() {
234 return getDrawable("background");
237 Bitmap
getShadowPattern() {
238 return getDrawable("shadow");
241 private void onSizeChanged(int width
, int height
) {
242 mGLController
.surfaceChanged(width
, height
);
244 mLayerClient
.setViewportSize(new FloatSize(width
, height
), false);
246 if (mListener
!= null) {
247 mListener
.surfaceChanged(width
, height
);
250 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UPDATE_ZOOM_CONSTRAINTS
));
253 private void onDestroyed() {
254 mGLController
.surfaceDestroyed();
256 if (mListener
!= null) {
257 mListener
.compositionPauseRequested();
261 public Object
getNativeWindow() {
262 return mSurfaceView
.getHolder();
265 public interface Listener
{
266 void compositorCreated();
267 void renderRequested();
268 void compositionPauseRequested();
269 void surfaceChanged(int width
, int height
);
272 private class SurfaceListener
implements SurfaceHolder
.Callback
{
273 public void surfaceChanged(SurfaceHolder holder
, int format
, int width
,
275 onSizeChanged(width
, height
);
278 public void surfaceCreated(SurfaceHolder holder
) {
279 if (mRenderControllerThread
!= null) {
280 mRenderControllerThread
.surfaceCreated();
284 public void surfaceDestroyed(SurfaceHolder holder
) {
290 protected void onLayout(boolean changed
, int left
, int top
, int right
, int bottom
) {
291 super.onLayout(changed
, left
, top
, right
, bottom
);
293 mLayerClient
.setViewportSize(new FloatSize(right
- left
, bottom
- top
), true);
297 private RenderControllerThread mRenderControllerThread
;
299 public synchronized void createGLThread() {
300 if (mRenderControllerThread
!= null) {
301 throw new LayerViewException ("createGLThread() called with a GL thread already in place!");
304 Log
.e(LOGTAG
, "### Creating GL thread!");
305 mRenderControllerThread
= new RenderControllerThread(mGLController
);
306 mRenderControllerThread
.start();
307 setListener(mRenderControllerThread
);
311 public synchronized Thread
destroyGLThread() {
312 // Wait for the GL thread to be started.
313 Log
.e(LOGTAG
, "### Waiting for GL thread to be created...");
314 while (mRenderControllerThread
== null) {
317 } catch (InterruptedException e
) {
318 throw new RuntimeException(e
);
322 Log
.e(LOGTAG
, "### Destroying GL thread!");
323 Thread thread
= mRenderControllerThread
;
324 mRenderControllerThread
.shutdown();
326 mRenderControllerThread
= null;
330 public static class LayerViewException
extends RuntimeException
{
331 public static final long serialVersionUID
= 1L;
333 LayerViewException(String e
) {