merged with muzei

This commit is contained in:
Emil Kabirov 2018-11-18 15:36:37 +05:00
parent 1d4b103f06
commit 2c51ab0cc6
31 changed files with 1296 additions and 1425 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
Debug
Release
log.txt
build

View File

@ -1 +0,0 @@
/build

View File

@ -20,7 +20,6 @@ include_directories(${LIBJPEG_PATH}/vc10)
include_directories(${LUA_PATH})
include_directories(${EIGEN_PATH})
include_directories(${SOL2_PATH})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../)
include_directories(${BOOST_PATH})
include_directories(${LIBPNG_PATH})
include_directories(${LIBJPEG_PATH})

View File

@ -1,43 +1,75 @@
/*
* Copyright 2014 Google Inc.
*
* 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.
*/
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
buildToolsVersion "28.0.0"
defaultConfig {
applicationId "fishrungames.mountainwallpaper"
minSdkVersion 19
targetSdkVersion 28
versionCode 2
versionName "1.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions -fsigned-char -Wno-c++11-narrowing"
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt')
}
}
sourceSets {
main {
assets.srcDirs = ['../../assets/']
}
}
splits {
abi {
enable true
reset()
include 'arm64-v8a', 'armeabi-v7a', 'x86'
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:28+'
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
implementation "com.android.support:preference-v7:$supportLibraryVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile project(':SalmonEngineAndroid')
implementation project(':SalmonEngineAndroid')
}

View File

@ -1,26 +0,0 @@
package fishrungames.salmonandroidtemplate;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("fishrungames.salmonandroidtemplate", appContext.getPackageName());
}
}

View File

@ -1,41 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014 Google Inc.
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.
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="fishrungames.mountainwallpaper"
android:versionCode="1"
android:versionName="1.0.0">
xmlns:tools="http://schemas.android.com/tools"
package="fishrungames.mountainwallpaper">
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<!-- <uses-permission android:name="android.permission.WAKE_LOCK"/> -->
<!-- Don't request this starting with Marshmallow (we only write to the app's cache folder) -->
<!-- <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="22"/>-->
<application
android:supportsRtl="true"
android:label="@string/app_name"
android:icon="@drawable/icon" >
android:icon="@drawable/icon"
android:allowBackup="false">
<!--tools:ignore="GoogleAppIndexingWarning"-->
<!-- Needed to support long aspect ratio devices as Muzei has resizeableActivity="false" -->
<!-- <meta-data
android:name="android.max_aspect"
android:value="2.1"/>-->
<!--android:theme="@style/Theme.MuzeiActivity"-->
<!--android:resizeableActivity="false"-->
<activity
android:name=".Prefs">
android:name=".WallpaperPreferences"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!--<intent-filter>-->
<!--<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>-->
<!--</intent-filter>-->
</activity>
<!--android:directBootAware="true"-->
<!--tools:targetApi="n"-->
<service
android:name=".MountainWallpaperService"
android:name=".MountainWallpaper"
android:permission="android.permission.BIND_WALLPAPER"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter android:priority="1">
<action android:name="android.service.wallpaper.WallpaperService" />
android:label="@string/app_name">
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper"/>
</service>
</application>
<!--<activity-alias-->
<!--android:name="com.google.android.apps.muzei.settings.NotificationSettings"-->
<!--android:targetActivity="com.google.android.apps.muzei.WallpaperPreferences"-->
<!--android:enabled="@bool/enable_notification_settings">-->
<!--<intent-filter>-->
<!--<action android:name="android.intent.action.MAIN"/>-->
<!--<category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>-->
<!--</intent-filter>-->
<!--</activity-alias>-->
</application>
</manifest>

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2008 The Android Open Source 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 fishrungames.mountainwallpaper
import android.opengl.GLSurfaceView
import javax.microedition.khronos.egl.EGL10
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLDisplay
/**
* Created by romannurik on 11/6/13.
*/
internal abstract class BaseConfigChooser(configSpec: IntArray, private val eglContextClientVersion: Int) : GLSurfaceView.EGLConfigChooser {
protected var mConfigSpec: IntArray
init {
mConfigSpec = filterConfigSpec(configSpec)
}
override fun chooseConfig(egl: EGL10, display: EGLDisplay): EGLConfig {
val num_config = IntArray(1)
if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
num_config)) {
throw IllegalArgumentException("eglChooseConfig failed")
}
val numConfigs = num_config[0]
if (numConfigs <= 0) {
throw IllegalArgumentException(
"No configs match configSpec")
}
val configs = kotlin.arrayOfNulls<EGLConfig?>(numConfigs)
if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
num_config)) {
throw IllegalArgumentException("eglChooseConfig#2 failed")
}
return chooseConfig(egl, display, configs)
?: throw IllegalArgumentException("No config chosen")
}
internal abstract fun chooseConfig(egl: EGL10, display: EGLDisplay,
configs: Array<EGLConfig?>): EGLConfig?
private fun filterConfigSpec(configSpec: IntArray): IntArray {
if (eglContextClientVersion != 2) {
return configSpec
}
/* We know none of the subclasses define EGL_RENDERABLE_TYPE.
* And we know the configSpec is well formed.
*/
val len = configSpec.size
val newConfigSpec = IntArray(len + 2)
System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1)
newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE
newConfigSpec[len] = 4 /* EGL_OPENGL_ES2_BIT */
newConfigSpec[len + 1] = EGL10.EGL_NONE
return newConfigSpec
}
open class ComponentSizeChooser(// Subclasses can adjust these values:
protected var mRedSize: Int, protected var mGreenSize: Int, protected var mBlueSize: Int, protected var mAlphaSize: Int, protected var mDepthSize: Int,
protected var mStencilSize: Int, eglContextClientVersion: Int) : BaseConfigChooser(intArrayOf(EGL10.EGL_RED_SIZE, mRedSize, EGL10.EGL_GREEN_SIZE, mGreenSize, EGL10.EGL_BLUE_SIZE, mBlueSize, EGL10.EGL_ALPHA_SIZE, mAlphaSize, EGL10.EGL_DEPTH_SIZE, mDepthSize, EGL10.EGL_STENCIL_SIZE, mStencilSize, EGL10.EGL_NONE), eglContextClientVersion) {
private val mValue: IntArray
init {
mValue = IntArray(1)
}
public override fun chooseConfig(egl: EGL10, display: EGLDisplay, configs: Array<EGLConfig?>): EGLConfig? {
var closestConfig: EGLConfig? = null
var closestDistance = 1000
for (config in configs) {
val d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE)
val s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE)
if (d >= mDepthSize && s >= mStencilSize) {
val r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE)
val g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE)
val b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE)
val a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE)
val distance = (Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize)
+ Math.abs(a - mAlphaSize))
if (distance < closestDistance) {
closestDistance = distance
closestConfig = config
}
}
}
return closestConfig
}
private fun findConfigAttrib(egl: EGL10, display: EGLDisplay, config: EGLConfig?, attribute: Int): Int {
return if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
mValue[0]
} else 0
}
}
/**
* This class will choose a supported surface as close to RGB565 as possible, with or without a depth buffer.
*/
class SimpleEGLConfigChooser(withDepthBuffer: Boolean, eglContextClientVersion: Int) : ComponentSizeChooser(4, 4, 4, 0, if (withDepthBuffer) 16 else 0, 0, eglContextClientVersion) {
init {
// Adjust target values. This way we'll accept a 4444 or
// 555 buffer if there's no 565 buffer available.
mRedSize = 5
mGreenSize = 6
mBlueSize = 5
}
}
}

View File

@ -1,960 +0,0 @@
package fishrungames.mountainwallpaper;
import fishrungames.mountainwallpaper.BaseConfigChooser.ComponentSizeChooser;
import fishrungames.mountainwallpaper.BaseConfigChooser.SimpleEGLConfigChooser;
import java.util.ArrayList;
import java.util.Calendar;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;
import fishrungames.salmonengineandroid.EngineWrapper;
public class GLWallpaperService extends WallpaperService {
private static final String TAG = "GLWallpaperService";
@Override
public Engine onCreateEngine() {
return new GLEngine();
}
public class GLEngine extends Engine {
public final static int RENDERMODE_WHEN_DIRTY = 0;
public final static int RENDERMODE_CONTINUOUSLY = 1;
private GLThread mGLThread;
private EGLConfigChooser mEGLConfigChooser;
private EGLContextFactory mEGLContextFactory;
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
private int mDebugFlags;
public GLEngine() {
super();
}
@Override
public void onVisibilityChanged(boolean visible) {
if (visible) {
onResume();
} else {
onPause();
}
super.onVisibilityChanged(visible);
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// Log.d(TAG, "GLEngine.onCreate()");
}
@Override
public void onDestroy() {
super.onDestroy();
// Log.d(TAG, "GLEngine.onDestroy()");
mGLThread.requestExitAndWait();
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// Log.d(TAG, "onSurfaceChanged()");
mGLThread.onWindowResize(width, height);
super.onSurfaceChanged(holder, format, width, height);
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "onSurfaceCreated()");
mGLThread.surfaceCreated(holder);
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "onSurfaceDestroyed()");
mGLThread.surfaceDestroyed();
super.onSurfaceDestroyed(holder);
}
public void setDebugFlags(int debugFlags) {
mDebugFlags = debugFlags;
}
public int getDebugFlags() {
return mDebugFlags;
}
public void setRenderer() {
checkRenderThreadState();
if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
if (mEGLContextFactory == null) {
//mEGLContextFactory = new DefaultContextFactory();
mEGLContextFactory = new ES20ContextFactory();
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mGLThread = new GLThread(mEGLConfigChooser,
mEGLContextFactory, mEGLWindowSurfaceFactory);
mGLThread.start();
}
public void setEGLContextFactory(EGLContextFactory factory) {
checkRenderThreadState();
mEGLContextFactory = factory;
}
public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
checkRenderThreadState();
mEGLWindowSurfaceFactory = factory;
}
public void setEGLConfigChooser(EGLConfigChooser configChooser) {
checkRenderThreadState();
mEGLConfigChooser = configChooser;
}
public void setEGLConfigChooser(boolean needDepth) {
setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
}
public void setEGLConfigChooser(int redSize, int greenSize,
int blueSize, int alphaSize, int depthSize, int stencilSize) {
setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
blueSize, alphaSize, depthSize, stencilSize));
}
public void setRenderMode(int renderMode) {
mGLThread.setRenderMode(renderMode);
}
public int getRenderMode() {
return mGLThread.getRenderMode();
}
public void requestRender() {
mGLThread.requestRender();
}
public void onPause() {
mGLThread.onPause();
}
public void onResume() {
mGLThread.onResume();
}
public void queueEvent(Runnable r) {
mGLThread.queueEvent(r);
}
private void checkRenderThreadState() {
if (mGLThread != null) {
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
}
}
}
}
// ----------------------------------------------------------------------
/**
* An interface for customizing the eglCreateContext and eglDestroyContext
* calls.
*
*
* This interface must be implemented by clients wishing to call
* {@link GLWallpaperService.GLEngine#setEGLContextFactory(EGLContextFactory)}
*/
interface EGLContextFactory {
EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
}
class DefaultContextFactory implements EGLContextFactory {
public EGLContext createContext(EGL10 egl, EGLDisplay display,
EGLConfig config) {
return egl
.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
}
public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
egl.eglDestroyContext(display, context);
}
}
class ES20ContextFactory implements EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(EGL10 egl, EGLDisplay display,
EGLConfig config) {
int[] attrib_list =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
return egl
.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, attrib_list);
}
public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
egl.eglDestroyContext(display, context);
}
}
/**
* An interface for customizing the eglCreateWindowSurface and eglDestroySurface
* calls.
*
*
* This interface must be implemented by clients wishing to call
* {@link GLWallpaperService.GLEngine#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
*/
interface EGLWindowSurfaceFactory {
EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow);
void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
}
class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow) {
// this is a bit of a hack to work around Droid init problems - if you
// don't have this, it'll get hung up on orientation changes
EGLSurface eglSurface = null;
while (eglSurface == null) {
try {
eglSurface = egl.eglCreateWindowSurface(display, config,
nativeWindow, null);
} catch (Throwable t) {
} finally {
if (eglSurface == null) {
try {
Thread.sleep(10);
} catch (InterruptedException t) {
}
}
}
}
return eglSurface;
}
public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {
egl.eglDestroySurface(display, surface);
}
}
class EglHelper {
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLSurface mEglSurface;
private EGLContext mEglContext;
EGLConfig mEglConfig;
private EGLConfigChooser mEGLConfigChooser;
private EGLContextFactory mEGLContextFactory;
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
public EglHelper(EGLConfigChooser chooser,
EGLContextFactory contextFactory,
EGLWindowSurfaceFactory surfaceFactory) {
this.mEGLConfigChooser = chooser;
this.mEGLContextFactory = contextFactory;
this.mEGLWindowSurfaceFactory = surfaceFactory;
}
/**
* Initialize EGL for a given configuration spec.
*
* configSpec
*/
public void start() {
String instanceId = "";
Log.d("EglHelper" + instanceId, "start()");
if (mEgl == null) {
Log.d("EglHelper" + instanceId, "getting new EGL");
/*
* Get an EGL instance
*/
mEgl = (EGL10) EGLContext.getEGL();
} else {
Log.d("EglHelper" + instanceId, "reusing EGL");
}
if (mEglDisplay == null) {
Log.d("EglHelper" + instanceId, "getting new display");
/*
* Get to the default display.
*/
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
} else {
Log.d("EglHelper" + instanceId, "reusing display");
}
if (mEglConfig == null) {
Log.d("EglHelper" + instanceId, "getting new config");
/*
* We can now initialize EGL for that display
*/
int[] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version);
mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
} else {
Log.d("EglHelper" + instanceId, "reusing config");
}
if (mEglContext == null) {
Log.d("EglHelper" + instanceId, "creating new context");
/*
* Create an OpenGL ES context. This must be done only once, an
* OpenGL context is a somewhat heavy object.
*/
mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay,
mEglConfig);
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
throw new RuntimeException("createContext failed");
}
} else {
Log.d("EglHelper" + instanceId, "reusing context");
}
mEglSurface = null;
}
/*
* React to the creation of a new surface by creating and returning an
* OpenGL interface that renders to that surface.
*/
public void createSurface(SurfaceHolder holder) {
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay,
mEglSurface);
}
mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, holder);
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("createWindowSurface failed");
}
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext)) {
//throw new RuntimeException("eglMakeCurrent failed.");
}
}
/**
* Display the current render surface.
*
* @return false if the context has been lost.
*/
public boolean swap() {
try {
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} catch (Exception e) {
return false;
}
return true;
/*
* Always check for EGL_CONTEXT_LOST, which means the context and all
* associated data were lost (For instance because the device went to
* sleep). We need to sleep until we get a new surface.
*/
}
public void destroySurface() {
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay,
mEglSurface);
mEglSurface = null;
}
}
public void finish() {
if (mEglContext != null) {
mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
mEglContext = null;
}
if (mEglDisplay != null) {
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
}
}
}
class GLThread extends Thread {
private final static boolean LOG_THREADS = false;
public final static int DEBUG_CHECK_GL_ERROR = 1;
public final static int DEBUG_LOG_GL_CALLS = 2;
private final GLThreadManager sGLThreadManager = new GLThreadManager();
private GLThread mEglOwner;
private EGLConfigChooser mEGLConfigChooser;
private EGLContextFactory mEGLContextFactory;
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
public SurfaceHolder mHolder;
private boolean mSizeChanged = true;
// Once the thread is started, all accesses to the following member
// variables are protected by the sGLThreadManager monitor
public boolean mDone;
private boolean mPaused;
private boolean mHasSurface;
private boolean mWaitingForSurface;
private boolean mHaveEgl;
private int mWidth;
private int mHeight;
private int mRenderMode;
private boolean mRequestRender;
private boolean mEventsWaiting;
// End of member variables protected by the sGLThreadManager monitor.
//private GLWallpaperService.Renderer mRenderer;
private ArrayList mEventQueue = new ArrayList();
private EglHelper mEglHelper;
static long lastTimeStamp;
static boolean gameIsInited = false;
GLThread(EGLConfigChooser chooser,
EGLContextFactory contextFactory,
EGLWindowSurfaceFactory surfaceFactory) {
super();
mDone = false;
mWidth = 0;
mHeight = 0;
mRequestRender = true;
mRenderMode = GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY;
this.mEGLConfigChooser = chooser;
this.mEGLContextFactory = contextFactory;
this.mEGLWindowSurfaceFactory = surfaceFactory;
Calendar c = Calendar.getInstance();
lastTimeStamp = c.getTimeInMillis();
gameIsInited = true;
}
@Override
public void run() {
setName("GLThread " + getId());
if (LOG_THREADS) {
Log.i("GLThread", "starting tid=" + getId());
}
try {
guardedRun();
} catch (InterruptedException e) {
// fall thru and exit normally
} finally {
sGLThreadManager.threadExiting(this);
}
}
/*
* This private method should only be called inside a
* synchronized(sGLThreadManager) block.
*/
private void stopEglLocked() {
if (mHaveEgl) {
mHaveEgl = false;
mEglHelper.destroySurface();
sGLThreadManager.releaseEglSurface(this);
}
}
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper(mEGLConfigChooser, mEGLContextFactory,
mEGLWindowSurfaceFactory/*, mGLWrapper*/);
try {
boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true;
/*
* This is our main activity thread's loop, we go until asked to
* quit.
*/
while (!isDone()) {
/*
* Update the asynchronous state (window size)
*/
int w = 0;
int h = 0;
boolean changed = false;
boolean needStart = false;
boolean eventsWaiting = false;
synchronized (sGLThreadManager) {
while (true) {
// Manage acquiring and releasing the SurfaceView
// surface and the EGL surface.
if (mPaused) {
stopEglLocked();
}
if (!mHasSurface) {
if (!mWaitingForSurface) {
stopEglLocked();
mWaitingForSurface = true;
sGLThreadManager.notifyAll();
}
} else {
if (!mHaveEgl) {
if (sGLThreadManager.tryAcquireEglSurface(this)) {
mHaveEgl = true;
mEglHelper.start();
mRequestRender = true;
needStart = true;
}
}
}
// Check if we need to wait. If not, update any state
// that needs to be updated, copy any state that
// needs to be copied, and use "break" to exit the
// wait loop.
if (mDone) {
return;
}
if (mEventsWaiting) {
eventsWaiting = true;
mEventsWaiting = false;
break;
}
if ((!mPaused)
&& mHasSurface
&& mHaveEgl
&& (mWidth > 0)
&& (mHeight > 0)
&& (mRequestRender || (mRenderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
mRequestRender = false;
if (mHasSurface && mWaitingForSurface) {
changed = true;
mWaitingForSurface = false;
sGLThreadManager.notifyAll();
}
break;
}
// By design, this is the only place where we wait().
if (LOG_THREADS) {
Log.i("GLThread", "waiting tid=" + getId());
}
sGLThreadManager.wait();
}
} // end of synchronized(sGLThreadManager)
/*
* Handle queued events
*/
if (eventsWaiting) {
Runnable r;
while ((r = getEvent()) != null) {
r.run();
if (isDone()) {
return;
}
}
// Go back and see if we need to wait to render.
continue;
}
if (needStart) {
tellRendererSurfaceCreated = true;
changed = true;
}
if (changed) {
mEglHelper.createSurface(mHolder);
tellRendererSurfaceChanged = true;
}
if (tellRendererSurfaceCreated) {
tellRendererSurfaceCreated = false;
}
if (tellRendererSurfaceChanged) {
//Xperimental -- VLAD KHOREV
JniWrapper.Init(w, h);
tellRendererSurfaceChanged = false;
}
if ((w > 0) && (h > 0)) {
/* draw a frame here */
if (gameIsInited)
{
Calendar c = Calendar.getInstance();
long currentTimeStamp = c.getTimeInMillis();
EngineWrapper.Update(currentTimeStamp - lastTimeStamp);
lastTimeStamp = currentTimeStamp;
}
/*
* Once we're done with GL, we need to call swapBuffers() to
* instruct the system to display the rendered frame
*/
mEglHelper.swap();
}
}
} finally {
/*
* clean-up everything...
*/
synchronized (sGLThreadManager) {
stopEglLocked();
mEglHelper.finish();
}
}
}
private boolean isDone() {
synchronized (sGLThreadManager) {
return mDone;
}
}
public void setRenderMode(int renderMode) {
if (!((GLWallpaperService.GLEngine.RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {
throw new IllegalArgumentException("renderMode");
}
synchronized (sGLThreadManager) {
mRenderMode = renderMode;
if (renderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY) {
sGLThreadManager.notifyAll();
}
}
}
public int getRenderMode() {
synchronized (sGLThreadManager) {
return mRenderMode;
}
}
public void requestRender() {
synchronized (sGLThreadManager) {
mRequestRender = true;
sGLThreadManager.notifyAll();
}
}
public void surfaceCreated(SurfaceHolder holder) {
mHolder = holder;
synchronized (sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
sGLThreadManager.notifyAll();
}
}
public void surfaceDestroyed() {
synchronized (sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceDestroyed tid=" + getId());
}
mHasSurface = false;
sGLThreadManager.notifyAll();
while (!mWaitingForSurface && isAlive() && !mDone) {
try {
sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
public void onPause() {
synchronized (sGLThreadManager) {
mPaused = true;
sGLThreadManager.notifyAll();
}
}
public void onResume() {
synchronized (sGLThreadManager) {
mPaused = false;
mRequestRender = true;
sGLThreadManager.notifyAll();
}
}
public void onWindowResize(int w, int h) {
synchronized (sGLThreadManager) {
mWidth = w;
mHeight = h;
mSizeChanged = true;
sGLThreadManager.notifyAll();
}
}
public void requestExitAndWait() {
// don't call this from GLThread thread or it is a guaranteed
// deadlock!
synchronized (sGLThreadManager) {
mDone = true;
sGLThreadManager.notifyAll();
}
try {
join();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Queue an "event" to be run on the GL rendering thread.
*
* @param r
* the runnable to be run on the GL rendering thread.
*/
public void queueEvent(Runnable r) {
synchronized (this) {
mEventQueue.add(r);
synchronized (sGLThreadManager) {
mEventsWaiting = true;
sGLThreadManager.notifyAll();
}
}
}
private Runnable getEvent() {
synchronized (this) {
if (mEventQueue.size() > 0) {
return (Runnable) mEventQueue.remove(0);
}
}
return null;
}
private class GLThreadManager {
public synchronized void threadExiting(GLThread thread) {
if (LOG_THREADS) {
Log.i("GLThread", "exiting tid=" + thread.getId());
}
thread.mDone = true;
if (mEglOwner == thread) {
mEglOwner = null;
}
notifyAll();
}
/*
* Tries once to acquire the right to use an EGL surface. Does not
* block.
*
* @return true if the right to use an EGL surface was acquired.
*/
public synchronized boolean tryAcquireEglSurface(GLThread thread) {
if (mEglOwner == thread || mEglOwner == null) {
mEglOwner = thread;
notifyAll();
return true;
}
return false;
}
public synchronized void releaseEglSurface(GLThread thread) {
if (mEglOwner == thread) {
mEglOwner = null;
}
notifyAll();
}
}
}
interface EGLConfigChooser {
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
}
abstract class BaseConfigChooser implements EGLConfigChooser {
public BaseConfigChooser(int[] configSpec) {
mConfigSpec = configSpec;
}
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] num_config = new int[1];
egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
int numConfigs = num_config[0];
if (numConfigs <= 0) {
throw new IllegalArgumentException("No configs match configSpec");
}
EGLConfig[] configs = new EGLConfig[numConfigs];
egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
num_config);
EGLConfig config = chooseConfig(egl, display, configs);
if (config == null) {
throw new IllegalArgumentException("No config chosen");
}
return config;
}
abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
EGLConfig[] configs);
protected int[] mConfigSpec;
public static class ComponentSizeChooser extends BaseConfigChooser {
public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
int alphaSize, int depthSize, int stencilSize) {
super(new int[] { EGL10.EGL_RED_SIZE, redSize,
EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE,
blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize,
EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE,
stencilSize, EGL10.EGL_NONE });
mValue = new int[1];
mRedSize = redSize;
mGreenSize = greenSize;
mBlueSize = blueSize;
mAlphaSize = alphaSize;
mDepthSize = depthSize;
mStencilSize = stencilSize;
}
@Override
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
EGLConfig[] configs) {
EGLConfig closestConfig = null;
int closestDistance = 1000;
for (EGLConfig config : configs) {
int d = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
if (d >= mDepthSize && s >= mStencilSize) {
int r = findConfigAttrib(egl, display, config,
EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config,
EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config,
EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config,
EGL10.EGL_ALPHA_SIZE, 0);
int distance = Math.abs(r - mRedSize)
+ Math.abs(g - mGreenSize)
+ Math.abs(b - mBlueSize)
+ Math.abs(a - mAlphaSize);
if (distance < closestDistance) {
closestDistance = distance;
closestConfig = config;
}
}
}
return closestConfig;
}
private int findConfigAttrib(EGL10 egl, EGLDisplay display,
EGLConfig config, int attribute, int defaultValue) {
if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
return mValue[0];
}
return defaultValue;
}
private int[] mValue;
// Subclasses can adjust these values:
protected int mRedSize;
protected int mGreenSize;
protected int mBlueSize;
protected int mAlphaSize;
protected int mDepthSize;
protected int mStencilSize;
}
/**
* This class will choose a supported surface as close to RGB565 as
* possible, with or without a depth buffer.
*
*/
public static class SimpleEGLConfigChooser extends ComponentSizeChooser {
public SimpleEGLConfigChooser(boolean withDepthBuffer) {
super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
// Adjust target values. This way we'll accept a 4444 or
// 555 buffer if there's no 565 buffer available.
mRedSize = 5;
mGreenSize = 6;
mBlueSize = 5;
}
}
}

View File

@ -0,0 +1,764 @@
/*
* Copyright (C) 2008 The Android Open Source 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 fishrungames.mountainwallpaper
import java.io.Writer
import java.util.ArrayList
import javax.microedition.khronos.egl.EGL10
import javax.microedition.khronos.egl.EGL11
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLContext
import javax.microedition.khronos.egl.EGLDisplay
import javax.microedition.khronos.egl.EGLSurface
import javax.microedition.khronos.opengles.GL
import javax.microedition.khronos.opengles.GL10
import android.opengl.GLSurfaceView
import android.service.wallpaper.WallpaperService
import android.util.Log
import android.view.SurfaceHolder
// Original code provided by Robert Green
// http://www.rbgrn.net/content/354-glsurfaceview-adapted-3d-live-wallpapers
open class GLWallpaperService : WallpaperService() {
companion object {
private val TAG = "GLWallpaperService"
val RENDERMODE_WHEN_DIRTY = 0;
val RENDERMODE_CONTINUOUSLY = 1;
}
override fun onCreateEngine(): WallpaperService.Engine {
return GLEngine()
}
open inner class GLEngine : WallpaperService.Engine() {
private var mGLThread: GLThread? = null
private var mEGLConfigChooser: GLSurfaceView.EGLConfigChooser? = null
private var mEGLContextFactory: GLSurfaceView.EGLContextFactory? = null
private var mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory? = null
private var mEGLContextClientVersion: Int = 0
var renderMode: Int
get() = mGLThread!!.renderMode
set(renderMode) {
mGLThread!!.renderMode = renderMode
}
override fun onVisibilityChanged(visible: Boolean) {
if (visible) {
onResume()
} else {
onPause()
}
super.onVisibilityChanged(visible)
}
override fun onDestroy() {
super.onDestroy()
// Log.d(TAG, "GLEngine.onDestroy()");
mGLThread!!.requestExitAndWait()
}
override fun onSurfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
// Log.d(TAG, "onSurfaceChanged()");
mGLThread!!.onWindowResize(width, height)
super.onSurfaceChanged(holder, format, width, height)
}
override fun onSurfaceCreated(holder: SurfaceHolder) {
Log.d(TAG, "onSurfaceCreated()")
mGLThread!!.surfaceCreated(holder)
super.onSurfaceCreated(holder)
}
override fun onSurfaceDestroyed(holder: SurfaceHolder) {
Log.d(TAG, "onSurfaceDestroyed()")
mGLThread!!.surfaceDestroyed()
super.onSurfaceDestroyed(holder)
}
fun setRenderer(renderer: GLSurfaceView.Renderer) {
checkRenderThreadState()
var mEGLConfigChooser = this.mEGLConfigChooser;
var mEGLContextFactory = this.mEGLContextFactory;
var mEGLWindowSurfaceFactory = this.mEGLWindowSurfaceFactory;
if (mEGLConfigChooser == null) {
mEGLConfigChooser = BaseConfigChooser.SimpleEGLConfigChooser(true, mEGLContextClientVersion)
}
if (mEGLContextFactory == null) {
mEGLContextFactory = DefaultContextFactory(mEGLContextClientVersion)
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = DefaultWindowSurfaceFactory()
}
mGLThread = GLThread(renderer, mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory)
mGLThread!!.start()
}
fun setEGLContextFactory(factory: GLSurfaceView.EGLContextFactory) {
checkRenderThreadState()
mEGLContextFactory = factory
}
fun setEGLWindowSurfaceFactory(factory: GLSurfaceView.EGLWindowSurfaceFactory) {
checkRenderThreadState()
mEGLWindowSurfaceFactory = factory
}
fun setEGLConfigChooser(configChooser: GLSurfaceView.EGLConfigChooser) {
checkRenderThreadState()
mEGLConfigChooser = configChooser
}
fun setEGLConfigChooser(needDepth: Boolean) {
setEGLConfigChooser(BaseConfigChooser.SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion))
}
fun setEGLConfigChooser(redSize: Int, greenSize: Int, blueSize: Int, alphaSize: Int, depthSize: Int,
stencilSize: Int) {
setEGLConfigChooser(
BaseConfigChooser.ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize,
depthSize,
stencilSize, mEGLContextClientVersion))
}
fun setEGLContextClientVersion(version: Int) {
checkRenderThreadState()
mEGLContextClientVersion = version
}
open fun requestRender() {
mGLThread!!.requestRender()
}
fun onPause() {
mGLThread!!.onPause()
}
fun onResume() {
mGLThread!!.onResume()
}
fun queueEvent(r: Runnable) {
mGLThread!!.queueEvent(r)
}
private fun checkRenderThreadState() {
if (mGLThread != null) {
throw IllegalStateException("setRenderer has already been called for this instance.")
}
}
}
}
internal class LogWriter : Writer() {
private val mBuilder = StringBuilder()
override fun close() {
flushBuilder()
}
override fun flush() {
flushBuilder()
}
override fun write(buf: CharArray, offset: Int, count: Int) {
for (i in 0 until count) {
val c = buf[offset + i]
if (c == '\n') {
flushBuilder()
} else {
mBuilder.append(c)
}
}
}
private fun flushBuilder() {
if (mBuilder.length > 0) {
Log.v("GLSurfaceView", mBuilder.toString())
mBuilder.delete(0, mBuilder.length)
}
}
}
// ----------------------------------------------------------------------
internal class DefaultContextFactory(val eglContextClientVersion : Int) : GLSurfaceView.EGLContextFactory {
private val EGL_CONTEXT_CLIENT_VERSION = 0x3098
override fun createContext(egl: EGL10, display: EGLDisplay, config: EGLConfig): EGLContext {
val attrib_list = intArrayOf(EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion, EGL10.EGL_NONE)
return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
if (eglContextClientVersion != 0) attrib_list else null)
}
override fun destroyContext(egl: EGL10, display: EGLDisplay, context: EGLContext) {
egl.eglDestroyContext(display, context)
}
}
internal class DefaultWindowSurfaceFactory : GLSurfaceView.EGLWindowSurfaceFactory {
override fun createWindowSurface(egl: EGL10, display: EGLDisplay, config: EGLConfig, nativeWindow: Any): EGLSurface {
// this is a bit of a hack to work around Droid init problems - if you don't have this, it'll get hung up on orientation changes
var eglSurface: EGLSurface? = null
while (eglSurface == null) {
try {
eglSurface = egl.eglCreateWindowSurface(display,
config, nativeWindow, null)
} catch (t: Throwable) {
} finally {
if (eglSurface == null) {
try {
Thread.sleep(10)
} catch (t: InterruptedException) {
}
}
}
}
return eglSurface
}
override fun destroySurface(egl: EGL10, display: EGLDisplay, surface: EGLSurface) {
egl.eglDestroySurface(display, surface)
}
}
internal class EglHelper(private val mEGLConfigChooser: GLSurfaceView.EGLConfigChooser, private val mEGLContextFactory: GLSurfaceView.EGLContextFactory,
private val mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory) {
private var mEgl: EGL10? = null
private var mEglDisplay: EGLDisplay? = null
private var mEglSurface: EGLSurface? = null
private var mEglContext: EGLContext? = null
var mEglConfig: EGLConfig? = null
/**
* Initialize EGL for a given configuration spec.
*
* @param configSpec
*/
fun start() {
// Log.d("EglHelper" + instanceId, "start()");
if (mEgl == null) {
// Log.d("EglHelper" + instanceId, "getting new EGL");
/*
* Get an EGL instance
*/
mEgl = EGLContext.getEGL() as EGL10
} else {
// Log.d("EglHelper" + instanceId, "reusing EGL");
}
if (mEglDisplay == null) {
// Log.d("EglHelper" + instanceId, "getting new display");
/*
* Get to the default display.
*/
mEglDisplay = mEgl!!.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
} else {
// Log.d("EglHelper" + instanceId, "reusing display");
}
if (mEglConfig == null) {
// Log.d("EglHelper" + instanceId, "getting new config");
/*
* We can now initialize EGL for that display
*/
val version = IntArray(2)
mEgl!!.eglInitialize(mEglDisplay, version)
mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay)
} else {
// Log.d("EglHelper" + instanceId, "reusing config");
}
if (mEglContext == null) {
// Log.d("EglHelper" + instanceId, "creating new context");
/*
* Create an OpenGL ES context. This must be done only once, an OpenGL context is a somewhat heavy object.
*/
mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig)
if (mEglContext == null || mEglContext === EGL10.EGL_NO_CONTEXT) {
throw RuntimeException("createContext failed")
}
} else {
// Log.d("EglHelper" + instanceId, "reusing context");
}
mEglSurface = null
}
/*
* React to the creation of a new surface by creating and returning an OpenGL interface that renders to that
* surface.
*/
fun createSurface(holder: SurfaceHolder): GL {
/*
* The window size has changed, so we need to create a new surface.
*/
if (mEglSurface != null && mEglSurface !== EGL10.EGL_NO_SURFACE) {
/*
* Unbind and destroy the old EGL surface, if there is one.
*/
mEgl!!.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface)
}
/*
* Create an EGL surface we can render into.
*/
mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, holder)
if (mEglSurface == null || mEglSurface === EGL10.EGL_NO_SURFACE) {
throw RuntimeException("createWindowSurface failed")
}
/*
* Before we can issue GL commands, we need to make sure the context is current and bound to a surface.
*/
if (!mEgl!!.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw RuntimeException("eglMakeCurrent failed.")
}
var gl = mEglContext!!.gl
/*
* if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0) { int configFlags = 0; Writer log =
* null; if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; }
* if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { log = new LogWriter(); } gl = GLDebugHelper.wrap(gl,
* configFlags, log); }
*/
return gl
}
/**
* Display the current render surface.
*
* @return false if the context has been lost.
*/
fun swap(): Boolean {
mEgl!!.eglSwapBuffers(mEglDisplay, mEglSurface)
/*
* Always check for EGL_CONTEXT_LOST, which means the context and all associated data were lost (For instance
* because the device went to sleep). We need to sleep until we get a new surface.
*/
return mEgl!!.eglGetError() != EGL11.EGL_CONTEXT_LOST
}
fun destroySurface() {
if (mEglSurface != null && mEglSurface !== EGL10.EGL_NO_SURFACE) {
mEgl!!.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)
mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface)
mEglSurface = null
}
}
fun finish() {
if (mEglContext != null) {
mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext)
mEglContext = null
}
if (mEglDisplay != null) {
mEgl!!.eglTerminate(mEglDisplay)
mEglDisplay = null
}
}
}
internal class GLThread
(
// End of member variables protected by the sGLThreadManager monitor.
private val mRenderer: GLSurfaceView.Renderer, private val mEGLConfigChooser: GLSurfaceView.EGLConfigChooser, private val mEGLContextFactory: GLSurfaceView.EGLContextFactory,
private val mEGLWindowSurfaceFactory: GLSurfaceView.EGLWindowSurfaceFactory) : Thread() {
private val sGLThreadManager = GLThreadManager()
private var mEglOwner: GLThread? = null
lateinit var mHolder: SurfaceHolder
private var mSizeChanged = true
// Once the thread is started, all accesses to the following member
// variables are protected by the sGLThreadManager monitor
var mDone: Boolean = false
private var mPaused: Boolean = false
private var mHasSurface: Boolean = false
private var mWaitingForSurface: Boolean = false
private var mHaveEgl: Boolean = false
private var mWidth: Int = 0
private var mHeight: Int = 0
private var mRenderMode: Int = 0
private var mRequestRender: Boolean = false
private var mEventsWaiting: Boolean = false
private val mEventQueue = ArrayList<Runnable>()
private var mEglHelper: EglHelper? = null
private val isDone: Boolean
get() = synchronized(sGLThreadManager.lockObject) {
return mDone
}
var renderMode: Int
get() = synchronized(sGLThreadManager.lockObject) {
return mRenderMode
}
set(renderMode) {
if (!(GLWallpaperService.RENDERMODE_WHEN_DIRTY <= renderMode && renderMode <= GLWallpaperService.RENDERMODE_CONTINUOUSLY)) {
throw IllegalArgumentException("renderMode")
}
synchronized(sGLThreadManager.lockObject) {
mRenderMode = renderMode
if (renderMode == GLWallpaperService.RENDERMODE_CONTINUOUSLY) {
sGLThreadManager.lockObject.notifyAll()
}
}
}
private val event: Runnable?
get() {
synchronized(this) {
if (mEventQueue.size > 0) {
return mEventQueue.removeAt(0)
}
}
return null
}
init {
mDone = false
mWidth = 0
mHeight = 0
mRequestRender = true
mRenderMode = GLWallpaperService.RENDERMODE_CONTINUOUSLY
}
override fun run() {
name = "GLThread $id"
if (LOG_THREADS) {
Log.i("GLThread", "starting tid=$id")
}
try {
guardedRun()
} catch (e: InterruptedException) {
// fall thru and exit normally
} finally {
sGLThreadManager.threadExiting(this)
}
}
/*
* This private method should only be called inside a synchronized(sGLThreadManager.lockObject) block.
*/
private fun stopEglLocked() {
if (mHaveEgl) {
mHaveEgl = false
mEglHelper!!.destroySurface()
sGLThreadManager.releaseEglSurface(this)
}
}
@Throws(InterruptedException::class)
private fun guardedRun() {
mEglHelper = EglHelper(mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory)
try {
var gl: GL10? = null
var tellRendererSurfaceCreated = true
var tellRendererSurfaceChanged = true
/*
* This is our main activity thread's loop, we go until asked to quit.
*/
while (!isDone) {
/*
* Update the asynchronous state (window size)
*/
var w = 0
var h = 0
var changed = false
var needStart = false
var eventsWaiting = false
synchronized(sGLThreadManager.lockObject) {
while (true) {
// Manage acquiring and releasing the SurfaceView
// surface and the EGL surface.
if (mPaused) {
stopEglLocked()
}
if (!mHasSurface) {
if (!mWaitingForSurface) {
stopEglLocked()
mWaitingForSurface = true
sGLThreadManager.lockObject.notifyAll()
}
} else {
if (!mHaveEgl) {
if (sGLThreadManager.tryAcquireEglSurface(this)) {
mHaveEgl = true
mEglHelper!!.start()
mRequestRender = true
needStart = true
}
}
}
// Check if we need to wait. If not, update any state
// that needs to be updated, copy any state that
// needs to be copied, and use "break" to exit the
// wait loop.
if (mDone) {
return
}
if (mEventsWaiting) {
eventsWaiting = true
mEventsWaiting = false
break
}
if (!mPaused && mHasSurface && mHaveEgl && mWidth > 0 && mHeight > 0
&& (mRequestRender || mRenderMode == GLWallpaperService.RENDERMODE_CONTINUOUSLY)) {
changed = mSizeChanged
w = mWidth
h = mHeight
mSizeChanged = false
mRequestRender = false
if (mHasSurface && mWaitingForSurface) {
changed = true
mWaitingForSurface = false
sGLThreadManager.lockObject.notifyAll()
}
break
}
// By design, this is the only place where we wait().
if (LOG_THREADS) {
Log.i("GLThread", "waiting tid=$id")
}
sGLThreadManager.lockObject.wait()
}
} // end of synchronized(sGLThreadManager.lockObject)
/*
* Handle queued events
*/
if (eventsWaiting) {
var r: Runnable? = event
while (r != null) {
r!!.run()
if (isDone) {
return
}
}
// Go back and see if we need to wait to render.
continue
}
if (needStart) {
tellRendererSurfaceCreated = true
changed = true
}
if (changed) {
gl = mEglHelper!!.createSurface(mHolder) as GL10
tellRendererSurfaceChanged = true
}
if (tellRendererSurfaceCreated) {
mRenderer.onSurfaceCreated(gl, mEglHelper!!.mEglConfig)
tellRendererSurfaceCreated = false
}
if (tellRendererSurfaceChanged) {
mRenderer.onSurfaceChanged(gl, w, h)
tellRendererSurfaceChanged = false
}
if (w > 0 && h > 0) {
/* draw a frame here */
mRenderer.onDrawFrame(gl)
/*
* Once we're done with GL, we need to call swapBuffers() to instruct the system to display the
* rendered frame
*/
mEglHelper!!.swap()
Thread.sleep(10)
}
}
} finally {
/*
* clean-up everything...
*/
synchronized(sGLThreadManager.lockObject) {
stopEglLocked()
mEglHelper!!.finish()
}
}
}
fun requestRender() {
synchronized(sGLThreadManager.lockObject) {
mRequestRender = true
sGLThreadManager.lockObject.notifyAll()
}
}
fun surfaceCreated(holder: SurfaceHolder) {
mHolder = holder
synchronized(sGLThreadManager.lockObject) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=$id")
}
mHasSurface = true
sGLThreadManager.lockObject.notifyAll()
}
}
fun surfaceDestroyed() {
synchronized(sGLThreadManager.lockObject) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceDestroyed tid=$id")
}
mHasSurface = false
sGLThreadManager.lockObject.notifyAll()
while (!mWaitingForSurface && isAlive && !mDone) {
try {
sGLThreadManager.lockObject.wait()
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
}
}
}
}
fun onPause() {
synchronized(sGLThreadManager.lockObject) {
mPaused = true
sGLThreadManager.lockObject.notifyAll()
}
}
fun onResume() {
synchronized(sGLThreadManager.lockObject) {
mPaused = false
mRequestRender = true
sGLThreadManager.lockObject.notifyAll()
}
}
fun onWindowResize(w: Int, h: Int) {
synchronized(sGLThreadManager.lockObject) {
mWidth = w
mHeight = h
mSizeChanged = true
sGLThreadManager.lockObject.notifyAll()
}
}
fun requestExitAndWait() {
// don't call this from GLThread thread or it is a guaranteed
// deadlock!
synchronized(sGLThreadManager.lockObject) {
mDone = true
sGLThreadManager.lockObject.notifyAll()
}
try {
join()
} catch (ex: InterruptedException) {
Thread.currentThread().interrupt()
}
}
/**
* Queue an "event" to be run on the GL rendering thread.
*
* @param r
* the runnable to be run on the GL rendering thread.
*/
fun queueEvent(r: Runnable) {
synchronized(this) {
mEventQueue.add(r)
synchronized(sGLThreadManager.lockObject) {
mEventsWaiting = true
sGLThreadManager.lockObject.notifyAll()
}
}
}
private inner class GLThreadManager {
val lockObject = Object()
@Synchronized
fun threadExiting(thread: GLThread) {
synchronized(lockObject)
{
if (LOG_THREADS) {
Log.i("GLThread", "exiting tid=" + thread.id)
}
thread.mDone = true
if (mEglOwner === thread) {
mEglOwner = null
}
lockObject.notifyAll()
}
}
/*
* Tries once to acquire the right to use an EGL surface. Does not block.
*
* @return true if the right to use an EGL surface was acquired.
*/
@Synchronized
fun tryAcquireEglSurface(thread: GLThread): Boolean {
if (mEglOwner === thread || mEglOwner == null) {
mEglOwner = thread
lockObject.notifyAll()
return true
}
return false
}
@Synchronized
fun releaseEglSurface(thread: GLThread) {
if (mEglOwner === thread) {
mEglOwner = null
}
lockObject.notifyAll()
}
}
companion object {
private val LOG_THREADS = false
val DEBUG_CHECK_GL_ERROR = 1
val DEBUG_LOG_GL_CALLS = 2
}
}

View File

@ -1,25 +1,17 @@
package fishrungames.mountainwallpaper;
public class JniWrapper
class JniWrapper
{
static
{
System.loadLibrary("MountainWallpaper");
}
public static void LoadLibrary()
{
//To force loading libraries
}
public static native void SetTimeOfDayPref(int timeofday);
public static native void SetSnowPref(boolean snow);
public static native void Init(int width, int height);
public static native void SetOffset(float offsetX, float offsetY);
}

View File

@ -0,0 +1,127 @@
/*
* Copyright 2014 Google Inc.
*
* 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 fishrungames.mountainwallpaper
import android.content.*
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.preference.PreferenceManager
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.SurfaceHolder
import fishrungames.salmonengineandroid.EngineWrapper
class MountainWallpaper : GLWallpaperService(), SharedPreferences.OnSharedPreferenceChangeListener {
init
{
EngineWrapper.LoadSalmonEngineLibrary();
//JniWrapper.LoadLibrary();
}
override fun onCreate() {
super.onCreate()
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
EngineWrapper.SetActivityInstance(this)
EngineWrapper.SetupEnviroment()
var apkFilePath: String? = null
var appInfo: ApplicationInfo? = null
val packMgmr = this.packageManager
try {
appInfo = packMgmr.getApplicationInfo("fishrungames.mountainwallpaper", 0)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
throw RuntimeException("Unable to locate assets, aborting...")
}
apkFilePath = appInfo!!.sourceDir
EngineWrapper.SetupApkFilePath(apkFilePath)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return START_STICKY
}
override fun onCreateEngine(): Engine {
return MuzeiWallpaperEngine()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key.compareTo("Timeofday", ignoreCase = true) == 0) {
val time = Integer.parseInt(sharedPreferences.getString("Timeofday", "0")!!)
JniWrapper.SetTimeOfDayPref(time)
}
if (key.compareTo("Snow", ignoreCase = true) == 0) {
JniWrapper.SetSnowPref(sharedPreferences.getBoolean("Snow", false))
}
}
inner class MuzeiWallpaperEngine : GLWallpaperService.GLEngine()
{
private lateinit var renderer: WallpaperRenderer
private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
}
private val gestureDetector: GestureDetector = GestureDetector(this@MountainWallpaper,
gestureListener)
override fun onCreate(surfaceHolder: SurfaceHolder) {
super.onCreate(surfaceHolder)
setEGLContextClientVersion(2)
setRenderer(WallpaperRenderer())
renderMode = RENDERMODE_CONTINUOUSLY
requestRender()
// Use the MuzeiWallpaperService's lifecycle to wait for the user to unlock
setTouchEventsEnabled(true)
setOffsetNotificationsEnabled(true)
}
override fun onOffsetsChanged(
xOffset: Float,
yOffset: Float,
xOffsetStep: Float,
yOffsetStep: Float,
xPixelOffset: Int,
yPixelOffset: Int
) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset,
yPixelOffset)
JniWrapper.SetOffset(xPixelOffset * xOffsetStep, yPixelOffset * yOffsetStep)
}
override fun onTouchEvent(event: MotionEvent) {
super.onTouchEvent(event)
gestureDetector.onTouchEvent(event)
}
}
}

View File

@ -1,233 +0,0 @@
package fishrungames.mountainwallpaper;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
//import com.seb.SLWP.SLWP.GlEngine.DownloadTask;
import fishrungames.salmonengineandroid.EngineWrapper;
public class MountainWallpaperService extends GLWallpaperService implements
OnSharedPreferenceChangeListener {
/*
* (non-Javadoc)
*
* @see android.app.Service#onLowMemory()
*/
static
{
EngineWrapper.LoadSalmonEngineLibrary();
JniWrapper.LoadLibrary();
}
public static final long SLEEPTIME = 1000 * 60 * 30; // 30 minutes
private GlEngine mGle;
public static Context mContext;
public static boolean ShowClouds;
public static boolean TouchRot;
public static int Bg;
public static boolean Usebg;
public static int Tex;
static long Synctime;
public boolean Slidedir;
public boolean Slideplanet;
public boolean Syncrot;
public static boolean Randomtex = true;
public static boolean visible = false;
public static boolean useCropper = true;
public static int Cropaspect;
public static boolean loading = false;
public static final Handler mHandler = new Handler();
public static final int RNDMAP = -1;
public static boolean destroyed;
public static String bgfile;
public ConnectivityManager cm;
public boolean needresume;
public boolean fstart;
public static String[] randlist;
public int curtexidx = -99;
static final String ACTION_FOREGROUND = "fishrungames.mountainwallpaper.FOREGROUND";
static final String ACTION_BACKGROUND = "fishrungames.mountainwallpaper.BACKGROUND";
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
EngineWrapper.SetActivityInstance(this);
EngineWrapper.SetupEnviroment();
String apkFilePath = null;
ApplicationInfo appInfo = null;
PackageManager packMgmr = this.getPackageManager();
try {
appInfo = packMgmr.getApplicationInfo("fishrungames.mountainwallpaper", 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Unable to locate assets, aborting...");
}
apkFilePath = appInfo.sourceDir;
EngineWrapper.SetupApkFilePath(apkFilePath);
Init();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// handleCommand(intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
private void Init() {
try {
mContext = this;
cm = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key.compareToIgnoreCase("Timeofday") == 0)
{
int time = Integer.parseInt(sharedPreferences.getString("Timeofday", "0"));
JniWrapper.SetTimeOfDayPref(time);
}
if (key.compareToIgnoreCase("Snow") == 0) {
JniWrapper.SetSnowPref(sharedPreferences.getBoolean("Snow", false));
}
}
@Override
public Engine onCreateEngine() {
if (mGle != null) {
mGle = null;
}
try {
mGle = new GlEngine();
} catch (Exception e) {
return null;
}
return mGle;
}
class GlEngine extends GLEngine {
public Handler mHandler = new Handler();
long NOW;
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
try {
this.setTouchEventsEnabled(true);
fstart = true;
setRenderer();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onTouchEvent(MotionEvent e) {
return;
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep, int xPixelOffset,
int yPixelOffset) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
xPixelOffset, yPixelOffset);
JniWrapper.SetOffset(xPixelOffset*xOffsetStep, yPixelOffset*yOffsetStep);
}
@Override
public void onVisibilityChanged(boolean visible) {
// TODO Auto-generated method stub
super.onVisibilityChanged(visible);
MountainWallpaperService.visible = visible;
if (visible) {
} else {
}
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
super.onSurfaceChanged(holder, format, width, height);
fstart = true;
}
}
}

View File

@ -1,72 +0,0 @@
package fishrungames.mountainwallpaper;
import fishrungames.mountainwallpaper.R;
import fishrungames.mountainwallpaper.JniWrapper;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.Preference.OnPreferenceChangeListener;
public class Prefs extends PreferenceActivity implements
OnPreferenceChangeListener {
private CheckBoxPreference snowPref;
private ListPreference timeOfDayPref;
public static Uri currImageURI;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.prefliste);
addPreferencesFromResource(R.xml.preferences);
snowPref = (CheckBoxPreference)this.getPreferenceManager().findPreference("Snow");
timeOfDayPref = (ListPreference) findPreference("Timeofday");
if (timeOfDayPref.getKey().compareToIgnoreCase("Timeofday") == 0)
{
JniWrapper.SetTimeOfDayPref(Integer.parseInt((String) timeOfDayPref.getValue()));
}
if (snowPref.getKey().compareToIgnoreCase("Snow") == 0) {
if (!snowPref.isChecked())
{
JniWrapper.SetSnowPref(false);
}
else
{
JniWrapper.SetSnowPref(true);
}
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}

View File

@ -0,0 +1,11 @@
package fishrungames.mountainwallpaper
import android.support.v7.preference.PreferenceFragmentCompat
import android.os.Bundle
class WallpaperPreferenceFragment : PreferenceFragmentCompat()
{
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2014 Google Inc.
*
* 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 fishrungames.mountainwallpaper
import android.os.Bundle
import android.support.v4.app.FragmentActivity
class WallpaperPreferences : FragmentActivity()
{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.pref_activity)
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2014 Google Inc.
*
* 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 fishrungames.mountainwallpaper
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.util.Log
import fishrungames.salmonengineandroid.EngineWrapper
import java.util.*
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
class WallpaperRenderer() : GLSurfaceView.Renderer {
private var surfaceCreated: Boolean = false
private var lastTimeStamp: Long = 0
override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
surfaceCreated = true
}
override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
JniWrapper.Init(width, height)
}
override fun onDrawFrame(unused: GL10) {
val currentTimeStamp = Calendar.getInstance().timeInMillis
if (lastTimeStamp == 0L)
{
lastTimeStamp = currentTimeStamp
}
EngineWrapper.Update(currentTimeStamp - lastTimeStamp)
lastTimeStamp = currentTimeStamp
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</LinearLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_margin="20dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon">
</ImageView>
<fragment
class="fishrungames.mountainwallpaper.WallpaperPreferenceFragment"
android:id="@+id/preferences"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true">
</fragment>
<TextView
android:text="@string/feedback"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent">
<RelativeLayout
android:id="@+id/LinearLayout01"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<ImageView
android:id="@+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"
android:layout_alignParentLeft="true"
android:layout_marginLeft="3dp">
</ImageView>
</RelativeLayout>
<ListView
android:layout_width="fill_parent"
android:id="@android:id/list"
android:layout_height="wrap_content">
</ListView>
<TextView
android:layout_width="fill_parent"
android:id="@+id/android_text_feedback"
android:padding="20px"
android:text="@string/feedback"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>

View File

@ -5,9 +5,11 @@
<ListPreference
android:key="Timeofday" android:summary="@string/p_stimeofday"
android:title="@string/p_timeofday" android:entries="@array/timeofday_id"
android:entryValues="@array/timeofday_value" android:defaultValue="0"/>
android:entryValues="@array/timeofday_value" android:defaultValue="0"
/>
<CheckBoxPreference android:summaryOn="@string/p_snow_on"
android:key="Snow" android:title="@string/p_snow"
android:summaryOff="@string/p_snow_off" android:defaultValue="false" />
android:summaryOff="@string/p_snow_off" android:defaultValue="false"
/>
</PreferenceScreen>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:thumbnail="@drawable/thumb"
android:thumbnail="@drawable/icon"
android:description="@string/description"
android:settingsActivity="fishrungames.mountainwallpaper.Prefs"/>
android:settingsActivity="fishrungames.mountainwallpaper.WallpaperPreferences"
/>

View File

@ -1,17 +0,0 @@
package fishrungames.salmonandroidtemplate;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View File

@ -1,14 +1,20 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.2.70'
ext {
compileSdkVersion = 28
targetSdkVersion = 28
kotlin_version = "1.3.10"
supportLibraryVersion = "28.0.0"
}
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-rc03'
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong