commit 46405bb4ab07361d4a69881b8cf7a77ec297c39c
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Sep 23 22:29:31 2020 +0100

    Add lock button.

diff --git a/src/main/java/org/distorted/main/RubikActivity.java b/src/main/java/org/distorted/main/RubikActivity.java
index b3916b51..5f448dd9 100644
--- a/src/main/java/org/distorted/main/RubikActivity.java
+++ b/src/main/java/org/distorted/main/RubikActivity.java
@@ -81,6 +81,7 @@ public class RubikActivity extends AppCompatActivity
     private static int mScreenWidth, mScreenHeight;
     private boolean mPolicyAccepted, mIsChinese;
     private int mCurrentApiVersion;
+    private boolean mIsLocked;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -100,6 +101,7 @@ public class RubikActivity extends AppCompatActivity
       mScreenHeight=displaymetrics.heightPixels;
 
       mIsChinese = localeIsChinese();
+      mIsLocked = false;
 
       hideNavigationBar();
       huaweiHack();
@@ -489,4 +491,32 @@ public class RubikActivity extends AppCompatActivity
       RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
       return view.isVertical();
       }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void toggleLock()
+      {
+      mIsLocked = !mIsLocked;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public boolean isLocked()
+      {
+      RubikState state = RubikState.getCurrentState();
+
+      if( state==RubikState.PLAY || state==RubikState.READ || state==RubikState.SOLV )
+        {
+        return mIsLocked;
+        }
+
+      return false;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public boolean retLocked()
+      {
+      return mIsLocked;
+      }
 }
diff --git a/src/main/java/org/distorted/main/RubikSurfaceView.java b/src/main/java/org/distorted/main/RubikSurfaceView.java
index 449b942b..e9966d94 100644
--- a/src/main/java/org/distorted/main/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/main/RubikSurfaceView.java
@@ -338,7 +338,9 @@ public class RubikSurfaceView extends GLSurfaceView
           }
         else
           {
-          mDragging           = true;
+          final RubikActivity act = (RubikActivity)getContext();
+
+          mDragging           = !act.isLocked();
           mBeginningRotation  = false;
           mContinuingRotation = false;
           }
diff --git a/src/main/java/org/distorted/states/RubikStatePlay.java b/src/main/java/org/distorted/states/RubikStatePlay.java
index ecaeabca..7a03cf93 100644
--- a/src/main/java/org/distorted/states/RubikStatePlay.java
+++ b/src/main/java/org/distorted/states/RubikStatePlay.java
@@ -56,7 +56,7 @@ public class RubikStatePlay extends RubikStateAbstract implements RubikPreRender
   private static int[] BUTTON_LABELS = { R.string.scores, R.string.patterns, R.string.solver, R.string.about };
   private static final int NUM_BUTTONS = BUTTON_LABELS.length;
 
-  private ImageButton mObjButton, mMenuButton, mPrevButton, mSolveButton;
+  private ImageButton mObjButton, mMenuButton, mPrevButton, mSolveButton, mLockButton;
   private Button mPlayButton;
   private PopupWindow mObjectPopup, mMenuPopup, mPlayPopup;
   private int mObject = DEF_OBJECT;
@@ -137,6 +137,8 @@ public class RubikStatePlay extends RubikStateAbstract implements RubikPreRender
 
     setupPrevButton(act,width);
     layoutLeft.addView(mPrevButton);
+    setupLockButton(act,width);
+    layoutMid.addView(mLockButton);
     setupSolveButton(act,width);
     layoutRight.addView(mSolveButton);
 
@@ -298,6 +300,34 @@ public class RubikStatePlay extends RubikStateAbstract implements RubikPreRender
       });
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupLockButton(final RubikActivity act, final float width)
+    {
+    int padding  = (int)(width*RubikActivity.PADDING);
+    int margin   = (int)(width*RubikActivity.MARGIN);
+
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
+    params.topMargin    = margin;
+    params.bottomMargin = margin;
+    params.leftMargin   = margin;
+    params.rightMargin  = margin;
+
+    mLockButton = new ImageButton(act);
+    mLockButton.setLayoutParams(params);
+    mLockButton.setPadding(padding,0,padding,0);
+    mLockButton.setImageResource(getLockIcon(act));
+
+    mLockButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        toggleLock(act);
+        }
+      });
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void setupPrevButton(final RubikActivity act, final float width)
@@ -535,6 +565,28 @@ public class RubikStatePlay extends RubikStateAbstract implements RubikPreRender
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void toggleLock(RubikActivity act)
+    {
+    act.toggleLock();
+    mLockButton.setImageResource(getLockIcon(act));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getLockIcon(RubikActivity act)
+    {
+    if( act.retLocked() )
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_locked,R.drawable.ui_medium_locked, R.drawable.ui_big_locked, R.drawable.ui_huge_locked);
+      }
+    else
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_unlocked,R.drawable.ui_medium_unlocked, R.drawable.ui_big_unlocked, R.drawable.ui_huge_unlocked);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
diff --git a/src/main/java/org/distorted/states/RubikStateReady.java b/src/main/java/org/distorted/states/RubikStateReady.java
index d586a22c..2cd38f20 100644
--- a/src/main/java/org/distorted/states/RubikStateReady.java
+++ b/src/main/java/org/distorted/states/RubikStateReady.java
@@ -23,7 +23,6 @@ import android.content.SharedPreferences;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -35,7 +34,7 @@ import org.distorted.main.RubikActivity;
 
 public class RubikStateReady extends RubikStateAbstract
   {
-  private ImageButton mPrevButton;
+  private ImageButton mPrevButton, mLockButton, mBackButton;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -49,7 +48,6 @@ public class RubikStateReady extends RubikStateAbstract
   void enterState(final RubikActivity act)
     {
     float width = act.getScreenWidthInPixels();
-    float buttonSize = width*RubikActivity.BUTTON_TEXT_SIZE;
     float titleSize  = width*RubikActivity.TITLE_TEXT_SIZE;
 
     LayoutInflater inflater = act.getLayoutInflater();
@@ -75,25 +73,38 @@ public class RubikStateReady extends RubikStateAbstract
     LinearLayout layoutRight = new LinearLayout(act);
     layoutRight.setLayoutParams(paramsL);
 
-    setupPrevMoveButtom(act,width);
+    setupPrevButtom(act,width);
     layoutLeft.addView(mPrevButton);
+    setupLockButton(act,width);
+    layoutMid.addView(mLockButton);
+    setupBackButton(act,width);
+    layoutRight.addView(mBackButton);
 
+    layoutBot.addView(layoutLeft);
+    layoutBot.addView(layoutMid);
+    layoutBot.addView(layoutRight);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupBackButton(final RubikActivity act, float width)
+    {
     int padding = (int)(width*RubikActivity.PADDING);
     int margin  = (int)(width*RubikActivity.MARGIN);
+    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_back,R.drawable.ui_medium_back, R.drawable.ui_big_back, R.drawable.ui_huge_back);
+
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
     params.topMargin    = margin;
     params.bottomMargin = margin;
     params.leftMargin   = margin;
     params.rightMargin  = margin;
 
-    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_back,R.drawable.ui_medium_back, R.drawable.ui_big_back, R.drawable.ui_huge_back);
-
-    ImageButton back = new ImageButton(act);
-    back.setLayoutParams(params);
-    back.setPadding(padding,0,padding,0);
-    back.setImageResource(icon);
+    mBackButton = new ImageButton(act);
+    mBackButton.setLayoutParams(params);
+    mBackButton.setPadding(padding,0,padding,0);
+    mBackButton.setImageResource(icon);
 
-    back.setOnClickListener( new View.OnClickListener()
+    mBackButton.setOnClickListener( new View.OnClickListener()
       {
       @Override
       public void onClick(View v)
@@ -101,17 +112,39 @@ public class RubikStateReady extends RubikStateAbstract
         RubikState.goBack(act);
         }
       });
+    }
 
-    layoutRight.addView(back);
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    layoutBot.addView(layoutLeft);
-    layoutBot.addView(layoutMid);
-    layoutBot.addView(layoutRight);
+  private void setupLockButton(final RubikActivity act, final float width)
+    {
+    int padding  = (int)(width*RubikActivity.PADDING);
+    int margin   = (int)(width*RubikActivity.MARGIN);
+
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
+    params.topMargin    = margin;
+    params.bottomMargin = margin;
+    params.leftMargin   = margin;
+    params.rightMargin  = margin;
+
+    mLockButton = new ImageButton(act);
+    mLockButton.setLayoutParams(params);
+    mLockButton.setPadding(padding,0,padding,0);
+    mLockButton.setImageResource(getLockIcon(act));
+
+    mLockButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        toggleLock(act);
+        }
+      });
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void setupPrevMoveButtom(final RubikActivity act, float width)
+  private void setupPrevButtom(final RubikActivity act, float width)
     {
     int padding = (int)(width*RubikActivity.PADDING);
     int margin  = (int)(width*RubikActivity.MARGIN);
@@ -138,6 +171,28 @@ public class RubikStateReady extends RubikStateAbstract
       });
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void toggleLock(RubikActivity act)
+    {
+    act.toggleLock();
+    mLockButton.setImageResource(getLockIcon(act));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getLockIcon(RubikActivity act)
+    {
+    if( act.retLocked() )
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_locked,R.drawable.ui_medium_locked, R.drawable.ui_big_locked, R.drawable.ui_huge_locked);
+      }
+    else
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_unlocked,R.drawable.ui_medium_unlocked, R.drawable.ui_big_unlocked, R.drawable.ui_huge_unlocked);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void savePreferences(SharedPreferences.Editor editor)
diff --git a/src/main/java/org/distorted/states/RubikStateSolving.java b/src/main/java/org/distorted/states/RubikStateSolving.java
index c67293cb..d5cd6f28 100644
--- a/src/main/java/org/distorted/states/RubikStateSolving.java
+++ b/src/main/java/org/distorted/states/RubikStateSolving.java
@@ -23,7 +23,6 @@ import android.content.SharedPreferences;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -50,7 +49,7 @@ public class RubikStateSolving extends RubikStateAbstract implements RubikPreRen
   private long mStartTime;
   private boolean mRunning;
   private RubikScores mScores;
-  private ImageButton mPrevButton;
+  private ImageButton mPrevButton, mLockButton, mBackButton;
   private boolean mCanPrevMove;
   private ArrayList<Move> mMoves;
   private long mElapsed;
@@ -86,7 +85,6 @@ public class RubikStateSolving extends RubikStateAbstract implements RubikPreRen
   void enterState(final RubikActivity act)
     {
     float width = act.getScreenWidthInPixels();
-    float buttonSize = width*RubikActivity.BUTTON_TEXT_SIZE;
     float titleSize  = width*RubikActivity.TITLE_TEXT_SIZE;
 
     mCanPrevMove = true;
@@ -120,25 +118,39 @@ public class RubikStateSolving extends RubikStateAbstract implements RubikPreRen
     LinearLayout layoutRight = new LinearLayout(act);
     layoutRight.setLayoutParams(paramsL);
 
-    setupPrevMoveButtom(act,width);
+    setupPrevButtom(act,width);
     layoutLeft.addView(mPrevButton);
+    setupLockButton(act,width);
+    layoutMid.addView(mLockButton);
+    setupBackButtom(act,width);
+    layoutRight.addView(mBackButton);
 
+    layoutBot.addView(layoutLeft);
+    layoutBot.addView(layoutMid);
+    layoutBot.addView(layoutRight);
+    }
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setupBackButtom(final RubikActivity act, float width)
+    {
     int padding = (int)(width*RubikActivity.PADDING);
     int margin  = (int)(width*RubikActivity.MARGIN);
+    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_back,R.drawable.ui_medium_back, R.drawable.ui_big_back, R.drawable.ui_huge_back);
+
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
     params.topMargin    = margin;
     params.bottomMargin = margin;
     params.leftMargin   = margin;
     params.rightMargin  = margin;
 
-    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_back,R.drawable.ui_medium_back, R.drawable.ui_big_back, R.drawable.ui_huge_back);
+    mBackButton = new ImageButton(act);
+    mBackButton.setLayoutParams(params);
+    mBackButton.setPadding(padding,0,padding,0);
+    mBackButton.setImageResource(icon);
 
-    ImageButton back = new ImageButton(act);
-    back.setLayoutParams(params);
-    back.setPadding(padding,0,padding,0);
-    back.setImageResource(icon);
-
-    back.setOnClickListener( new View.OnClickListener()
+    mBackButton.setOnClickListener( new View.OnClickListener()
       {
       @Override
       public void onClick(View v)
@@ -146,17 +158,39 @@ public class RubikStateSolving extends RubikStateAbstract implements RubikPreRen
         RubikState.goBack(act);
         }
       });
+    }
 
-    layoutRight.addView(back);
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    layoutBot.addView(layoutLeft);
-    layoutBot.addView(layoutMid);
-    layoutBot.addView(layoutRight);
+  private void setupLockButton(final RubikActivity act, final float width)
+    {
+    int padding  = (int)(width*RubikActivity.PADDING);
+    int margin   = (int)(width*RubikActivity.MARGIN);
+
+    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
+    params.topMargin    = margin;
+    params.bottomMargin = margin;
+    params.leftMargin   = margin;
+    params.rightMargin  = margin;
+
+    mLockButton = new ImageButton(act);
+    mLockButton.setLayoutParams(params);
+    mLockButton.setPadding(padding,0,padding,0);
+    mLockButton.setImageResource(getLockIcon(act));
+
+    mLockButton.setOnClickListener( new View.OnClickListener()
+      {
+      @Override
+      public void onClick(View v)
+        {
+        toggleLock(act);
+        }
+      });
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void setupPrevMoveButtom(final RubikActivity act, float width)
+  private void setupPrevButtom(final RubikActivity act, float width)
     {
     int padding = (int)(width*RubikActivity.PADDING);
     int margin  = (int)(width*RubikActivity.MARGIN);
@@ -215,6 +249,28 @@ public class RubikStateSolving extends RubikStateAbstract implements RubikPreRen
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void toggleLock(RubikActivity act)
+    {
+    act.toggleLock();
+    mLockButton.setImageResource(getLockIcon(act));
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getLockIcon(RubikActivity act)
+    {
+    if( act.retLocked() )
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_locked,R.drawable.ui_medium_locked, R.drawable.ui_big_locked, R.drawable.ui_huge_locked);
+      }
+    else
+      {
+      return RubikActivity.getDrawable(R.drawable.ui_small_unlocked,R.drawable.ui_medium_unlocked, R.drawable.ui_big_unlocked, R.drawable.ui_huge_unlocked);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void addMove(int axis, int row, int angle)
diff --git a/src/main/res/drawable-nodpi/ui_big_locked.png b/src/main/res/drawable-nodpi/ui_big_locked.png
new file mode 100644
index 00000000..ca5140f2
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_big_locked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_big_unlocked.png b/src/main/res/drawable-nodpi/ui_big_unlocked.png
new file mode 100644
index 00000000..000232b4
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_big_unlocked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_huge_locked.png b/src/main/res/drawable-nodpi/ui_huge_locked.png
new file mode 100644
index 00000000..676db820
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_huge_locked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_huge_unlocked.png b/src/main/res/drawable-nodpi/ui_huge_unlocked.png
new file mode 100644
index 00000000..59efc275
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_huge_unlocked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_medium_locked.png b/src/main/res/drawable-nodpi/ui_medium_locked.png
new file mode 100644
index 00000000..243525e9
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_medium_locked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_medium_unlocked.png b/src/main/res/drawable-nodpi/ui_medium_unlocked.png
new file mode 100644
index 00000000..fc105f75
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_medium_unlocked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_small_locked.png b/src/main/res/drawable-nodpi/ui_small_locked.png
new file mode 100644
index 00000000..87cc4574
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_small_locked.png differ
diff --git a/src/main/res/drawable-nodpi/ui_small_unlocked.png b/src/main/res/drawable-nodpi/ui_small_unlocked.png
new file mode 100644
index 00000000..668786f8
Binary files /dev/null and b/src/main/res/drawable-nodpi/ui_small_unlocked.png differ
