commit 001cc0e44dea3d5c1ef1bf7baa16d5c6cc5de9bc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sun Apr 26 12:27:29 2020 +0100

    Fix a potential crasher ( do not set up a callback for end of rotation effect on the very first cubit that belongs to a rotation if all belonging cubits have not been set up yet )

diff --git a/src/main/java/org/distorted/objects/Cubit.java b/src/main/java/org/distorted/objects/Cubit.java
index 9bf07561..b277e435 100644
--- a/src/main/java/org/distorted/objects/Cubit.java
+++ b/src/main/java/org/distorted/objects/Cubit.java
@@ -21,8 +21,6 @@ package org.distorted.objects;
 
 import android.content.SharedPreferences;
 
-import com.google.firebase.crashlytics.FirebaseCrashlytics;
-
 import org.distorted.library.effect.MatrixEffectMove;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.effect.MatrixEffectRotate;
@@ -40,6 +38,7 @@ import org.distorted.main.RubikSurfaceView;
 
 class Cubit
   {
+  private static final int POST_ROTATION_MILLISEC = 500;
   private static final Static3D matrCenter = new Static3D(0,0,0);
 
   private final Static3D mOrigPosition;
@@ -50,8 +49,8 @@ class Cubit
   private MatrixEffectRotate mRotateEffect;
   private Static3D mCurrentPosition;
   private int mNumAxis;
+  private Dynamic1D mRotationAngle;
 
-  Dynamic1D mRotationAngle;
   DistortedNode mNode;
   DistortedEffects mEffect;
   Static4D mQuatScramble;
@@ -300,62 +299,43 @@ class Cubit
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  long finishRotationNow(EffectListener listener)
+  void removeRotationNow(Static4D quat)
     {
-    int pointNum = mRotationAngle.getNumPoints();
-
-    if( pointNum>=1 )
-      {
-      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
-      int nearestAngleInDegrees = mParent.computeNearestAngle(startingAngle);
-      mParent.mRotationAngleStatic.set0(startingAngle);
-      mParent.mRotationAngleFinal.set0(nearestAngleInDegrees);
-      mParent.mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
-      return setUpCallback(listener);
-      }
-    else
-      {
-      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
-      crashlytics.setCustomKey("points", "finish, points in RotationAngle: "+pointNum );
-      return 0;
-      }
+    mRotationAngle.removeAll();
+    mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
+    normalizeScrambleQuat( mQuatScramble );
+    modifyCurrentPosition(quat);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  Static4D returnRotationQuat(int axis)
+  void beginNewRotation(int axis)
     {
-    int pointNum = mRotationAngle.getNumPoints();
+    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
+    mRotationAngle.add(mParent.mRotationAngleStatic);
+    }
 
-    if( pointNum>=1 )
-      {
-      float axisX = mParent.ROTATION_AXIS[axis].get0();
-      float axisY = mParent.ROTATION_AXIS[axis].get1();
-      float axisZ = mParent.ROTATION_AXIS[axis].get2();
-
-      float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
-      int nearestAngleInDegrees = mParent.computeNearestAngle(startingAngle);
-      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
-      float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
-      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
-      return new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
-      }
-    else
-      {
-      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
-      crashlytics.setCustomKey("points", "return, points in RotationAngle: "+pointNum );
-      return null;
-      }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void addNewRotation(int axis, long durationMillis, int angle)
+    {
+    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
+    mRotationAngle.setDuration(durationMillis);
+    mRotationAngle.resetToBeginning();
+    mRotationAngle.add(new Static1D(0));
+    mRotationAngle.add(new Static1D(angle));
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void removeRotationNow(Static4D quat)
+  void resetRotationAngle()
     {
+    mRotationAngle.setDuration(POST_ROTATION_MILLISEC);
+    mRotationAngle.resetToBeginning();
     mRotationAngle.removeAll();
-    mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
-    normalizeScrambleQuat( mQuatScramble );
-    modifyCurrentPosition(quat);
+    mRotationAngle.add(mParent.mRotationAngleStatic);
+    mRotationAngle.add(mParent.mRotationAngleMiddle);
+    mRotationAngle.add(mParent.mRotationAngleFinal);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -378,25 +358,6 @@ class Cubit
     computeRotationRow();
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void beginNewRotation(int axis)
-    {
-    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
-    mRotationAngle.add(mParent.mRotationAngleStatic);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void addNewRotation(int axis, long durationMillis, int angle)
-    {
-    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
-    mRotationAngle.setDuration(durationMillis);
-    mRotationAngle.resetToBeginning();
-    mRotationAngle.add(new Static1D(0));
-    mRotationAngle.add(new Static1D(angle));
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   long setUpCallback(EffectListener listener)
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index 87180f14..202228a6 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -34,7 +34,6 @@ import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
 import org.distorted.library.mesh.MeshRectangles;
 import org.distorted.library.message.EffectListener;
-import org.distorted.library.type.Dynamic1D;
 import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
@@ -51,7 +50,6 @@ public abstract class RubikObject extends DistortedNode
 
   static float OBJECT_SCREEN_RATIO;
 
-  private static final int POST_ROTATION_MILLISEC = 500;
   private final int NUM_CUBITS;
   private int mRotRowBitmap;
   private int mRotAxis;
@@ -205,18 +203,6 @@ public abstract class RubikObject extends DistortedNode
     return diff*diff < MAX_ERROR;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void resetRotationAngle(Dynamic1D rotationAngle)
-    {
-    rotationAngle.setDuration(POST_ROTATION_MILLISEC);
-    rotationAngle.resetToBeginning();
-    rotationAngle.removeAll();
-    rotationAngle.add(mRotationAngleStatic);
-    rotationAngle.add(mRotationAngleMiddle);
-    rotationAngle.add(mRotationAngleFinal);
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // note the minus in front of the sin() - we rotate counterclockwise
 // when looking towards the direction where the axis increases in values.
@@ -368,29 +354,6 @@ public abstract class RubikObject extends DistortedNode
     for(int i=0; i<NUM_CUBITS; i++) mCubits[i].restorePreferences(preferences);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public long finishRotationNow(EffectListener listener)
-    {
-    boolean first = true;
-    long effectID=0;
-
-    for(int i=0; i<NUM_CUBITS; i++)
-      {
-      if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
-        {
-        if( first )
-          {
-          first=false;
-          effectID = mCubits[i].finishRotationNow(listener);
-          }
-        resetRotationAngle(mCubits[i].mRotationAngle);
-        }
-      }
-
-    return effectID;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void releaseResources()
@@ -490,7 +453,7 @@ public abstract class RubikObject extends DistortedNode
   public long addNewRotation( int axis, int rowBitmap, int angle, long durationMillis, EffectListener listener )
      {
      long effectID=0;
-     boolean first = true;
+     int firstCubit = -1;
 
      mRotAxis       = axis;
      mRotRowBitmap  = rowBitmap;
@@ -501,17 +464,44 @@ public abstract class RubikObject extends DistortedNode
        if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
          {
          mCubits[i].addNewRotation(axis,durationMillis,angle);
-
-         if( first )
-           {
-           first = false;
-           effectID = mCubits[i].setUpCallback(listener);
-           }
+         if( firstCubit<0 ) firstCubit = i;
          }
 
+     if( firstCubit>=0 ) effectID = mCubits[firstCubit].setUpCallback(listener);
+
      return effectID;
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public long finishRotationNow(EffectListener listener)
+    {
+    int firstCubit= -1;
+    long effectID =  0;
+
+    for(int i=0; i<NUM_CUBITS; i++)
+      {
+      if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
+        {
+        if( firstCubit<0 )
+          {
+          firstCubit=i;
+
+          float angle = mRotationAngleStatic.get0();
+          int nearestAngleInDegrees = computeNearestAngle(angle);
+          mRotationAngleStatic.set0(angle);
+          mRotationAngleFinal.set0(nearestAngleInDegrees);
+          mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-angle)*0.2f );
+          }
+        mCubits[i].resetRotationAngle();
+        }
+      }
+
+    if( firstCubit>=0 ) effectID = mCubits[firstCubit].setUpCallback(listener);
+
+    return effectID;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void removeRotationNow()
@@ -525,7 +515,16 @@ public abstract class RubikObject extends DistortedNode
          if( first )
            {
            first = false;
-           quat = mCubits[i].returnRotationQuat(mRotAxis);
+
+           float angle = mRotationAngleFinal.get0();
+           int nearestAngleInDegrees = computeNearestAngle(angle);
+           double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
+           float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
+           float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
+           float axisX = ROTATION_AXIS[mRotAxis].get0();
+           float axisY = ROTATION_AXIS[mRotAxis].get1();
+           float axisZ = ROTATION_AXIS[mRotAxis].get2();
+           quat = new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
            }
 
          mCubits[i].removeRotationNow(quat);
