commit 36b9ee93653a9016d3a3cee70b63220c4c5b0b9b
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Feb 16 00:53:35 2021 +0100

    Attempt to programmatically catch the 'cube is sometimes not drawn' bug and report it to my server.

diff --git a/src/main/java/org/distorted/effects/objectchange/ObjectChangeEffect.java b/src/main/java/org/distorted/effects/objectchange/ObjectChangeEffect.java
index 37a84bc0..bb3dfacf 100644
--- a/src/main/java/org/distorted/effects/objectchange/ObjectChangeEffect.java
+++ b/src/main/java/org/distorted/effects/objectchange/ObjectChangeEffect.java
@@ -50,7 +50,7 @@ public abstract class ObjectChangeEffect extends BaseEffect implements EffectLis
       }
     }
 
-  private static int NUM_EFFECTS = Type.values().length;
+  private static final int NUM_EFFECTS = Type.values().length;
   private static final int NUM_PHASES  = 2;
   private static final int FAKE_EFFECT_ID  = -1;
   private static final Type[] types;
@@ -68,10 +68,10 @@ public abstract class ObjectChangeEffect extends BaseEffect implements EffectLis
 
   private EffectController mController;
   private int mDuration;
-  private int[] mEffectReturned;
-  private int[] mCubeEffectNumber, mNodeEffectNumber;
-  private int[] mEffectFinished;
-  private boolean[] mPhaseActive;
+  private final int[] mEffectReturned;
+  private final int[] mCubeEffectNumber, mNodeEffectNumber;
+  private final int[] mEffectFinished;
+  private final boolean[] mPhaseActive;
 
   TwistyObject[] mObject;
   DistortedScreen mScreen;
diff --git a/src/main/java/org/distorted/effects/scramble/ScrambleEffect.java b/src/main/java/org/distorted/effects/scramble/ScrambleEffect.java
index 38bf43c8..304e1ef9 100644
--- a/src/main/java/org/distorted/effects/scramble/ScrambleEffect.java
+++ b/src/main/java/org/distorted/effects/scramble/ScrambleEffect.java
@@ -49,7 +49,7 @@ public abstract class ScrambleEffect extends BaseEffect implements EffectListene
       }
     }
 
-  private static int NUM_EFFECTS = Type.values().length;
+  private static final int NUM_EFFECTS = Type.values().length;
   private static final int FAKE_EFFECT_ID  = -3;
   private static final Type[] types;
 
@@ -72,7 +72,7 @@ public abstract class ScrambleEffect extends BaseEffect implements EffectListene
   private int mNumDoubleScramblesLeft, mNumScramblesLeft;
   private int mLastRotAxis, mLastRow;
   private long mDurationSingleTurn;
-  private Random mRnd;
+  private final Random mRnd;
   private int mBasicAngle;
 
   TwistyObject mObject;
diff --git a/src/main/java/org/distorted/main/RubikActivity.java b/src/main/java/org/distorted/main/RubikActivity.java
index f06bc1c8..825b05a5 100644
--- a/src/main/java/org/distorted/main/RubikActivity.java
+++ b/src/main/java/org/distorted/main/RubikActivity.java
@@ -41,6 +41,7 @@ import org.distorted.dialogs.RubikDialogPrivacy;
 import org.distorted.effects.BaseEffect;
 import org.distorted.library.main.DistortedLibrary;
 
+import org.distorted.library.message.EffectListener;
 import org.distorted.objects.TwistyObject;
 import org.distorted.scores.RubikScores;
 import org.distorted.scores.RubikScoresDownloader;
@@ -48,12 +49,13 @@ import org.distorted.objects.ObjectList;
 import org.distorted.states.StateList;
 import org.distorted.states.RubikStatePlay;
 import org.distorted.tutorial.TutorialActivity;
+import org.distorted.tutorial.TutorialList;
 
 import java.util.Locale;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class RubikActivity extends AppCompatActivity
+public class RubikActivity extends AppCompatActivity implements RubikDebug.ActivityChanger, EffectListener
 {
     public static final float PADDING             = 0.01f;
     public static final float MARGIN              = 0.004f;
@@ -89,6 +91,8 @@ public class RubikActivity extends AppCompatActivity
     private int mCurrentApiVersion;
     private boolean mIsLocked;
 
+    private static int mNumTests=0;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
@@ -224,6 +228,10 @@ public class RubikActivity extends AppCompatActivity
     protected void onPause() 
       {
       super.onPause();
+
+      RubikDebug debug = RubikDebug.getInstance();
+      debug.onPause();
+
       RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
       view.onPause();
       DistortedLibrary.onPause(0);
@@ -240,6 +248,10 @@ public class RubikActivity extends AppCompatActivity
       DistortedLibrary.onResume(0);
       RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
       view.onResume();
+
+      RubikDebug debug = RubikDebug.getInstance();
+      debug.onResume(this);
+
       view.initialize();
       restorePreferences();
       StateList.setState(this);
@@ -252,6 +264,10 @@ public class RubikActivity extends AppCompatActivity
         scores.setCountry(this);
         }
 
+RubikPreRender pre = view.getPreRender();
+pre.destroyNewObject();
+RubikDebug.addDebug("RubikActivity: onResume");
+
       boolean success = false;
       RubikStatePlay play = (RubikStatePlay) StateList.PLAY.getStateClass();
       int object = play.getObject();
@@ -572,4 +588,46 @@ public class RubikActivity extends AppCompatActivity
       myIntent.putExtra("siz", size);
       startActivity(myIntent);
       }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void change()
+    {
+    mNumTests++;
+
+    if( mNumTests<100 )
+      {
+      TutorialList list  = TutorialList.getObject(2);
+      ObjectList objList = list.getObjectList();
+      int size           = list.getSize();
+      String url         = list.getTutorialURL(0);
+
+      switchTutorial(url, objList, size);
+      }
+    else
+      {
+      finish();
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void assign()
+    {
+    RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
+    RubikPreRender pre = view.getPreRender();
+    TwistyObject object = pre.getObject();
+
+    int angle = 360 / object.getBasicAngle();
+
+    object.addNewRotation(1,1,angle,1000,this);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void effectFinished(final long effectID)
+    {
+    RubikDebug debug = RubikDebug.getInstance();
+    debug.onReturned();
+    }
 }
diff --git a/src/main/java/org/distorted/main/RubikDebug.java b/src/main/java/org/distorted/main/RubikDebug.java
new file mode 100644
index 00000000..22b0c2a3
--- /dev/null
+++ b/src/main/java/org/distorted/main/RubikDebug.java
@@ -0,0 +1,148 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2021 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is free software: you can redistribute it and/or modify                            //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Magic Cube is distributed in the hope that it will be useful,                                 //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.main;
+
+import org.distorted.scores.RubikScoresDownloader;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikDebug
+  {
+  private static final int CHECK_INTERVAL = 1000;
+
+  private String mDebug;
+  private long mResumeTime;
+  private int mNumReturned;
+  private ActivityChanger mChanger;
+
+  public static RubikDebug mThis;
+
+  public interface ActivityChanger
+    {
+    void change();
+    void assign();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void initialize()
+    {
+    mDebug      = "";
+    mResumeTime = 0;
+    mNumReturned= 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void report(String debug)
+    {
+    android.util.Log.e("debug", "Reporting: "+debug);
+
+    RubikScoresDownloader downloader = RubikScoresDownloader.getInstance();
+    downloader.error(debug);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void check(int loopNum)
+    {
+    if( loopNum==1 )
+      {
+      mChanger.assign();
+      }
+    if( loopNum==4 )
+      {
+      if( mNumReturned!=2 )
+        {
+        report(mDebug);
+        }
+
+      mChanger.change();
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private RubikDebug()
+    {
+    initialize();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static RubikDebug getInstance()
+    {
+    if( mThis==null ) mThis = new RubikDebug();
+
+    return mThis;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void addDebug(String debug)
+    {
+    if( mThis==null ) mThis = new RubikDebug();
+
+    mThis.mDebug += (debug + "\n");
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onResume(ActivityChanger changer)
+    {
+    mChanger = changer;
+    mResumeTime = System.currentTimeMillis();
+
+    final Timer timer = new Timer();
+
+    timer.scheduleAtFixedRate(new TimerTask()
+      {
+      private int mLoopNum = 0;
+
+      @Override
+      public void run()
+        {
+        if( mLoopNum==5 )
+          {
+          timer.cancel();
+          }
+
+        check(mLoopNum++);
+        }
+      } ,CHECK_INTERVAL, CHECK_INTERVAL);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onPause()
+    {
+    initialize();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onReturned()
+    {
+    mNumReturned++;
+    }
+  }
diff --git a/src/main/java/org/distorted/main/RubikPreRender.java b/src/main/java/org/distorted/main/RubikPreRender.java
index abd17412..77f854ce 100644
--- a/src/main/java/org/distorted/main/RubikPreRender.java
+++ b/src/main/java/org/distorted/main/RubikPreRender.java
@@ -55,7 +55,7 @@ public class RubikPreRender implements EffectController
     void onActionFinished(long effectID);
     }
 
-  private RubikSurfaceView mView;
+  private final RubikSurfaceView mView;
   private boolean mFinishRotation, mRemoveRotation, mRemovePatternRotation, mAddRotation,
                   mSetQuat, mChangeObject, mSetupObject, mSolveObject, mScrambleObject,
                   mInitializeObject, mSetTextureMap, mResetAllTextureMaps;
@@ -64,7 +64,7 @@ public class RubikPreRender implements EffectController
   private ObjectList mNextObject;
   private int mNextSize;
   private long mRotationFinishedID;
-  private long[] mEffectID;
+  private final long[] mEffectID;
   private boolean mIsNewRecord;
   private long mNewRecord;
   private int mScreenWidth;
@@ -111,6 +111,17 @@ public class RubikPreRender implements EffectController
     mDebug = "";
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void destroyNewObject()
+    {
+    if( mNewObject!=null )
+      {
+      mNewObject.releaseResources();
+      mNewObject = null;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void createObjectNow(ObjectList object, int size, int[][] moves)
diff --git a/src/main/java/org/distorted/objects/TwistyObject.java b/src/main/java/org/distorted/objects/TwistyObject.java
index 5eac8f87..b2a98bb7 100644
--- a/src/main/java/org/distorted/objects/TwistyObject.java
+++ b/src/main/java/org/distorted/objects/TwistyObject.java
@@ -47,6 +47,7 @@ import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.BuildConfig;
+import org.distorted.main.RubikDebug;
 
 import java.io.DataInputStream;
 import java.io.IOException;
@@ -618,6 +619,8 @@ public abstract class TwistyObject extends DistortedNode
 
   public synchronized long addNewRotation( int axis, int rowBitmap, int angle, long durationMillis, EffectListener listener )
     {
+    RubikDebug.addDebug("adding new rot: axis="+axis+" rowBmp="+rowBitmap+" angle="+angle+" dur="+durationMillis+" object="+getObjectList().name());
+
     mRotAxis     = axis;
     mRotRowBitmap= rowBitmap;
 
diff --git a/src/main/java/org/distorted/scores/RubikScoresDownloader.java b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
index 25133a0f..82e4d4d4 100644
--- a/src/main/java/org/distorted/scores/RubikScoresDownloader.java
+++ b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
@@ -19,6 +19,7 @@
 
 package org.distorted.scores;
 
+import android.app.Activity;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 
@@ -50,7 +51,8 @@ public class RubikScoresDownloader implements Runnable
 
   private static final int DOWNLOAD   = 0;
   private static final int SUBMIT     = 1;
-  private static final int IDLE       = 2;
+  private static final int ERROR      = 2;
+  private static final int IDLE       = 3;
 
   private final String[] hex = {
     "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
@@ -99,6 +101,7 @@ public class RubikScoresDownloader implements Runnable
   private static int mMode = IDLE;
   private static Receiver mReceiver;
   private static String mVersion;
+  private static String mError = "";
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -381,6 +384,13 @@ public class RubikScoresDownloader implements Runnable
     return url1 + "?" + url2 + "&h=" + hash;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private String constructErrorURL()
+    {
+    return "https://distorted.org/magic/cgi-bin/error.cgi?e="+URLencode(mError);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private boolean gottaDownload()
@@ -411,25 +421,36 @@ public class RubikScoresDownloader implements Runnable
           success = network(constructSubmitURL());
           }
         }
+      if( mMode==ERROR )
+        {
+        mRunning = true;
+        success = network(constructErrorURL());
+        }
       }
     catch( Exception e )
       {
-      mReceiver.message("Exception downloading records: "+e.getMessage() );
-      }
-
-    if( mRunning )
-      {
-      success = fillValues();
-      mRunning = false;
+      if( mReceiver!=null )
+        {
+        mReceiver.message("Exception downloading records: "+e.getMessage() );
+        }
       }
 
-    if( success )
+    if( mReceiver!=null )
       {
-      mReceiver.receive(mCountry, mName, mTime);
+      if( mRunning )
+        {
+        success = fillValues();
+        mRunning = false;
+        }
 
-      if( mMode==SUBMIT )
+      if( success )
         {
-        RubikScores.getInstance().successfulSubmit();
+        mReceiver.receive(mCountry, mName, mTime);
+
+        if( mMode==SUBMIT )
+          {
+          RubikScores.getInstance().successfulSubmit();
+          }
         }
       }
     }
@@ -464,15 +485,18 @@ public class RubikScoresDownloader implements Runnable
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void start(Receiver receiver, FragmentActivity act, int mode)
+  private void start(Receiver receiver, Activity act, int mode)
     {
     mReceiver = receiver;
     mMode     = mode;
 
     try
       {
-      PackageInfo pInfo = act.getPackageManager().getPackageInfo( act.getPackageName(), 0);
-      mVersion = pInfo.versionName;
+      if( act!=null )
+        {
+        PackageInfo pInfo = act.getPackageManager().getPackageInfo( act.getPackageName(), 0);
+        mVersion = pInfo.versionName;
+        }
       }
     catch (PackageManager.NameNotFoundException e)
       {
@@ -483,6 +507,14 @@ public class RubikScoresDownloader implements Runnable
     networkThrd.start();
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void error(String error)
+    {
+    mError = error;
+    start(null, null, ERROR);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void download(Receiver receiver, FragmentActivity act)
diff --git a/src/main/java/org/distorted/states/RubikStateSolving.java b/src/main/java/org/distorted/states/RubikStateSolving.java
index a7373630..15bb7ea5 100644
--- a/src/main/java/org/distorted/states/RubikStateSolving.java
+++ b/src/main/java/org/distorted/states/RubikStateSolving.java
@@ -43,7 +43,7 @@ public class RubikStateSolving extends RubikStateBase
   private Timer mTimer;
   private long mStartTime;
   private boolean mRunning;
-  private RubikScores mScores;
+  private final RubikScores mScores;
   private long mElapsed;
   private ImageButton mBackButton;
 
diff --git a/src/main/java/org/distorted/tutorial/TutorialActivity.java b/src/main/java/org/distorted/tutorial/TutorialActivity.java
index 592f8841..55aaae39 100644
--- a/src/main/java/org/distorted/tutorial/TutorialActivity.java
+++ b/src/main/java/org/distorted/tutorial/TutorialActivity.java
@@ -30,11 +30,11 @@ import android.widget.LinearLayout;
 
 import androidx.appcompat.app.AppCompatActivity;
 
-import com.google.firebase.analytics.FirebaseAnalytics;
-
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.library.main.DistortedLibrary;
+import org.distorted.library.message.EffectListener;
 import org.distorted.main.R;
+import org.distorted.main.RubikDebug;
 import org.distorted.objects.ObjectList;
 import org.distorted.objects.TwistyObject;
 import org.distorted.states.StateList;
@@ -43,7 +43,7 @@ import static org.distorted.main.RubikRenderer.BRIGHTNESS;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class TutorialActivity extends AppCompatActivity
+public class TutorialActivity extends AppCompatActivity implements RubikDebug.ActivityChanger, EffectListener
 {
     private static final String URL = "https://www.youtube.com/embed/";
 
@@ -56,11 +56,7 @@ public class TutorialActivity extends AppCompatActivity
                                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 
-    public static final int FLAGS2=  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                                   | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-
     private boolean mIsLocked;
-    private FirebaseAnalytics mFirebaseAnalytics;
     private static int mScreenWidth, mScreenHeight;
     private int mCurrentApiVersion;
     private TutorialState mState;
@@ -88,7 +84,6 @@ public class TutorialActivity extends AppCompatActivity
         }
 
       mIsLocked = false;
-      mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
 
       DisplayMetrics displaymetrics = new DisplayMetrics();
       getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
@@ -189,6 +184,8 @@ public class TutorialActivity extends AppCompatActivity
       super.onPause();
       TutorialSurfaceView view = findViewById(R.id.tutorialSurfaceView);
       view.onPause();
+      RubikDebug debug = RubikDebug.getInstance();
+      debug.onPause();
 
       if( mWebView!=null ) mWebView.onPause();
 
@@ -201,6 +198,10 @@ public class TutorialActivity extends AppCompatActivity
     protected void onResume() 
       {
       super.onResume();
+      RubikDebug debug = RubikDebug.getInstance();
+      debug.onResume(this);
+      RubikDebug.addDebug("RubikActivity: onResume");
+
       DistortedLibrary.onResume(1);
       TutorialSurfaceView view = findViewById(R.id.tutorialSurfaceView);
       view.onResume();
@@ -247,13 +248,6 @@ public class TutorialActivity extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public FirebaseAnalytics getAnalytics()
-      {
-      return mFirebaseAnalytics;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public TwistyObject getObject()
@@ -270,13 +264,6 @@ public class TutorialActivity extends AppCompatActivity
       return mScreenWidth;
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public TutorialPreRender getPreRender()
@@ -355,4 +342,32 @@ public class TutorialActivity extends AppCompatActivity
       {
       return mIsLocked;
       }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void change()
+    {
+    finish();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void assign()
+    {
+    TutorialSurfaceView view = findViewById(R.id.tutorialSurfaceView);
+    TutorialPreRender pre = view.getPreRender();
+    TwistyObject object = pre.getObject();
+
+    int angle = 360 / object.getBasicAngle();
+
+    object.addNewRotation(1,1,angle,1000,this);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void effectFinished(final long effectID)
+    {
+    RubikDebug debug = RubikDebug.getInstance();
+    debug.onReturned();
+    }
 }
diff --git a/src/main/java/org/distorted/tutorial/TutorialPreRender.java b/src/main/java/org/distorted/tutorial/TutorialPreRender.java
index 3b212bed..cd476c2a 100644
--- a/src/main/java/org/distorted/tutorial/TutorialPreRender.java
+++ b/src/main/java/org/distorted/tutorial/TutorialPreRender.java
@@ -34,7 +34,7 @@ import org.distorted.scores.RubikScores;
 public class TutorialPreRender implements EffectController
   {
   private ActionFinishedListener mAddActionListener;
-  private TutorialSurfaceView mView;
+  private final TutorialSurfaceView mView;
   private boolean mFinishRotation, mRemoveRotation, mAddRotation,
                   mSetQuat, mChangeObject, mSetupObject, mSolveObject, mScrambleObject,
                   mInitializeObject, mResetAllTextureMaps, mRemovePatternRotation;
@@ -335,14 +335,6 @@ public class TutorialPreRender implements EffectController
     mAddRotationDuration  = duration;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void initializeObject(int[][] moves)
-    {
-    mInitializeObject = true;
-    mNextMoves = moves;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getNumScrambles()
@@ -371,13 +363,6 @@ public class TutorialPreRender implements EffectController
       }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void resetAllTextureMaps()
-    {
-    mResetAllTextureMaps = true;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public TwistyObject getObject()
diff --git a/src/main/java/org/distorted/tutorial/TutorialState.java b/src/main/java/org/distorted/tutorial/TutorialState.java
index 189938b9..8370d21c 100644
--- a/src/main/java/org/distorted/tutorial/TutorialState.java
+++ b/src/main/java/org/distorted/tutorial/TutorialState.java
@@ -46,7 +46,7 @@ public class TutorialState implements RubikPreRender.ActionFinishedListener
 
   private static class Move
     {
-    private int mAxis, mRow, mAngle;
+    private final int mAxis, mRow, mAngle;
 
     Move(int axis, int row, int angle)
       {
diff --git a/src/main/java/org/distorted/tutorial/TutorialSurfaceView.java b/src/main/java/org/distorted/tutorial/TutorialSurfaceView.java
index 178a675f..0bd55aa4 100644
--- a/src/main/java/org/distorted/tutorial/TutorialSurfaceView.java
+++ b/src/main/java/org/distorted/tutorial/TutorialSurfaceView.java
@@ -70,8 +70,8 @@ public class TutorialSurfaceView extends GLSurfaceView
     private int mFirstIndex, mLastIndex;
     private int mDensity;
 
-    private static Static4D mQuat= new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
-    private static Static4D mTemp= new Static4D(0,0,0,1);
+    private static final Static4D mQuat= new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
+    private static final Static4D mTemp= new Static4D(0,0,0,1);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
