14c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn/* 24c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Copyright (C) 2009 The Android Open Source Project 34c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * 44c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 54c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * you may not use this file except in compliance with the License. 64c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * You may obtain a copy of the License at 74c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * 84c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 94c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * 104c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 114c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 124c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * See the License for the specific language governing permissions and 144c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * limitations under the License. 154c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn */ 164c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 17ba39839444532af0ed3766f736582413f6d7a40bDianne Hackbornpackage com.android.systemui; 184c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 19407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.app.ActivityManager; 204c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.app.WallpaperManager; 21407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.content.BroadcastReceiver; 22407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.content.Context; 23407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.content.Intent; 24407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.graphics.Bitmap; 254c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.graphics.Canvas; 26759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackbornimport android.graphics.Rect; 27e2d034c9014919a45ddd717d4e564e73771b2fefMathias Agopianimport android.graphics.Region.Op; 28407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.opengl.GLUtils; 29043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guyimport android.os.SystemProperties; 30407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.renderscript.Matrix4f; 314c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.service.wallpaper.WallpaperService; 32c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackbornimport android.util.Log; 33407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.view.Display; 348df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackbornimport android.view.MotionEvent; 354c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornimport android.view.SurfaceHolder; 36407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport android.view.WindowManager; 37407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 38407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.egl.EGL10; 39407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.egl.EGLConfig; 40407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.egl.EGLContext; 41407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.egl.EGLDisplay; 42407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.egl.EGLSurface; 43407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport javax.microedition.khronos.opengles.GL; 44407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport java.io.IOException; 45407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport java.nio.ByteBuffer; 46407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport java.nio.ByteOrder; 47407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport java.nio.FloatBuffer; 48407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 49407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport static android.opengl.GLES20.*; 50407ec78b828173257b0c5dae221649a4ccd8b058Romain Guyimport static javax.microedition.khronos.egl.EGL10.*; 514c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 524c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn/** 534c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn * Default built-in wallpaper that simply shows a static image. 544c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn */ 55407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy@SuppressWarnings({"UnusedDeclaration"}) 564c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackbornpublic class ImageWallpaper extends WallpaperService { 57fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown private static final String TAG = "ImageWallpaper"; 58407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final String GL_LOG_TAG = "ImageWallpaperGL"; 59fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown private static final boolean DEBUG = false; 60043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu"; 61fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 62ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn static final boolean FIXED_SIZED_SURFACE = true; 63881fb2092b41f4447e708da2f341d2ca5602c0d4Erik Gilling static final boolean USE_OPENGL = true; 64ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn 65ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy WallpaperManager mWallpaperManager; 66407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 67407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy boolean mIsHwAccelerated; 68ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy 69ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy @Override 70ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy public void onCreate() { 71ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy super.onCreate(); 72ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE); 73407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 74407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy //noinspection PointlessBooleanExpression,ConstantConditions 75407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (FIXED_SIZED_SURFACE && USE_OPENGL) { 76043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy if (!isEmulator()) { 77043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy WindowManager windowManager = 78043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy (WindowManager) getSystemService(Context.WINDOW_SERVICE); 79043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy Display display = windowManager.getDefaultDisplay(); 80043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy mIsHwAccelerated = ActivityManager.isHighEndGfx(display); 81043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy } 82407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 83ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy } 84ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy 85043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy private static boolean isEmulator() { 86043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy return "1".equals(SystemProperties.get(PROPERTY_KERNEL_QEMU, "0")); 87043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy } 88043a6b1e5709c46cb8094766c792ec57d3fd97dfRomain Guy 89ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy public Engine onCreateEngine() { 90284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn return new DrawableEngine(); 91ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy } 92ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy 93ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy class DrawableEngine extends Engine { 94407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 95407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy static final int EGL_OPENGL_ES2_BIT = 4; 96407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 97407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private final Object mLock = new Object[0]; 98407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 99407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy // TODO: Not currently used, keeping around until we know we don't need it 100407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy @SuppressWarnings({"UnusedDeclaration"}) 101284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn private WallpaperObserver mReceiver; 102407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 103407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Bitmap mBackground; 104ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn int mBackgroundWidth = -1, mBackgroundHeight = -1; 1057341d7a104b47996445d069a695e155a07184606Dianne Hackborn float mXOffset; 1067341d7a104b47996445d069a695e155a07184606Dianne Hackborn float mYOffset; 107759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn 108fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown boolean mVisible = true; 109fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown boolean mRedrawNeeded; 110fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown boolean mOffsetsChanged; 111fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown int mLastXTranslation; 112fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown int mLastYTranslation; 113fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 114407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGL10 mEgl; 115407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGLDisplay mEglDisplay; 116407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGLConfig mEglConfig; 117407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGLContext mEglContext; 118407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGLSurface mEglSurface; 119407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private GL mGL; 120407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 121407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final String sSimpleVS = 122407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "attribute vec4 position;\n" + 123407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "attribute vec2 texCoords;\n" + 124407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "varying vec2 outTexCoords;\n" + 125407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "uniform mat4 projection;\n" + 126407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "\nvoid main(void) {\n" + 127407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy " outTexCoords = texCoords;\n" + 128407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy " gl_Position = projection * position;\n" + 129407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "}\n\n"; 130407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final String sSimpleFS = 131407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "precision mediump float;\n\n" + 132407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "varying vec2 outTexCoords;\n" + 133407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "uniform sampler2D texture;\n" + 134407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "\nvoid main(void) {\n" + 135407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy " gl_FragColor = texture2D(texture, outTexCoords);\n" + 136407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy "}\n\n"; 137407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 138407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final int FLOAT_SIZE_BYTES = 4; 139407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 140407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 141407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 142407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 143284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn class WallpaperObserver extends BroadcastReceiver { 144284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn public void onReceive(Context context, Intent intent) { 14530bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 14630bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "onReceive"); 14730bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 14830bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown 149fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown synchronized (mLock) { 150ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn mBackgroundWidth = mBackgroundHeight = -1; 151ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn mBackground = null; 152ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn mRedrawNeeded = true; 15330bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown drawFrameLocked(); 154fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 155284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn } 156284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn } 157284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn 15835be7560300a97fc3675bdd325910f28827d9508Jeff Sharkey public DrawableEngine() { 15935be7560300a97fc3675bdd325910f28827d9508Jeff Sharkey super(); 16035be7560300a97fc3675bdd325910f28827d9508Jeff Sharkey setFixedSizeAllowed(true); 16135be7560300a97fc3675bdd325910f28827d9508Jeff Sharkey } 16235be7560300a97fc3675bdd325910f28827d9508Jeff Sharkey 1634c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn @Override 164759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn public void onCreate(SurfaceHolder surfaceHolder) { 16530bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 16630bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "onCreate"); 16730bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 16830bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown 169759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn super.onCreate(surfaceHolder); 1709ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn 171407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy // TODO: Don't need this currently because the wallpaper service 1729ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn // will restart the image wallpaper whenever the image changes. 1739ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 1749ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn //mReceiver = new WallpaperObserver(); 1759ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn //registerReceiver(mReceiver, filter, null, mHandler); 176fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 177ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn updateSurfaceSize(surfaceHolder); 178a8e5a2bcd6a0d35893187c6df42425c03be005daChet Haase 179a8e5a2bcd6a0d35893187c6df42425c03be005daChet Haase setOffsetNotificationsEnabled(false); 1804c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn } 1814c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 1824c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn @Override 183284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn public void onDestroy() { 184284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn super.onDestroy(); 1859ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn if (mReceiver != null) { 1869ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn unregisterReceiver(mReceiver); 1879ea31639738e8d2c90dc3a4fcd535d09a0b7209aDianne Hackborn } 188284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn } 189284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn 190284ac93aa30642fda87d5c40263a1263677c21cdDianne Hackborn @Override 191ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 192912d9d13698693709991b76f83a8d64179e97e83Dianne Hackborn super.onDesiredSizeChanged(desiredWidth, desiredHeight); 193ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn SurfaceHolder surfaceHolder = getSurfaceHolder(); 194ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn if (surfaceHolder != null) { 195ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn updateSurfaceSize(surfaceHolder); 196ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn } 197ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn } 198ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn 199ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn void updateSurfaceSize(SurfaceHolder surfaceHolder) { 200ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn if (FIXED_SIZED_SURFACE) { 201ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // Used a fixed size surface, because we are special. We can do 202ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // this because we know the current design of window animations doesn't 203ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // cause this to break. 204ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn surfaceHolder.setFixedSize(getDesiredMinimumWidth(), getDesiredMinimumHeight()); 205ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn } else { 206ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn surfaceHolder.setSizeFromLayout(); 207ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn } 208ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn } 209ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn 210ac1471a4fff660710f88afc679c4119fdf8dc417Dianne Hackborn @Override 211759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn public void onVisibilityChanged(boolean visible) { 21230bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 21330bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "onVisibilityChanged: visible=" + visible); 21430bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 21530bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown 216fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown synchronized (mLock) { 21730bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (mVisible != visible) { 21830bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 21930bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "Visibility changed to visible=" + visible); 22030bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 22130bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown mVisible = visible; 22230bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown drawFrameLocked(); 22330bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 224fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 225759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn } 226fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 227759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn @Override 2288df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn public void onTouchEvent(MotionEvent event) { 2298df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn super.onTouchEvent(event); 2308df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn } 2318df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn 2328df8b2b405c60cacf7a66c4e2ca078dd3d7ec7bdDianne Hackborn @Override 23372c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn public void onOffsetsChanged(float xOffset, float yOffset, 234bf6956b1d95442e9d9c483894d578fe6b7044cbbMarco Nelissen float xOffsetStep, float yOffsetStep, 23572c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn int xPixels, int yPixels) { 23630bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 23730bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset 23830bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep 23930bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown + ", xPixels=" + xPixels + ", yPixels=" + yPixels); 24030bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 24130bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown 242fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown synchronized (mLock) { 243fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (mXOffset != xOffset || mYOffset != yOffset) { 244fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (DEBUG) { 245fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ")."); 246fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 247fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown mXOffset = xOffset; 248fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown mYOffset = yOffset; 24930bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown mOffsetsChanged = true; 250fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 25130bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown drawFrameLocked(); 252fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 25372c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn } 25472c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn 25572c82ab9923025a91bbabb32e56bfea27bfd083bDianne Hackborn @Override 2564c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 25730bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown if (DEBUG) { 25830bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height); 259fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 2604c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 26130bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown super.onSurfaceChanged(holder, format, width, height); 2624c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn 26330bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown synchronized (mLock) { 26430bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown mRedrawNeeded = true; 26530bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown drawFrameLocked(); 26630bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown } 2674c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn } 268fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 26930bc34f191ca8a009af313fc751e5b4bff6e39a1Jeff Brown void drawFrameLocked() { 270fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (!mVisible) { 271fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (DEBUG) { 272fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible."); 273fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 274fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown return; 275fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 276fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (!mRedrawNeeded && !mOffsetsChanged) { 277fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (DEBUG) { 278fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Log.d(TAG, "Suppressed drawFrame since redraw is not needed " 279fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown + "and offsets have not changed."); 280fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 281fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown return; 282fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 283fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown 284321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka // If we don't yet know the size of the wallpaper bitmap, 285321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka // we need to get it now. 286321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka boolean updateWallpaper = mBackgroundWidth < 0 || mBackgroundHeight < 0 ; 287321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka 288321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka // If we somehow got to this point after we have last flushed 289321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka // the wallpaper, well we really need it to draw again. So 290321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka // seems like we need to reload it. Ouch. 291321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka updateWallpaper = updateWallpaper || mBackground == null; 292321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka 293321357b6066a34cc12a0528b7b835c7664db2e08Michael Jurka if (updateWallpaper) { 294ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn updateWallpaperLocked(); 295ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn } 296ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn 297759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn SurfaceHolder sh = getSurfaceHolder(); 298033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown final Rect frame = sh.getSurfaceFrame(); 299033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown final int dw = frame.width(); 300033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown final int dh = frame.height(); 301ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn final int availw = dw - mBackgroundWidth; 302ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn final int availh = dh - mBackgroundHeight; 303033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2); 304033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2); 305033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown 306033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown mOffsetsChanged = false; 307407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (!mRedrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) { 308033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown if (DEBUG) { 309033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown Log.d(TAG, "Suppressed drawFrame since the image has not " 310033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown + "actually moved an integral number of pixels."); 311033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown } 312033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown return; 313033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown } 314033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown mRedrawNeeded = false; 315033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown mLastXTranslation = xPixels; 316033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown mLastYTranslation = yPixels; 317033f63a1a5e8f768a72a11561fe70957eb44fa3eJeff Brown 318ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn 319407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (mIsHwAccelerated) { 320f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) { 321f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 322f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy } 323407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } else { 324407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 325759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn } 326ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn 327ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn if (FIXED_SIZED_SURFACE) { 328ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // If the surface is fixed-size, we should only need to 329ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // draw it once and then we'll let the window manager 330ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // position it appropriately. As such, we no longer needed 331ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn // the loaded bitmap. Yay! 332ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn mBackground = null; 333ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn mWallpaperManager.forgetLoadedWallpaper(); 334ba39839444532af0ed3766f736582413f6d7a40bDianne Hackborn } 335759a39e8d2a8b27ef07e102394629dce68aa186bDianne Hackborn } 336ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy 337fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown void updateWallpaperLocked() { 338fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Throwable exception = null; 339fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown try { 340407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mBackground = mWallpaperManager.getBitmap(); 341fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } catch (RuntimeException e) { 342fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown exception = e; 343fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } catch (OutOfMemoryError e) { 344fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown exception = e; 345fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } 346407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 347fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown if (exception != null) { 348fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown mBackground = null; 349fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown // Note that if we do fail at this, and the default wallpaper can't 350fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown // be loaded, we will go into a cycle. Don't do a build where the 351fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown // default wallpaper can't be loaded. 352fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Log.w(TAG, "Unable to load wallpaper!", exception); 353c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn try { 354fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown mWallpaperManager.clear(); 355fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown } catch (IOException ex) { 356fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown // now we're really screwed. 357fa2e504087362989e5dd7fe6e65b6481cef59495Jeff Brown Log.w(TAG, "Unable reset to default wallpaper!", ex); 358c9dbbe28f7879bd377114587ed1f40235a2d37caDianne Hackborn } 359ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy } 360407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 361407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0; 362407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0; 363407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 364407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 365407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) { 366407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Canvas c = sh.lockCanvas(); 367407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (c != null) { 368407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy try { 369407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (DEBUG) { 370407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.d(TAG, "Redrawing: x=" + x + ", y=" + y); 371407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 372407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 373407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.translate(x, y); 374407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (w < 0 || h < 0) { 375407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.save(Canvas.CLIP_SAVE_FLAG); 376407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE); 377407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.drawColor(0xff000000); 378407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.restore(); 379407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 380407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (mBackground != null) { 381407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy c.drawBitmap(mBackground, 0, 0, null); 382407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 383407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } finally { 384407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy sh.unlockCanvasAndPost(c); 385407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 386407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 387407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 388407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 389f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) { 390f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy if (!initGL(sh)) return false; 391407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 392407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final float right = left + mBackgroundWidth; 393407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final float bottom = top + mBackgroundHeight; 394407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 395407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final Rect frame = sh.getSurfaceFrame(); 396407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 397407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final Matrix4f ortho = new Matrix4f(); 398407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f); 399407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 400407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final FloatBuffer triangleVertices = createMesh(left, top, right, bottom); 401407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 402407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int texture = loadTexture(mBackground); 403407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int program = buildProgram(sSimpleVS, sSimpleFS); 404407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 405407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int attribPosition = glGetAttribLocation(program, "position"); 406407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int attribTexCoords = glGetAttribLocation(program, "texCoords"); 407407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int uniformTexture = glGetUniformLocation(program, "texture"); 408407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int uniformProjection = glGetUniformLocation(program, "projection"); 409407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 410407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 411407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 412407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glViewport(0, 0, frame.width(), frame.height()); 413407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glBindTexture(GL_TEXTURE_2D, texture); 414407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 415407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glUseProgram(program); 416407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glEnableVertexAttribArray(attribPosition); 417407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glEnableVertexAttribArray(attribTexCoords); 418407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glUniform1i(uniformTexture, 0); 419407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0); 420407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 421407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 422407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 423407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (w < 0 || h < 0) { 424407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 425407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glClear(GL_COLOR_BUFFER_BIT); 426407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 427407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 428407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy // drawQuad 429407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 430407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 431407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 432407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 433407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 434407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 435407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 436407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 437407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 438407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 439407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 440407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("Cannot swap buffers"); 441407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 442407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkEglError(); 443407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 444407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy finishGL(); 445f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy 446f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy return true; 447407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 448407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 449407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private FloatBuffer createMesh(int left, int top, float right, float bottom) { 450407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final float[] verticesData = { 451407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy // X, Y, Z, U, V 452407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy left, bottom, 0.0f, 0.0f, 1.0f, 453407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy right, bottom, 0.0f, 1.0f, 1.0f, 454407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy left, top, 0.0f, 0.0f, 0.0f, 455407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy right, top, 0.0f, 1.0f, 0.0f, 456407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy }; 457407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 458407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final int bytes = verticesData.length * FLOAT_SIZE_BYTES; 459407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order( 460407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy ByteOrder.nativeOrder()).asFloatBuffer(); 461407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy triangleVertices.put(verticesData).position(0); 462407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return triangleVertices; 463407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 464407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 465407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private int loadTexture(Bitmap bitmap) { 466407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] textures = new int[1]; 467407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 468407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glActiveTexture(GL_TEXTURE0); 469407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glGenTextures(1, textures, 0); 470407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 471407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 472407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int texture = textures[0]; 473407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glBindTexture(GL_TEXTURE_2D, texture); 474407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 475407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 476407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 477407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 478407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 479407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 480407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 481407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 482407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 483407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 484407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 485407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy bitmap.recycle(); 486407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 487407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return texture; 488407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 489407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 490407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private int buildProgram(String vertex, String fragment) { 491407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 492407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (vertexShader == 0) return 0; 493407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 494407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 495407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (fragmentShader == 0) return 0; 496407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 497407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int program = glCreateProgram(); 498407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glAttachShader(program, vertexShader); 499407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 500407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 501407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glAttachShader(program, fragmentShader); 502407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 503407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 504407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glLinkProgram(program); 505407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 506407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 507407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] status = new int[1]; 508407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glGetProgramiv(program, GL_LINK_STATUS, status, 0); 509407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (status[0] != GL_TRUE) { 510407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy String error = glGetProgramInfoLog(program); 511407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.d(GL_LOG_TAG, "Error while linking program:\n" + error); 512407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glDeleteShader(vertexShader); 513407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glDeleteShader(fragmentShader); 514407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glDeleteProgram(program); 515407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return 0; 516407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 517407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 518407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return program; 519407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 520407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 521407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private int buildShader(String source, int type) { 522407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int shader = glCreateShader(type); 523407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 524407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glShaderSource(shader, source); 525407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 526407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 527407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glCompileShader(shader); 528407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy checkGlError(); 529407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 530407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] status = new int[1]; 531407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 532407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (status[0] != GL_TRUE) { 533407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy String error = glGetShaderInfoLog(shader); 534407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error); 535407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy glDeleteShader(shader); 536407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return 0; 537407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 538407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 539407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return shader; 540407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 541407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 542407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private void checkEglError() { 543407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int error = mEgl.eglGetError(); 544407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (error != EGL_SUCCESS) { 545407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error)); 546407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 547407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 548407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 549407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private void checkGlError() { 550407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int error = glGetError(); 551407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (error != GL_NO_ERROR) { 552407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable()); 553407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 554407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 555407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 556407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private void finishGL() { 557f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 558407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 559f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy mEgl.eglDestroyContext(mEglDisplay, mEglContext); 560407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 561407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 562f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy private boolean initGL(SurfaceHolder surfaceHolder) { 563407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEgl = (EGL10) EGLContext.getEGL(); 564407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 565407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 566407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (mEglDisplay == EGL_NO_DISPLAY) { 567407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("eglGetDisplay failed " + 568407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.getEGLErrorString(mEgl.eglGetError())); 569407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 570407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 571407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] version = new int[2]; 572407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (!mEgl.eglInitialize(mEglDisplay, version)) { 573407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("eglInitialize failed " + 574407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.getEGLErrorString(mEgl.eglGetError())); 575407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 576407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 577407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEglConfig = chooseEglConfig(); 578407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (mEglConfig == null) { 579407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("eglConfig not initialized"); 580407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 581407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 582407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 583407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 584407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null); 585407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 586407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 587407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int error = mEgl.eglGetError(); 588407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (error == EGL_BAD_NATIVE_WINDOW) { 589407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 590f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy return false; 591407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 592407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("createWindowSurface failed " + 593407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.getEGLErrorString(error)); 594407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 595407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 596407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 597407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new RuntimeException("eglMakeCurrent failed " + 598407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.getEGLErrorString(mEgl.eglGetError())); 599407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 600407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 601407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy mGL = mEglContext.getGL(); 602f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy 603f929629e74fe84b986f76db448b9c95d72b2903eRomain Guy return true; 604407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 605407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 606407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 607407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 608407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 609407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); 610407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 611407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 612407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private EGLConfig chooseEglConfig() { 613407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] configsCount = new int[1]; 614407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGLConfig[] configs = new EGLConfig[1]; 615407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy int[] configSpec = getConfig(); 616407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 617407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy throw new IllegalArgumentException("eglChooseConfig failed " + 618407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy GLUtils.getEGLErrorString(mEgl.eglGetError())); 619407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } else if (configsCount[0] > 0) { 620407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return configs[0]; 621407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 622407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return null; 623407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy } 624407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy 625407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy private int[] getConfig() { 626407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy return new int[] { 627407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 628407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_RED_SIZE, 8, 629407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_GREEN_SIZE, 8, 630407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_BLUE_SIZE, 8, 631407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_ALPHA_SIZE, 0, 632407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_DEPTH_SIZE, 0, 633407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_STENCIL_SIZE, 0, 634407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy EGL_NONE 635407ec78b828173257b0c5dae221649a4ccd8b058Romain Guy }; 636ef654bdd5bd957574abd4194d7b0585f3fc3fd34Romain Guy } 6374c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn } 6384c62fc0e1e5ea9c69a12a7d1cf8b3ec8b2d114a3Dianne Hackborn} 639