1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/*
2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2013 The Android Open Source Project
3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License.
6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at
7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software
11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and
14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License.
15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.photos.views;
18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.annotation.SuppressLint;
20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.annotation.TargetApi;
21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.content.Context;
22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap;
23e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Canvas;
24e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Color;
25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Matrix;
26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint;
27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Paint.Align;
28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.RectF;
29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.opengl.GLSurfaceView;
30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.opengl.GLSurfaceView.Renderer;
31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.os.Build;
32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.util.AttributeSet;
33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.Choreographer;
34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.Choreographer.FrameCallback;
35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.view.View;
36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.widget.FrameLayout;
37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.BasicTexture;
39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.gallery3d.glrenderer.GLES20Canvas;
40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport com.android.photos.views.TiledImageRenderer.TileSource;
41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport javax.microedition.khronos.egl.EGLConfig;
43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport javax.microedition.khronos.opengles.GL10;
44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/**
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * or {@link BlockingGLTextureView}.
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic class TiledImageView extends FrameLayout {
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final boolean USE_TEXTURE_VIEW = false;
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final boolean IS_SUPPORTED =
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final boolean USE_CHOREOGRAPHER =
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private BlockingGLTextureView mTextureView;
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private GLSurfaceView mGLSurfaceView;
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private boolean mInvalPending = false;
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private FrameCallback mFrameCallback;
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected static class ImageRendererWrapper {
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // Guarded by locks
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public float scale;
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int centerX, centerY;
6669784065ea78550944b7eddb559c0dac952e20e8Michael Jurka        public int rotation;
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public TileSource source;
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Runnable isReadyCallback;
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        // GL thread only
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        TiledImageRenderer image;
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private float[] mValues = new float[9];
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // -------------------------
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // Guarded by mLock
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // -------------------------
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected Object mLock = new Object();
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected ImageRendererWrapper mRenderer;
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static boolean isTilingSupported() {
83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return IS_SUPPORTED;
84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public TiledImageView(Context context) {
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        this(context, null);
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public TiledImageView(Context context, AttributeSet attrs) {
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super(context, attrs);
92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mRenderer = new ImageRendererWrapper();
97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mRenderer.image = new TiledImageRenderer(this);
98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        View view;
99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (USE_TEXTURE_VIEW) {
100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTextureView = new BlockingGLTextureView(context);
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTextureView.setRenderer(new TileRenderer());
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            view = mTextureView;
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView = new GLSurfaceView(context);
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.setEGLContextClientVersion(2);
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.setRenderer(new TileRenderer());
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            view = mGLSurfaceView;
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        addView(view, new LayoutParams(
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        //setTileSource(new ColoredTiles());
113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void destroy() {
116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (USE_TEXTURE_VIEW) {
120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTextureView.destroy();
121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.queueEvent(mFreeTextures);
123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private Runnable mFreeTextures = new Runnable() {
127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void run() {
130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.image.freeTextures();
131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    };
133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void onPause() {
135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!USE_TEXTURE_VIEW) {
139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.onPause();
140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void onResume() {
144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
147e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!USE_TEXTURE_VIEW) {
148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mGLSurfaceView.onResume();
149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setTileSource(TileSource source, Runnable isReadyCallback) {
153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        synchronized (mLock) {
157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.source = source;
158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.isReadyCallback = isReadyCallback;
159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0;
160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0;
161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.rotation = source != null ? source.getRotation() : 0;
162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.scale = 0;
163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            updateScaleIfNecessaryLocked(mRenderer);
164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        invalidate();
166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void onLayout(boolean changed, int left, int top, int right,
170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int bottom) {
171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.onLayout(changed, left, top, right, bottom);
172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        synchronized (mLock) {
176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            updateScaleIfNecessaryLocked(mRenderer);
177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) {
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (renderer == null || renderer.source == null
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                || renderer.scale > 0 || getWidth() == 0) {
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        renderer.scale = Math.min(
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                (float) getWidth() / (float) renderer.source.getImageWidth(),
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                (float) getHeight() / (float) renderer.source.getImageHeight());
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void dispatchDraw(Canvas canvas) {
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (USE_TEXTURE_VIEW) {
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTextureView.render();
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.dispatchDraw(canvas);
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @SuppressLint("NewApi")
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setTranslationX(float translationX) {
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.setTranslationX(translationX);
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void invalidate() {
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (USE_TEXTURE_VIEW) {
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            super.invalidate();
217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTextureView.invalidate();
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (USE_CHOREOGRAPHER) {
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                invalOnVsync();
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
222e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mGLSurfaceView.requestRender();
223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void invalOnVsync() {
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!mInvalPending) {
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mInvalPending = true;
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mFrameCallback == null) {
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mFrameCallback = new FrameCallback() {
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    @Override
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    public void doFrame(long frameTimeNanos) {
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mInvalPending = false;
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mGLSurfaceView.requestRender();
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                };
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Choreographer.getInstance().postFrameCallback(mFrameCallback);
241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private RectF mTempRectF = new RectF();
245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void positionFromMatrix(Matrix matrix) {
246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!IS_SUPPORTED) {
247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return;
248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mRenderer.source != null) {
250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final int rotation = mRenderer.source.getRotation();
251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final boolean swap = !(rotation % 180 == 0);
252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final int width = swap ? mRenderer.source.getImageHeight()
253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    : mRenderer.source.getImageWidth();
254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            final int height = swap ? mRenderer.source.getImageWidth()
255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    : mRenderer.source.getImageHeight();
256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mTempRectF.set(0, 0, width, height);
257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            matrix.mapRect(mTempRectF);
258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            matrix.getValues(mValues);
259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int cx = width / 2;
260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int cy = height / 2;
261e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            float scale = mValues[Matrix.MSCALE_X];
262e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale);
263e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale);
264e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (rotation == 90 || rotation == 180) {
265e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                cx += (mTempRectF.left / scale) - xoffset;
266e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
267e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                cx -= (mTempRectF.left / scale) - xoffset;
268e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
269e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (rotation == 180 || rotation == 270) {
270e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                cy += (mTempRectF.top / scale) - yoffset;
271e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } else {
272e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                cy -= (mTempRectF.top / scale) - yoffset;
273e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
274e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.scale = scale;
275e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.centerX = swap ? cy : cx;
276e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.centerY = swap ? cx : cy;
277e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            invalidate();
278e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
279e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
280e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
281e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private class TileRenderer implements Renderer {
282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
283e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private GLES20Canvas mCanvas;
284e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
285e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas = new GLES20Canvas();
288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            BasicTexture.invalidateAllTextures();
289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void onSurfaceChanged(GL10 gl, int width, int height) {
294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.setSize(width, height);
295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mRenderer.image.setViewSize(width, height);
296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
299e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public void onDrawFrame(GL10 gl) {
300e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.clearBuffer();
301e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Runnable readyCallback;
302e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            synchronized (mLock) {
303e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                readyCallback = mRenderer.isReadyCallback;
304e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
305e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY,
306e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mRenderer.scale);
307e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
308e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            boolean complete = mRenderer.image.draw(mCanvas);
309e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (complete && readyCallback != null) {
310e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                synchronized (mLock) {
311e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // Make sure we don't trample on a newly set callback/source
312e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // if it changed while we were rendering
313e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mRenderer.isReadyCallback == readyCallback) {
314e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        mRenderer.isReadyCallback = null;
315e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
316e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
317e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (readyCallback != null) {
318e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    post(readyCallback);
319e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
320e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
321e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
322e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
323e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
324e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
325e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @SuppressWarnings("unused")
326e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static class ColoredTiles implements TileSource {
327e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private static final int[] COLORS = new int[] {
328e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.RED,
329e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.BLUE,
330e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.YELLOW,
331e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.GREEN,
332e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.CYAN,
333e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.MAGENTA,
334e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Color.WHITE,
335e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        };
336e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
337e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private Paint mPaint = new Paint();
338e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        private Canvas mCanvas = new Canvas();
339e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
340e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
341e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getTileSize() {
342e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return 256;
343e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
344e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
345e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
346e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getImageWidth() {
347e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return 16384;
348e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
349e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
350e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
351e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getImageHeight() {
352e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return 8192;
353e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
354e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
355e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
356e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int getRotation() {
357e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return 0;
358e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
359e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
360e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
361e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
362e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int tileSize = getTileSize();
363e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (bitmap == null) {
364e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                bitmap = Bitmap.createBitmap(tileSize, tileSize,
365e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Bitmap.Config.ARGB_8888);
366e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
367e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.setBitmap(bitmap);
368e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.drawColor(COLORS[level]);
369e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPaint.setColor(Color.BLACK);
370e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPaint.setTextSize(20);
371e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mPaint.setTextAlign(Align.CENTER);
372e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.drawText(x + "x" + y, 128, 128, mPaint);
373e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            tileSize <<= level;
374e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            x /= tileSize;
375e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            y /= tileSize;
376e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint);
377e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mCanvas.setBitmap(null);
378e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return bitmap;
379e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
380e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
381e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
382e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BasicTexture getPreview() {
383e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return null;
384e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
385e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
386e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka}
387