• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.photos.views;
18 
19 import android.content.Context;
20 import android.opengl.GLSurfaceView;
21 import android.opengl.GLSurfaceView.Renderer;
22 import android.util.AttributeSet;
23 import android.view.Choreographer;
24 import android.view.Choreographer.FrameCallback;
25 import android.widget.FrameLayout;
26 
27 import com.android.gallery3d.glrenderer.BasicTexture;
28 import com.android.gallery3d.glrenderer.GLES20Canvas;
29 import com.android.photos.views.TiledImageRenderer.TileSource;
30 
31 import javax.microedition.khronos.egl.EGLConfig;
32 import javax.microedition.khronos.opengles.GL10;
33 
34 /**
35  * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}.
36  */
37 public class TiledImageView extends FrameLayout {
38 
39     private GLSurfaceView mGLSurfaceView;
40     private boolean mInvalPending = false;
41     private FrameCallback mFrameCallback;
42 
43     protected static class ImageRendererWrapper {
44         // Guarded by locks
45         public float scale;
46         public int centerX, centerY;
47         public int rotation;
48         public TileSource source;
49         Runnable isReadyCallback;
50 
51         // GL thread only
52         TiledImageRenderer image;
53     }
54 
55     private float[] mValues = new float[9];
56 
57     // -------------------------
58     // Guarded by mLock
59     // -------------------------
60     protected Object mLock = new Object();
61     protected ImageRendererWrapper mRenderer;
62 
TiledImageView(Context context)63     public TiledImageView(Context context) {
64         this(context, null);
65     }
66 
TiledImageView(Context context, AttributeSet attrs)67     public TiledImageView(Context context, AttributeSet attrs) {
68         super(context, attrs);
69         mRenderer = new ImageRendererWrapper();
70         mRenderer.image = new TiledImageRenderer(this);
71         mGLSurfaceView = new GLSurfaceView(context);
72         mGLSurfaceView.setEGLContextClientVersion(2);
73         mGLSurfaceView.setRenderer(new TileRenderer());
74         mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
75         addView(mGLSurfaceView, new LayoutParams(
76                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
77     }
78 
79     @Override
setVisibility(int visibility)80     public void setVisibility(int visibility) {
81         super.setVisibility(visibility);
82         // need to update inner view's visibility because it seems like we're causing it to draw
83         // from {@link #dispatchDraw} or {@link #invalidate} even if we are invisible.
84         mGLSurfaceView.setVisibility(visibility);
85     }
86 
destroy()87     public void destroy() {
88         mGLSurfaceView.queueEvent(mFreeTextures);
89     }
90 
91     private Runnable mFreeTextures = new Runnable() {
92 
93         @Override
94         public void run() {
95             mRenderer.image.freeTextures();
96         }
97     };
98 
onPause()99     public void onPause() {
100         mGLSurfaceView.onPause();
101     }
102 
onResume()103     public void onResume() {
104         mGLSurfaceView.onResume();
105     }
106 
setTileSource(TileSource source, Runnable isReadyCallback)107     public void setTileSource(TileSource source, Runnable isReadyCallback) {
108         synchronized (mLock) {
109             mRenderer.source = source;
110             mRenderer.isReadyCallback = isReadyCallback;
111             mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0;
112             mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0;
113             mRenderer.rotation = source != null ? source.getRotation() : 0;
114             mRenderer.scale = 0;
115             updateScaleIfNecessaryLocked(mRenderer);
116         }
117         invalidate();
118     }
119 
getTileSource()120     public TileSource getTileSource() {
121         return mRenderer.source;
122     }
123 
124     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)125     protected void onLayout(boolean changed, int left, int top, int right,
126             int bottom) {
127         super.onLayout(changed, left, top, right, bottom);
128         synchronized (mLock) {
129             updateScaleIfNecessaryLocked(mRenderer);
130         }
131     }
132 
updateScaleIfNecessaryLocked(ImageRendererWrapper renderer)133     private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) {
134         if (renderer == null || renderer.source == null
135                 || renderer.scale > 0 || getWidth() == 0) {
136             return;
137         }
138         renderer.scale = Math.min(
139                 (float) getWidth() / (float) renderer.source.getImageWidth(),
140                 (float) getHeight() / (float) renderer.source.getImageHeight());
141     }
142 
143     @Override
invalidate()144     public void invalidate() {
145         invalOnVsync();
146     }
147 
invalOnVsync()148     private void invalOnVsync() {
149         if (!mInvalPending) {
150             mInvalPending = true;
151             if (mFrameCallback == null) {
152                 mFrameCallback = new FrameCallback() {
153                     @Override
154                     public void doFrame(long frameTimeNanos) {
155                         mInvalPending = false;
156                         mGLSurfaceView.requestRender();
157                     }
158                 };
159             }
160             Choreographer.getInstance().postFrameCallback(mFrameCallback);
161         }
162     }
163 
164     private class TileRenderer implements Renderer {
165 
166         private GLES20Canvas mCanvas;
167 
168         @Override
onSurfaceCreated(GL10 gl, EGLConfig config)169         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
170             mCanvas = new GLES20Canvas();
171             BasicTexture.invalidateAllTextures();
172             mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
173         }
174 
175         @Override
onSurfaceChanged(GL10 gl, int width, int height)176         public void onSurfaceChanged(GL10 gl, int width, int height) {
177             mCanvas.setSize(width, height);
178             mRenderer.image.setViewSize(width, height);
179         }
180 
181         @Override
onDrawFrame(GL10 gl)182         public void onDrawFrame(GL10 gl) {
183             mCanvas.clearBuffer();
184             Runnable readyCallback;
185             synchronized (mLock) {
186                 readyCallback = mRenderer.isReadyCallback;
187                 mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
188                 mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY,
189                         mRenderer.scale);
190             }
191             boolean complete = mRenderer.image.draw(mCanvas);
192             if (complete && readyCallback != null) {
193                 synchronized (mLock) {
194                     // Make sure we don't trample on a newly set callback/source
195                     // if it changed while we were rendering
196                     if (mRenderer.isReadyCallback == readyCallback) {
197                         mRenderer.isReadyCallback = null;
198                     }
199                 }
200                 if (readyCallback != null) {
201                     post(readyCallback);
202                 }
203             }
204         }
205 
206     }
207 }
208