1/*
2 * Copyright (C) 2016 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
17package com.android.test.hwui;
18
19import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
20import static android.opengl.GLES20.glClear;
21import static android.opengl.GLES20.glClearColor;
22
23import android.app.Activity;
24import android.graphics.Color;
25import android.graphics.SurfaceTexture;
26import android.opengl.GLUtils;
27import android.os.Bundle;
28import android.util.Log;
29import android.view.TextureView;
30import android.view.TextureView.SurfaceTextureListener;
31import android.view.View;
32import android.view.ViewGroup.LayoutParams;
33import android.widget.FrameLayout;
34import android.widget.TextView;
35
36import javax.microedition.khronos.egl.EGL10;
37import javax.microedition.khronos.egl.EGLConfig;
38import javax.microedition.khronos.egl.EGLContext;
39import javax.microedition.khronos.egl.EGLDisplay;
40import javax.microedition.khronos.egl.EGLSurface;
41
42public class SingleFrameTextureViewTestActivity extends Activity implements SurfaceTextureListener {
43    private static final String LOG_TAG = "SingleFrameTest";
44
45    private View mPreview;
46    private TextureView mTextureView;
47    private Thread mGLThread;
48
49    @Override
50    protected void onCreate(Bundle savedInstanceState) {
51        super.onCreate(savedInstanceState);
52        TextView preview = new TextView(this);
53        preview.setText("This is a preview");
54        preview.setBackgroundColor(Color.WHITE);
55        mPreview = preview;
56        mTextureView = new TextureView(this);
57        mTextureView.setSurfaceTextureListener(this);
58
59        FrameLayout content = new FrameLayout(this);
60        content.addView(mTextureView,
61                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
62        content.addView(mPreview,
63                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
64
65        setContentView(content);
66    }
67
68    private void stopGlThread() {
69        if (mGLThread != null) {
70            try {
71                mGLThread.join();
72                mGLThread = null;
73            } catch (InterruptedException e) { }
74        }
75    }
76
77    @Override
78    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
79        Log.d(LOG_TAG, "onSurfaceAvailable");
80        mGLThread = new Thread() {
81            static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
82            static final int EGL_OPENGL_ES2_BIT = 4;
83
84            private EGL10 mEgl;
85            private EGLDisplay mEglDisplay;
86            private EGLConfig mEglConfig;
87            private EGLContext mEglContext;
88            private EGLSurface mEglSurface;
89
90            @Override
91            public void run() {
92                initGL();
93                try {
94                    Thread.sleep(500);
95                } catch (InterruptedException e) {}
96
97                for (int i = 0; i < 2; i++) {
98                    if (i == 0) {
99                        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
100                    } else {
101                        glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
102                    }
103                    glClear(GL_COLOR_BUFFER_BIT);
104                    Log.d(LOG_TAG, "eglSwapBuffers");
105                    if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
106                        throw new RuntimeException("Cannot swap buffers");
107                    }
108                    try {
109                        Thread.sleep(50);
110                    } catch (InterruptedException e) {}
111                }
112
113                try {
114                    Thread.sleep(500);
115                } catch (InterruptedException e) {}
116
117                finishGL();
118            }
119
120            private void finishGL() {
121                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
122                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
123            }
124
125            private void initGL() {
126                mEgl = (EGL10) EGLContext.getEGL();
127
128                mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
129                if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
130                    throw new RuntimeException("eglGetDisplay failed "
131                            + GLUtils.getEGLErrorString(mEgl.eglGetError()));
132                }
133
134                int[] version = new int[2];
135                if (!mEgl.eglInitialize(mEglDisplay, version)) {
136                    throw new RuntimeException("eglInitialize failed " +
137                            GLUtils.getEGLErrorString(mEgl.eglGetError()));
138                }
139
140                mEglConfig = chooseEglConfig();
141                if (mEglConfig == null) {
142                    throw new RuntimeException("eglConfig not initialized");
143                }
144
145                mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
146
147                mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
148
149                if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
150                    int error = mEgl.eglGetError();
151                    if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
152                        Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
153                        return;
154                    }
155                    throw new RuntimeException("createWindowSurface failed "
156                            + GLUtils.getEGLErrorString(error));
157                }
158
159                if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
160                    throw new RuntimeException("eglMakeCurrent failed "
161                            + GLUtils.getEGLErrorString(mEgl.eglGetError()));
162                }
163            }
164
165
166            EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
167                int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
168                return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
169            }
170
171            private EGLConfig chooseEglConfig() {
172                int[] configsCount = new int[1];
173                EGLConfig[] configs = new EGLConfig[1];
174                int[] configSpec = getConfig();
175                if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
176                    throw new IllegalArgumentException("eglChooseConfig failed " +
177                            GLUtils.getEGLErrorString(mEgl.eglGetError()));
178                } else if (configsCount[0] > 0) {
179                    return configs[0];
180                }
181                return null;
182            }
183
184            private int[] getConfig() {
185                return new int[] {
186                        EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
187                        EGL10.EGL_RED_SIZE, 8,
188                        EGL10.EGL_GREEN_SIZE, 8,
189                        EGL10.EGL_BLUE_SIZE, 8,
190                        EGL10.EGL_ALPHA_SIZE, 8,
191                        EGL10.EGL_DEPTH_SIZE, 0,
192                        EGL10.EGL_STENCIL_SIZE, 0,
193                        EGL10.EGL_NONE
194                };
195            }
196        };
197        mGLThread.start();
198    }
199
200    @Override
201    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
202        Log.d(LOG_TAG, "onSurfaceTextureSizeChanged");
203    }
204
205    @Override
206    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
207        Log.d(LOG_TAG, "onSurfaceTextureDestroyed");
208        stopGlThread();
209        return true;
210    }
211
212    @Override
213    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
214        Log.d(LOG_TAG, "onSurfaceTextureUpdated");
215        mPreview.setVisibility(View.GONE);
216    }
217}
218