Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / android / source / src / java / org / mozilla / gecko / gfx / LayerView.java
blobc3f639ddf7d154cb2ed7737f1e9b0ee5d3fad26c
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;
33 /**
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;
87 setFocusable(true);
88 setFocusableInTouchMode(true);
90 createGLThread();
91 setOnTouchListener(new OnSlideSwipeListener(getContext(), mLayerClient));
94 public void show() {
95 // Fix this if TextureView support is turned back on above
96 mSurfaceView.setVisibility(View.VISIBLE);
99 public void hide() {
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) {
109 mRenderer.destroy();
113 public void setTouchIntercepter(final OnInterceptTouchListener touchIntercepter) {
114 // this gets run on the gecko thread, but for thread safety we want the assignment
115 // on the UI thread.
116 post(new Runnable() {
117 public void run() {
118 mTouchIntercepter = touchIntercepter;
123 public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) {
124 mInputConnectionHandler = inputConnectionHandler;
127 @Override
128 public boolean onTouchEvent(MotionEvent event) {
129 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
130 requestFocus();
133 if (mTouchIntercepter != null && mTouchIntercepter.onInterceptTouchEvent(this, event)) {
134 return true;
136 if (mPanZoomController != null && mPanZoomController.onTouchEvent(event)) {
137 return true;
139 if (mTouchIntercepter != null && mTouchIntercepter.onTouch(this, event)) {
140 return true;
142 return false;
145 @Override
146 public boolean onHoverEvent(MotionEvent event) {
147 return mTouchIntercepter != null && mTouchIntercepter.onTouch(this, event);
150 @Override
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();
162 @Override
163 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
164 if (mInputConnectionHandler != null)
165 return mInputConnectionHandler.onCreateInputConnection(outAttrs);
166 return null;
169 @Override
170 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
171 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyPreIme(keyCode, event);
174 @Override
175 public boolean onKeyDown(int keyCode, KeyEvent event) {
176 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyDown(keyCode, event);
179 @Override
180 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
181 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyLongPress(keyCode, event);
184 @Override
185 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
186 return mInputConnectionHandler != null && mInputConnectionHandler.onKeyMultiple(keyCode, repeatCount, event);
189 @Override
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() {
217 return mRenderer;
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() {
230 return mPaintState;
233 public LayerRenderer getRenderer() {
234 return mRenderer;
237 public void setListener(Listener listener) {
238 mListener = listener;
241 Listener getListener() {
242 return mListener;
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() {
293 try {
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);
299 return null;
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,
313 int height) {
314 onSizeChanged(width, height);
317 public void surfaceCreated(SurfaceHolder holder) {
318 if (mRenderControllerThread != null) {
319 mRenderControllerThread.surfaceCreated();
323 public void surfaceDestroyed(SurfaceHolder holder) {
324 onDestroyed();
328 @Override
329 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
330 super.onLayout(changed, left, top, right, bottom);
331 if (changed) {
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);
347 notifyAll();
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) {
354 try {
355 wait();
356 } catch (InterruptedException e) {
357 throw new RuntimeException(e);
361 Log.e(LOGTAG, "### Destroying GL thread!");
362 Thread thread = mRenderControllerThread;
363 mRenderControllerThread.shutdown();
364 setListener(null);
365 mRenderControllerThread = null;
366 return thread;
369 public static class LayerViewException extends RuntimeException {
370 public static final long serialVersionUID = 1L;
372 LayerViewException(String e) {
373 super(e);
377 public void setFullScreen(boolean fullScreen) {
378 mFullScreen = fullScreen;
381 public boolean isFullScreen() {
382 return mFullScreen;