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 * Note that LayerView is accessed by Robocop via reflection.
41 public class LayerView
extends FrameLayout
{
42 private static String LOGTAG
= LayerView
.class.getName();
44 private GeckoLayerClient mLayerClient
;
45 private PanZoomController mPanZoomController
;
46 private GLController mGLController
;
47 private InputConnectionHandler mInputConnectionHandler
;
48 private LayerRenderer mRenderer
;
50 /* Must be a PAINT_xxx constant */
51 private int mPaintState
= PAINT_NONE
;
52 private boolean mFullScreen
= false;
54 private SurfaceView mSurfaceView
;
56 private Listener mListener
;
57 private OnInterceptTouchListener mTouchIntercepter
;
58 //TODO static because of registerCxxCompositor() function, should be fixed in the future
59 private static LibreOfficeMainActivity mContext
;
61 /* Flags used to determine when to show the painted surface. The integer
62 * order must correspond to the order in which these states occur. */
63 public static final int PAINT_NONE
= 0;
64 public static final int PAINT_BEFORE_FIRST
= 1;
65 public static final int PAINT_AFTER_FIRST
= 2;
67 public LayerView(Context context
, AttributeSet attrs
) {
68 super(context
, attrs
);
69 mContext
= (LibreOfficeMainActivity
) context
;
71 mSurfaceView
= new SurfaceView(context
);
72 addView(mSurfaceView
, ViewGroup
.LayoutParams
.MATCH_PARENT
, ViewGroup
.LayoutParams
.MATCH_PARENT
);
74 SurfaceHolder holder
= mSurfaceView
.getHolder();
75 holder
.addCallback(new SurfaceListener());
76 holder
.setFormat(PixelFormat
.RGB_565
);
78 mGLController
= new GLController(this);
81 void connect(GeckoLayerClient layerClient
) {
82 mLayerClient
= layerClient
;
83 mPanZoomController
= mLayerClient
.getPanZoomController();
84 mRenderer
= new LayerRenderer(this);
85 mInputConnectionHandler
= null;
88 setFocusableInTouchMode(true);
91 setOnTouchListener(new OnSlideSwipeListener(getContext(), mLayerClient
));
95 // Fix this if TextureView support is turned back on above
96 mSurfaceView
.setVisibility(View
.VISIBLE
);
100 // Fix this if TextureView support is turned back on above
101 mSurfaceView
.setVisibility(View
.INVISIBLE
);
104 public void destroy() {
105 if (mLayerClient
!= null) {
106 mLayerClient
.destroy();
108 if (mRenderer
!= null) {
113 public void setTouchIntercepter(final OnInterceptTouchListener touchIntercepter
) {
114 // this gets run on the gecko thread, but for thread safety we want the assignment
116 post(new Runnable() {
118 mTouchIntercepter
= touchIntercepter
;
123 public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler
) {
124 mInputConnectionHandler
= inputConnectionHandler
;
128 public boolean onTouchEvent(MotionEvent event
) {
129 if (event
.getActionMasked() == MotionEvent
.ACTION_DOWN
) {
133 if (mTouchIntercepter
!= null && mTouchIntercepter
.onInterceptTouchEvent(this, event
)) {
136 if (mPanZoomController
!= null && mPanZoomController
.onTouchEvent(event
)) {
139 if (mTouchIntercepter
!= null && mTouchIntercepter
.onTouch(this, event
)) {
146 public boolean onHoverEvent(MotionEvent event
) {
147 return mTouchIntercepter
!= null && mTouchIntercepter
.onTouch(this, event
);
151 public boolean onGenericMotionEvent(MotionEvent event
) {
152 return mPanZoomController
!= null && mPanZoomController
.onMotionEvent(event
);
155 public GeckoLayerClient
getLayerClient() { return mLayerClient
; }
156 public PanZoomController
getPanZoomController() { return mPanZoomController
; }
158 public ImmutableViewportMetrics
getViewportMetrics() {
159 return mLayerClient
.getViewportMetrics();
163 public InputConnection
onCreateInputConnection(EditorInfo outAttrs
) {
164 if (mInputConnectionHandler
!= null)
165 return mInputConnectionHandler
.onCreateInputConnection(outAttrs
);
170 public boolean onKeyPreIme(int keyCode
, KeyEvent event
) {
171 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyPreIme(keyCode
, event
);
175 public boolean onKeyDown(int keyCode
, KeyEvent event
) {
176 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyDown(keyCode
, event
);
180 public boolean onKeyLongPress(int keyCode
, KeyEvent event
) {
181 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyLongPress(keyCode
, event
);
185 public boolean onKeyMultiple(int keyCode
, int repeatCount
, KeyEvent event
) {
186 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyMultiple(keyCode
, repeatCount
, event
);
190 public boolean onKeyUp(int keyCode
, KeyEvent event
) {
191 return mInputConnectionHandler
!= null && mInputConnectionHandler
.onKeyUp(keyCode
, event
);
194 public void requestRender() {
195 if (mListener
!= null) {
196 mListener
.renderRequested();
200 public void addLayer(Layer layer
) {
201 mRenderer
.addLayer(layer
);
204 public void removeLayer(Layer layer
) {
205 mRenderer
.removeLayer(layer
);
208 public int getMaxTextureSize() {
209 return mRenderer
.getMaxTextureSize();
212 public void setLayerRenderer(LayerRenderer renderer
) {
213 mRenderer
= renderer
;
216 public LayerRenderer
getLayerRenderer() {
220 /* paintState must be a PAINT_xxx constant. The state will only be changed
221 * if paintState represents a state that occurs after the current state. */
222 public void setPaintState(int paintState
) {
223 if (paintState
> mPaintState
) {
224 Log
.d(LOGTAG
, "LayerView paint state set to " + paintState
);
225 mPaintState
= paintState
;
229 public int getPaintState() {
233 public LayerRenderer
getRenderer() {
237 public void setListener(Listener listener
) {
238 mListener
= listener
;
241 Listener
getListener() {
245 public GLController
getGLController() {
246 return mGLController
;
249 public Bitmap
getDrawable(String name
) {
250 Context context
= getContext();
251 Resources resources
= context
.getResources();
252 String packageName
= resources
.getResourcePackageName(R
.id
.dummy_id_for_package_name_resolution
);
253 int resourceID
= resources
.getIdentifier(name
, "drawable", packageName
);
254 BitmapFactory
.Options options
= new BitmapFactory
.Options();
255 options
.inScaled
= false;
256 return BitmapFactory
.decodeResource(context
.getResources(), resourceID
, options
);
259 Bitmap
getBackgroundPattern() {
260 return getDrawable("background");
263 Bitmap
getShadowPattern() {
264 return getDrawable("shadow");
267 private void onSizeChanged(int width
, int height
) {
268 mGLController
.surfaceChanged(width
, height
);
270 mLayerClient
.setViewportSize(new FloatSize(width
, height
), false);
272 if (mListener
!= null) {
273 mListener
.surfaceChanged(width
, height
);
276 LOKitShell
.sendEvent(new LOEvent(LOEvent
.UPDATE_ZOOM_CONSTRAINTS
));
279 private void onDestroyed() {
280 mGLController
.surfaceDestroyed();
282 if (mListener
!= null) {
283 mListener
.compositionPauseRequested();
287 public Object
getNativeWindow() {
288 return mSurfaceView
.getHolder();
291 /** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */
292 public static GLController
registerCxxCompositor() {
294 LayerView layerView
= mContext
.getLayerClient().getView();
295 layerView
.mListener
.compositorCreated();
296 return layerView
.getGLController();
297 } catch (Exception e
) {
298 Log
.e(LOGTAG
, "Error registering compositor!", e
);
303 public interface Listener
{
304 void compositorCreated();
305 void renderRequested();
306 void compositionPauseRequested();
307 void compositionResumeRequested(int width
, int height
);
308 void surfaceChanged(int width
, int height
);
311 private class SurfaceListener
implements SurfaceHolder
.Callback
{
312 public void surfaceChanged(SurfaceHolder holder
, int format
, int width
,
314 onSizeChanged(width
, height
);
317 public void surfaceCreated(SurfaceHolder holder
) {
318 if (mRenderControllerThread
!= null) {
319 mRenderControllerThread
.surfaceCreated();
323 public void surfaceDestroyed(SurfaceHolder holder
) {
329 protected void onLayout(boolean changed
, int left
, int top
, int right
, int bottom
) {
330 super.onLayout(changed
, left
, top
, right
, bottom
);
332 mLayerClient
.setViewportSize(new FloatSize(right
- left
, bottom
- top
), true);
336 private RenderControllerThread mRenderControllerThread
;
338 public synchronized void createGLThread() {
339 if (mRenderControllerThread
!= null) {
340 throw new LayerViewException ("createGLThread() called with a GL thread already in place!");
343 Log
.e(LOGTAG
, "### Creating GL thread!");
344 mRenderControllerThread
= new RenderControllerThread(mGLController
);
345 mRenderControllerThread
.start();
346 setListener(mRenderControllerThread
);
350 public synchronized Thread
destroyGLThread() {
351 // Wait for the GL thread to be started.
352 Log
.e(LOGTAG
, "### Waiting for GL thread to be created...");
353 while (mRenderControllerThread
== null) {
356 } catch (InterruptedException e
) {
357 throw new RuntimeException(e
);
361 Log
.e(LOGTAG
, "### Destroying GL thread!");
362 Thread thread
= mRenderControllerThread
;
363 mRenderControllerThread
.shutdown();
365 mRenderControllerThread
= null;
369 public static class LayerViewException
extends RuntimeException
{
370 public static final long serialVersionUID
= 1L;
372 LayerViewException(String e
) {
377 public void setFullScreen(boolean fullScreen
) {
378 mFullScreen
= fullScreen
;
381 public boolean isFullScreen() {