commit 40d02f47b58d01bbf64af7445aeb7e5460fb7357
Author: leszek <leszek@koltunski.pl>
Date:   Fri Nov 15 13:06:26 2024 +0100

    Initial commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..a9fb009
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,36 @@
+plugins {
+    id 'com.android.application'
+}
+
+android {
+    namespace 'org.distorted.phasedsolver'
+    compileSdk 34
+
+    defaultConfig {
+        applicationId "org.distorted.phasedsolver"
+        minSdk 21
+        targetSdk 34
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    api project(':distorted-objectlib')
+    implementation project(':distorted-os-android')
+    implementation ('androidx.preference:preference:1.2.1')
+}
+
diff --git a/proguard-rules.pro b/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..cd84e15
--- /dev/null
+++ b/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
+    <uses-feature android:name="android.hardware.faketouch" android:required="true" />
+
+    <supports-screens android:largeScreens="true" android:xlargeScreens="true" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
+
+        <activity android:name="org.distorted.phasedsolver.SolverActivity" android:exported="true" android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/src/main/java/org/distorted/phasedsolver/SolverActivity.java b/src/main/java/org/distorted/phasedsolver/SolverActivity.java
new file mode 100644
index 0000000..ec60cb7
--- /dev/null
+++ b/src/main/java/org/distorted/phasedsolver/SolverActivity.java
@@ -0,0 +1,143 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2024 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.phasedsolver;
+
+import static org.distorted.objectlib.main.TwistyObject.MODE_NORM;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+import androidx.preference.PreferenceManager;
+
+import org.distorted.library.main.DistortedLibrary;
+import org.distorted.objectlib.main.InitAssets;
+import org.distorted.objectlib.main.ObjectControl;
+import org.distorted.objectlib.metadata.ListObjects;
+import org.distorted.os.OSInterface;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class SolverActivity extends Activity
+{
+    private InitAssets mAsset;
+    private SharedPreferences mPreferences;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    protected void onCreate(Bundle icicle) 
+      {
+      super.onCreate(icicle);
+      mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+      DistortedLibrary.onCreate();
+      setContentView(R.layout.mainlayout);
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      OSInterface os = view.getInterface();
+      mAsset = new InitAssets(null,null,os);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onPause() 
+      {
+      super.onPause();
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      view.onPause();
+      DistortedLibrary.onPause();
+
+      savePreferences();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onResume() 
+      {
+      super.onResume();
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      view.onResume();
+      DistortedLibrary.onResume();
+
+      restorePreferences();
+
+      ObjectControl control = getControl();
+      control.changeObject( ListObjects.CUBE_3.ordinal(), MODE_NORM, mAsset);
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onDestroy() 
+      {
+      DistortedLibrary.onDestroy();
+      super.onDestroy();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private ObjectControl getControl()
+      {
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      return view.getObjectControl();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void savePreferences()
+      {
+      SharedPreferences.Editor editor = mPreferences.edit();
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      OSInterface os = view.getInterface();
+      os.setEditor(editor);
+      view.getObjectControl().savePreferences();
+
+      editor.apply();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void restorePreferences()
+      {
+      SolverSurfaceView view = findViewById(R.id.solverView);
+      OSInterface os = view.getInterface();
+      os.setPreferences(mPreferences);
+      view.getObjectControl().restorePreferences();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Reset(View v)
+      {
+
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Solve(View v)
+      {
+
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Left(View v)
+      {
+
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Right(View v)
+      {
+
+      }
+}
diff --git a/src/main/java/org/distorted/phasedsolver/SolverObjectLibInterface.java b/src/main/java/org/distorted/phasedsolver/SolverObjectLibInterface.java
new file mode 100644
index 0000000..0913a0a
--- /dev/null
+++ b/src/main/java/org/distorted/phasedsolver/SolverObjectLibInterface.java
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2024 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.phasedsolver;
+
+import org.distorted.objectlib.helpers.ObjectLibInterface;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class SolverObjectLibInterface implements ObjectLibInterface
+{
+  public void onWinEffectFinished(long startTime, long endTime, String debug, int scrambleNum) { }
+  public void onScrambleEffectFinished() { }
+  public void onBeginRotation() { }
+  public void onSolved() { }
+  public void onObjectCreated(long time) { }
+  public void onRemoveRotation(int axis, int row, int angle) { }
+  public void failedToDrag() { }
+  public void reportBlockProblem(int type, int place, long pause, long resume, long time) { }
+  public void reportProblem(String problem, boolean reportException) {}
+
+  public void onReplaceModeDown(int cubit, int face) { }
+  public void onReplaceModeUp() { }
+  public void reportJSONError(String error, int ordinal) { }
+}
diff --git a/src/main/java/org/distorted/phasedsolver/SolverRenderer.java b/src/main/java/org/distorted/phasedsolver/SolverRenderer.java
new file mode 100644
index 0000000..a9bae20
--- /dev/null
+++ b/src/main/java/org/distorted/phasedsolver/SolverRenderer.java
@@ -0,0 +1,109 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2024 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.phasedsolver;
+
+import android.content.res.Resources;
+import android.opengl.GLSurfaceView;
+
+import org.distorted.library.effect.EffectType;
+import org.distorted.library.effect.PostprocessEffectBorder;
+import org.distorted.library.effect.VertexEffectQuaternion;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.main.DistortedLibrary;
+import org.distorted.library.main.DistortedScreen;
+import org.distorted.library.mesh.MeshBase;
+import org.distorted.objectlib.effects.BaseEffect;
+import org.distorted.objectlib.main.ObjectControl;
+
+import java.io.InputStream;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SolverRenderer implements GLSurfaceView.Renderer, DistortedLibrary.LibraryUser
+{
+    static final float BRIGHTNESS = 0.30f;
+
+    private final SolverSurfaceView mView;
+    private final DistortedScreen mScreen;
+    private final Resources mResources;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    SolverRenderer(SolverSurfaceView v)
+      {
+      mView = v;
+      mResources = v.getResources();
+      mScreen = new DistortedScreen();
+      mScreen.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    DistortedScreen getScreen()
+      {
+      return mScreen;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void onDrawFrame(GL10 glUnused) 
+      {
+      long time = System.currentTimeMillis();
+      mView.getObjectControl().preRender();
+      mScreen.render(time);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void onSurfaceChanged(GL10 glUnused, int width, int height) 
+      {
+      mScreen.resize(width,height);
+      mView.setScreenSize(width,height);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
+      {
+      DistortedLibrary.setMax(EffectType.VERTEX,ObjectControl.MAX_QUATS+1);
+      MeshBase.setMaxEffComponents(ObjectControl.MAX_MOVING_PARTS);
+
+      VertexEffectRotate.enable();
+      VertexEffectQuaternion.enable();
+      PostprocessEffectBorder.enable();
+      BaseEffect.Type.enableEffects();
+
+      DistortedLibrary.onSurfaceCreated(this);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void distortedException(Exception ex)
+      {
+      android.util.Log.e("Solver", ex.getMessage() );
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public InputStream localFile(int fileID)
+      {
+      return mResources.openRawResource(fileID);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void logMessage(String message)
+      {
+      android.util.Log.e("Solver", message );
+      }
+}
diff --git a/src/main/java/org/distorted/phasedsolver/SolverSurfaceView.java b/src/main/java/org/distorted/phasedsolver/SolverSurfaceView.java
new file mode 100644
index 0000000..e4f3c9f
--- /dev/null
+++ b/src/main/java/org/distorted/phasedsolver/SolverSurfaceView.java
@@ -0,0 +1,130 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2024 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.phasedsolver;
+
+import static org.distorted.objectlib.main.ObjectControl.MODE_ROTATE;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import org.distorted.objectlib.main.ObjectControl;
+import org.distorted.objectlib.main.TwistyObjectNode;
+import org.distorted.os.OSInterface;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SolverSurfaceView extends GLSurfaceView
+{
+    private ObjectControl mObjectController;
+    private OSInterface mInterface;
+    private SolverRenderer mRenderer;
+    private int mScreenWidth;
+    private boolean mCreated;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void setScreenSize(int width, int height)
+      {
+      mScreenWidth = width;
+      mObjectController.setScreenSizeAndScaling(width,height, Math.min(width,height) );
+
+      if( !mCreated )
+        {
+        mCreated = true;
+        mObjectController.createNode(width,height);
+        TwistyObjectNode objectNode = mObjectController.getNode();
+        mRenderer.getScreen().attach(objectNode);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    int getScreenWidth()
+      {
+      return mScreenWidth;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    ObjectControl getObjectControl()
+      {
+      return mObjectController;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    OSInterface getInterface()
+      {
+      return mInterface;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    SolverRenderer getRenderer()
+      {
+      return mRenderer;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public SolverSurfaceView(Context context, AttributeSet attrs)
+      {
+      super(context,attrs);
+
+      mCreated = false;
+
+      if(!isInEditMode())
+        {
+        SolverActivity act = (SolverActivity)context;
+        SolverObjectLibInterface ref = new SolverObjectLibInterface();
+        mInterface = new OSInterface(act,ref);
+        mObjectController = new ObjectControl(mInterface);
+
+        mRenderer = new SolverRenderer(this);
+        final ActivityManager activityManager= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+        int esVersion = configurationInfo.reqGlEsVersion>>16;
+        setEGLContextClientVersion(esVersion);
+        setRenderer(mRenderer);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onPause()
+      {
+      super.onPause();
+      mObjectController.onPause();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onResume()
+      {
+      super.onResume();
+      mObjectController.onResume();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event)
+      {
+      mInterface.setMotionEvent(event);
+      return mObjectController.onTouchEvent(MODE_ROTATE);
+      }
+}
+
diff --git a/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/src/main/res/drawable/ic_launcher_background.xml b/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/src/main/res/drawable/ui_left.png b/src/main/res/drawable/ui_left.png
new file mode 100644
index 0000000..7b71291
Binary files /dev/null and b/src/main/res/drawable/ui_left.png differ
diff --git a/src/main/res/drawable/ui_right.png b/src/main/res/drawable/ui_right.png
new file mode 100644
index 0000000..c1da12a
Binary files /dev/null and b/src/main/res/drawable/ui_right.png differ
diff --git a/src/main/res/layout/mainlayout.xml b/src/main/res/layout/mainlayout.xml
new file mode 100644
index 0000000..4fa60e4
--- /dev/null
+++ b/src/main/res/layout/mainlayout.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/relativeLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <org.distorted.phasedsolver.SolverSurfaceView
+        android:id="@+id/solverView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"/>
+
+    <LinearLayout
+        android:id="@+id/upperBar"
+        android:layout_alignParentTop="true"
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:gravity="center"
+        android:orientation="horizontal"
+        android:background="@android:color/transparent">
+
+        <Button
+            android:id="@+id/solverReset"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_vertical|center"
+            android:text="@string/reset"
+            android:onClick="Reset"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_gravity="center_vertical"/>
+
+        <Button
+            android:id="@+id/solverSolve"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_vertical|center"
+            android:text="@string/solve"
+            android:onClick="Solve"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_gravity="center_vertical"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/lowerBar"
+        android:layout_alignParentBottom="true"
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:orientation="horizontal"
+        android:background="@android:color/transparent">
+
+        <ImageButton
+            android:id="@+id/solverLeft"
+            android:background="@drawable/ui_left"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_vertical|center"
+            android:onClick="Left"
+            android:layout_gravity="center_vertical"/>
+
+        <TextView
+            android:id="@+id/solverText"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="4.0"/>
+
+        <ImageButton
+            android:id="@+id/solverRight"
+            android:background="@drawable/ui_right"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1.0"
+            android:gravity="center_vertical|center"
+            android:onClick="Right"
+            android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/src/main/res/mipmap-hdpi/ic_launcher.webp b/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/src/main/res/mipmap-mdpi/ic_launcher.webp b/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/src/main/res/mipmap-xhdpi/ic_launcher.webp b/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
new file mode 100644
index 0000000..b2a69af
--- /dev/null
+++ b/src/main/res/values/colors.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#D81B60</color>
+    <color name="red">#ffff0000</color>
+    <color name="dark_grey">#ff222222</color>
+    <color name="grey">#ff333333</color>
+    <color name="light_grey">#ff555555</color>
+    <color name="black">#ff010101</color>
+    <color name="white">#ffffffff</color>
+</resources>
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6e32fae
--- /dev/null
+++ b/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+<resources>
+    <string name="app_name">Phased Solver</string>
+    <string name="solve">Solve</string>
+    <string name="reset">Reset</string>
+</resources>
\ No newline at end of file
