aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java')
-rw-r--r--src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java661
1 files changed, 661 insertions, 0 deletions
diff --git a/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java
new file mode 100644
index 0000000..f57d53b
--- /dev/null
+++ b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.cyanogenmod.wallpapers.photophase;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.media.effect.EffectContext;
+import android.net.Uri;
+import android.opengl.GLES20;
+import android.opengl.GLException;
+import android.opengl.GLSurfaceView;
+import android.opengl.Matrix;
+import android.os.Handler;
+import android.util.Log;
+
+import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil;
+import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil.GLColor;
+import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil.GLESTextureInfo;
+import org.cyanogenmod.wallpapers.photophase.utils.Utils;
+import org.cyanogenmod.wallpapers.photophase.preferences.PreferencesProvider;
+import org.cyanogenmod.wallpapers.photophase.preferences.PreferencesProvider.Preferences;
+import org.cyanogenmod.wallpapers.photophase.preferences.TouchAction;
+import org.cyanogenmod.wallpapers.photophase.shapes.ColorShape;
+import org.cyanogenmod.wallpapers.photophase.shapes.OopsShape;
+import org.cyanogenmod.wallpapers.photophase.transitions.Transition;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * The EGL renderer of PhotoPhase Live Wallpaper.
+ */
+public class PhotoPhaseRenderer implements GLSurfaceView.Renderer {
+
+ private static final String TAG = "PhotoPhaseRenderer";
+
+ private static final boolean DEBUG = false;
+
+ private final long mInstance;
+ private static long sInstances;
+
+ /*package*/ final Context mContext;
+ /*package*/ EffectContext mEffectContext;
+ private final Handler mHandler;
+ /*package*/ final GLESSurfaceDispatcher mDispatcher;
+ /*package*/ TextureManager mTextureManager;
+
+ /*package*/ PhotoPhaseWallpaperWorld mWorld;
+ /*package*/ ColorShape mOverlay;
+ /*package*/ OopsShape mOopsShape;
+
+ /*package*/ long mLastRunningTransition;
+
+ private long mLastTouchTime;
+ private static final long TOUCH_BARRIER_TIME = 1000L;
+
+ /*package*/ int mWidth = -1;
+ /*package*/ int mHeight = -1;
+ private int mStatusBarHeight = 0;
+ /*package*/ int mMeasuredHeight = -1;
+
+ private final float[] mMVPMatrix = new float[16];
+ private final float[] mProjMatrix = new float[16];
+ private final float[] mVMatrix = new float[16];
+
+ private final Object mDrawing = new Object();
+
+ /*package*/ final Object mMediaSync = new Object();
+ private PendingIntent mMediaScanIntent;
+
+ private final BroadcastReceiver mSettingsChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Check what flags are been requested
+ boolean recreateWorld = intent.getBooleanExtra(PreferencesProvider.EXTRA_FLAG_RECREATE_WORLD, false);
+ boolean redraw = intent.getBooleanExtra(PreferencesProvider.EXTRA_FLAG_REDRAW, false);
+ boolean emptyTextureQueue = intent.getBooleanExtra(PreferencesProvider.EXTRA_FLAG_EMPTY_TEXTURE_QUEUE, false);
+ boolean mediaReload = intent.getBooleanExtra(PreferencesProvider.EXTRA_FLAG_MEDIA_RELOAD, false);
+ boolean mediaIntervalChanged = intent.getBooleanExtra(PreferencesProvider.EXTRA_FLAG_MEDIA_INTERVAL_CHANGED, false);
+ if (emptyTextureQueue) {
+ if (mTextureManager != null) {
+ mTextureManager.emptyTextureQueue(true);
+ }
+ }
+ if (mediaReload) {
+ synchronized (mMediaSync) {
+ if (mTextureManager != null) {
+ boolean userReloadRequest =
+ intent.getBooleanExtra(
+ PreferencesProvider.EXTRA_ACTION_MEDIA_USER_RELOAD_REQUEST, false);
+ mTextureManager.reloadMedia(userReloadRequest);
+ scheduleOrCancelMediaScan();
+ }
+ }
+ }
+ if (mediaIntervalChanged) {
+ scheduleOrCancelMediaScan();
+ }
+ if (recreateWorld && mWorld != null) {
+ // Recreate the wallpaper world
+ try {
+ mWorld.recreateWorld(mWidth, mMeasuredHeight);
+ } catch (GLException e) {
+ Log.e(TAG, "Cannot recreate the wallpaper world.", e);
+ }
+ }
+ if (redraw) {
+ mDispatcher.requestRender();
+ }
+ }
+ };
+
+ private final Runnable mTransitionThread = new Runnable() {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ // Run in GLES's thread
+ mDispatcher.dispatch(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Select a new transition
+ mWorld.selectRandomTransition();
+ mLastRunningTransition = System.currentTimeMillis();
+
+ // Now force continuously render while transition is applied
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+ } catch (Throwable ex) {
+ Log.e(TAG, "Something was wrong selecting the transition", ex);
+ }
+ }
+ });
+ }
+ };
+
+ /**
+ * Constructor of <code>PhotoPhaseRenderer<code>
+ *
+ * @param ctx The current context
+ * @param dispatcher The GLES dispatcher
+ */
+ public PhotoPhaseRenderer(Context ctx, GLESSurfaceDispatcher dispatcher) {
+ super();
+ mContext = ctx;
+ mHandler = new Handler();
+ mDispatcher = dispatcher;
+ mInstance = sInstances;
+ sInstances++;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (mInstance ^ (mInstance >>> 32));
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ PhotoPhaseRenderer other = (PhotoPhaseRenderer) obj;
+ if (mInstance != other.mInstance)
+ return false;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "PhotoPhaseRenderer [instance: " + mInstance + "]";
+ }
+
+ /**
+ * Method called when renderer is created
+ */
+ public void onCreate() {
+ if (DEBUG) Log.d(TAG, "onCreate [" + mInstance + "]");
+ // Register a receiver to listen for media reload request
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(PreferencesProvider.ACTION_SETTINGS_CHANGED);
+ mContext.registerReceiver(mSettingsChangedReceiver, filter);
+
+ // Check whether the media scan is active
+ int interval = Preferences.Media.getRefreshFrecuency();
+ if (interval != Preferences.Media.MEDIA_RELOAD_DISABLED) {
+ // Schedule a media scan
+ scheduleMediaScan(interval);
+ }
+ }
+
+ /**
+ * Method called when renderer is destroyed
+ */
+ public void onDestroy() {
+ if (DEBUG) Log.d(TAG, "onDestroy [" + mInstance + "]");
+ // Register a receiver to listen for media reload request
+ mContext.unregisterReceiver(mSettingsChangedReceiver);
+ recycle();
+ if (mEffectContext != null) {
+ mEffectContext.release();
+ }
+ mEffectContext = null;
+ mWidth = -1;
+ mHeight = -1;
+ mMeasuredHeight = -1;
+ }
+
+ /**
+ * Method called when system runs under low memory
+ */
+ public void onLowMemory() {
+ mTextureManager.emptyTextureQueue(false);
+ }
+
+ /**
+ * Method called when the renderer should be paused
+ */
+ public void onPause() {
+ if (DEBUG) Log.d(TAG, "onPause [" + mInstance + "]");
+ mHandler.removeCallbacks(mTransitionThread);
+ if (mTextureManager != null) {
+ mTextureManager.setPause(true);
+ }
+ }
+
+ /**
+ * Method called when the renderer should be resumed
+ */
+ public void onResume() {
+ if (DEBUG) Log.d(TAG, "onResume [" + mInstance + "]");
+ if (mTextureManager != null) {
+ mTextureManager.setPause(false);
+ }
+ }
+
+ /**
+ * Method called when the renderer should process a touch event over the screen
+ *
+ * @param x The x coordinate
+ * @param y The y coordinate
+ */
+ public void onTouch(float x , float y) {
+ if (mWorld != null) {
+ // Do user action
+ TouchAction touchAction = Preferences.General.getTouchAction();
+ if (touchAction.compareTo(TouchAction.NONE) == 0) {
+ //Ignore
+ } else {
+ // Avoid to handle multiple touchs
+ long touchTime = System.currentTimeMillis();
+ long diff = touchTime - mLastTouchTime;
+ mLastTouchTime = touchTime;
+ if (diff < TOUCH_BARRIER_TIME) {
+ return;
+ }
+
+ // Retrieve the photo frame for its coordinates
+ final PhotoFrame frame = mWorld.getFrameFromCoordinates(new PointF(x, y));
+ if (frame == null) {
+ Log.w(TAG, "No frame from coordenates");
+ return;
+ }
+
+ // Apply the action
+ if (touchAction.compareTo(TouchAction.TRANSITION) == 0) {
+ try {
+ // Select the frame with a transition
+ // Run in GLES's thread
+ mDispatcher.dispatch(new Runnable() {
+ @Override
+ public void run() {
+ // Select a new transition
+ deselectCurrentTransition();
+ mWorld.selectTransition(frame);
+ mLastRunningTransition = System.currentTimeMillis();
+
+ // Now force continuously render while transition is applied
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+ }
+ });
+
+ } catch (NotFoundException ex) {
+ Log.e(TAG, "The frame not exists " + frame.getTextureInfo().path, ex);
+ }
+
+ } else if (touchAction.compareTo(TouchAction.OPEN) == 0) {
+ // Open the image
+ try {
+ Uri uri = getUriFromFrame(frame);
+ if (uri != null) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.setDataAndType(uri, "image/*");
+ mContext.startActivity(intent);
+ }
+ } catch (ActivityNotFoundException ex) {
+ Log.e(TAG, "Open activity not found for " + frame.getTextureInfo().path, ex);
+ }
+
+ } else if (touchAction.compareTo(TouchAction.SHARE) == 0) {
+ // Send the image
+ try {
+ Uri uri = getUriFromFrame(frame);
+ if (uri != null) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.setType("image/*");
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ mContext.startActivity(intent);
+ }
+ } catch (ActivityNotFoundException ex) {
+ Log.e(TAG, "Send activity not found for " + frame.getTextureInfo().path, ex);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Method that returns an Uri reference from a photo frame
+ *
+ * @param frame The photo frame
+ * @return Uri The image uri
+ */
+ private static Uri getUriFromFrame(final PhotoFrame frame) {
+ // Sanity checks
+ GLESTextureInfo info = frame.getTextureInfo();
+ if (info == null) {
+ Log.e(TAG, "The frame has not a valid reference right now." +
+ "Touch action is not available.");
+ return null;
+ }
+ if (info.path == null || !info.path.isFile()) {
+ Log.e(TAG, "The image do not exists. Touch action is not available.");
+ return null;
+ }
+
+ // Return the uri from the path
+ return Uri.fromFile(frame.getTextureInfo().path);
+ }
+
+ /**
+ * Method that deselect the current transition
+ */
+ /*package*/ synchronized void deselectCurrentTransition() {
+ mHandler.removeCallbacks(mTransitionThread);
+ mWorld.deselectTransition(mMVPMatrix);
+ mLastRunningTransition = 0;
+ }
+
+ /*package*/ void scheduleOrCancelMediaScan() {
+ int interval = Preferences.Media.getRefreshFrecuency();
+ if (interval != Preferences.Media.MEDIA_RELOAD_DISABLED) {
+ scheduleMediaScan(interval);
+ } else {
+ cancelMediaScan();
+ }
+ }
+
+ /**
+ * Method that schedules a new media scan
+ *
+ * @param interval The new interval
+ */
+ private void scheduleMediaScan(int interval) {
+ AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+
+ Intent i = new Intent(PreferencesProvider.ACTION_SETTINGS_CHANGED);
+ i.putExtra(PreferencesProvider.EXTRA_FLAG_MEDIA_RELOAD, Boolean.TRUE);
+ mMediaScanIntent = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ long milliseconds = Preferences.Media.getRefreshFrecuency() * 1000L;
+ am.set(AlarmManager.RTC, System.currentTimeMillis() + milliseconds, mMediaScanIntent);
+ }
+
+ /**
+ * Method that cancels a pending media scan
+ */
+ private void cancelMediaScan() {
+ if (mMediaScanIntent != null) {
+ AlarmManager am = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ am.cancel(mMediaScanIntent);
+ mMediaScanIntent = null;
+ }
+ }
+
+ /**
+ * Method that destroy all the internal references
+ */
+ private void recycle() {
+ if (DEBUG) Log.d(TAG, "recycle [" + mInstance + "]");
+ synchronized (mDrawing) {
+ // Remove any pending handle
+ if (mHandler != null && mTransitionThread != null) {
+ mHandler.removeCallbacks(mTransitionThread);
+ }
+
+ // Delete the world
+ if (mWorld != null) mWorld.recycle();
+ if (mTextureManager != null) mTextureManager.recycle();
+ if (mOverlay != null) mOverlay.recycle();
+ if (mOopsShape != null) mOopsShape.recycle();
+ mWorld = null;
+ mTextureManager = null;
+ mOverlay = null;
+ mOopsShape = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+ if (DEBUG) Log.d(TAG, "onSurfaceCreated [" + mInstance + "]");
+
+ mWidth = -1;
+ mHeight = -1;
+ mMeasuredHeight = -1;
+ mStatusBarHeight = 0;
+
+ // We have a 2d (fake) scenario, disable all unnecessary tests. Deep are
+ // necessary for some 3d effects
+ GLES20.glDisable(GL10.GL_DITHER);
+ GLESUtil.glesCheckError("glDisable");
+ GLES20.glDisable(GL10.GL_CULL_FACE);
+ GLESUtil.glesCheckError("glDisable");
+ GLES20.glEnable(GL10.GL_DEPTH_TEST);
+ GLESUtil.glesCheckError("glEnable");
+ GLES20.glDepthMask(false);
+ GLESUtil.glesCheckError("glDepthMask");
+ GLES20.glDepthFunc(GLES20.GL_LEQUAL);
+ GLESUtil.glesCheckError("glDepthFunc");
+
+ // Create an effect context
+ if (mEffectContext != null) {
+ mEffectContext.release();
+ }
+ mEffectContext = EffectContext.createWithCurrentGlContext();
+
+ // Create the texture manager and recycle the old one
+ if (mTextureManager == null) {
+ // Precalculate the window size for the TextureManager. In onSurfaceChanged
+ // the best fixed size will be set. The disposition size is simple for a better
+ // performance of the internal arrays
+ final Configuration conf = mContext.getResources().getConfiguration();
+ int orientation = mContext.getResources().getConfiguration().orientation;
+ int w = (int) AndroidHelper.convertDpToPixel(mContext, conf.screenWidthDp);
+ int h = (int) AndroidHelper.convertDpToPixel(mContext, conf.screenHeightDp);
+ Rect dimensions = new Rect(0, 0, w, h);
+ int cc = (orientation == Configuration.ORIENTATION_PORTRAIT)
+ ? Preferences.Layout.getPortraitDisposition().size()
+ : Preferences.Layout.getLandscapeDisposition().size();
+
+ // Recycle the current texture manager and create a new one
+ recycle();
+ mTextureManager = new TextureManager(
+ mContext, mHandler, mEffectContext, mDispatcher, cc, dimensions);
+ } else {
+ mTextureManager.updateEffectContext(mEffectContext);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+ if (DEBUG) Log.d(TAG, "onSurfaceChanged [" + mInstance + "," + width + "x" + height + "]");
+
+ // Check if the size was changed
+ if (mWidth == width && mHeight == height) {
+ return;
+ }
+
+ // Save the width and height to avoid recreate the world
+ mWidth = width;
+ mHeight = height;
+ mStatusBarHeight = AndroidHelper.calculateStatusBarHeight(mContext);
+ mMeasuredHeight = mHeight + mStatusBarHeight;
+
+ // Calculate a better fixed size for the pictures
+ Rect dimensions = Utils.isTablet(mContext)
+ ? new Rect(0, 0, width / 2, height / 2)
+ : new Rect(0, 0, width / 4, height / 4);
+ Rect screenDimensions = new Rect(0, mStatusBarHeight, width, height);
+ mTextureManager.setDimensions(dimensions);
+ mTextureManager.setScreenDimesions(screenDimensions);
+ mTextureManager.setPause(false);
+
+ // Create the wallpaper (destroy the previous)
+ if (mWorld != null) {
+ mWorld.recycle();
+ }
+ mWorld = new PhotoPhaseWallpaperWorld(mContext, mTextureManager);
+
+ // Create the overlay shape
+ final float[] vertex = {
+ -1.0f, -1.0f,
+ 1.0f, -1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f
+ };
+ mOverlay = new ColorShape(mContext, vertex, Colors.getOverlay());
+
+ // Create the Oops shape
+ mOopsShape = new OopsShape(mContext, R.string.no_pictures_oops_msg);
+
+ // Set the viewport and the fustrum
+ GLES20.glViewport(0, -mStatusBarHeight, mWidth, mHeight);
+ GLESUtil.glesCheckError("glViewport");
+ Matrix.frustumM(mProjMatrix, 0, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 2.0f);
+
+ // Recreate the wallpaper world
+ try {
+ mWorld.recreateWorld(width, mMeasuredHeight);
+ } catch (GLException e) {
+ Log.e(TAG, "Cannot recreate the wallpaper world.", e);
+ }
+
+ // Force an immediate redraw of the screen (draw thread could be in dirty mode only)
+ deselectCurrentTransition();
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDrawFrame(GL10 glUnused) {
+ synchronized (mDrawing) {
+ // Set the projection, view and model
+ GLES20.glViewport(0, -mStatusBarHeight, mWidth, mHeight);
+ Matrix.setLookAtM(mVMatrix, 0, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
+ Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
+
+ if (mTextureManager != null) {
+ if (mTextureManager.getStatus() == 1 && mTextureManager.isEmpty()) {
+ // Advise the user and stop
+ drawOops();
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+
+ } else {
+ // Draw the background
+ drawBackground();
+
+ if (mWorld != null) {
+ // Now draw the world (all the photo frames with effects)
+ mWorld.draw(mMVPMatrix);
+
+ // Check if we have some pending transition or transition has
+ // exceed its timeout
+ if (Preferences.General.Transitions.getTransitionInterval() > 0) {
+ if (!mWorld.hasRunningTransition() || firedTransitionTimeout()) {
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+
+ // Now start a delayed thread to generate the next effect
+ deselectCurrentTransition();
+ mLastRunningTransition = 0;
+ mHandler.postDelayed(mTransitionThread,
+ Preferences.General.Transitions.getTransitionInterval());
+ }
+ } else {
+ // Just display the initial frames and never make transitions
+ if (!mWorld.hasRunningTransition() || firedTransitionTimeout()) {
+ mDispatcher.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ }
+ }
+
+ // Draw the overlay
+ drawOverlay();
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Check whether the transition has exceed the timeout
+ *
+ * @return boolean if the transition has exceed the timeout
+ */
+ private boolean firedTransitionTimeout() {
+ long now = System.currentTimeMillis();
+ long diff = now - mLastRunningTransition;
+ return mLastRunningTransition != 0 && diff > Transition.MAX_TRANSTION_TIME;
+ }
+
+ /**
+ * Method that draws the background of the wallpaper
+ */
+ private static void drawBackground() {
+ GLColor bg = Colors.getBackground();
+ GLES20.glClearColor(bg.r, bg.g, bg.b, bg.a);
+ GLESUtil.glesCheckError("glClearColor");
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
+ GLESUtil.glesCheckError("glClear");
+ }
+
+ /**
+ * Method that draws the overlay of the wallpaper
+ */
+ private void drawOverlay() {
+ if (mOverlay != null) {
+ mOverlay.setAlpha(Preferences.General.getWallpaperDim() / 100.0f);
+ mOverlay.draw(mMVPMatrix);
+ }
+ }
+
+ /**
+ * Method that draws the oops message
+ */
+ private void drawOops() {
+ if (mOopsShape != null) {
+ mOopsShape.draw(mMVPMatrix);
+ }
+ }
+
+}