commit 598de3ee9c5307a9fa3010380c90ebc2ba71bf6a
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jul 15 17:08:58 2021 +0200

    add possible scrolling to the 'object' popup in case the grid of objects does not fit on the screen.

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/main/RubikActivity.java b/src/main/java/org/distorted/main/RubikActivity.java
index 0855dc52..d852040d 100644
--- a/src/main/java/org/distorted/main/RubikActivity.java
+++ b/src/main/java/org/distorted/main/RubikActivity.java
@@ -86,11 +86,15 @@ public class RubikActivity extends TwistyActivity
     public static final int FLAGS2=  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 
+    private static final float RATIO_BAR  = 0.10f;
+    private static final float RATIO_INSET= 0.08f;
+
     private boolean mJustStarted;
     private FirebaseAnalytics mFirebaseAnalytics;
     private static int mScreenWidth, mScreenHeight;
     private boolean mPolicyAccepted, mIsChinese;
     private int mCurrentApiVersion;
+    private int mHeightUpperBar, mHeightLowerBar;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -116,9 +120,21 @@ public class RubikActivity extends TwistyActivity
 
       hideNavigationBar();
       cutoutHack();
+      computeBarHeights();
       // askForPermissions();
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// this does not include possible insets
+
+    private void computeBarHeights()
+      {
+      float height = getScreenHeightInPixels();
+      int barHeight = (int)(height*RATIO_BAR);
+      mHeightLowerBar = barHeight;
+      mHeightUpperBar = barHeight;
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void hideNavigationBar()
@@ -159,21 +175,21 @@ public class RubikActivity extends TwistyActivity
 
         LinearLayout layoutHid = findViewById(R.id.hiddenBar);
         ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams();
-        paramsHid.height = (int)(0.8f*insetHeight);
+        paramsHid.height = (int)(insetHeight*RATIO_INSET);
         layoutHid.setLayoutParams(paramsHid);
+        mHeightUpperBar += paramsHid.height;
         }
 
-      final float RATIO = 0.10f;
       float height = getScreenHeightInPixels();
 
       LinearLayout layoutTop = findViewById(R.id.upperBar);
       LinearLayout layoutBot = findViewById(R.id.lowerBar);
 
       ViewGroup.LayoutParams paramsTop = layoutTop.getLayoutParams();
-      paramsTop.height = (int)(height*RATIO);
+      paramsTop.height = (int)(height*RATIO_BAR);
       layoutTop.setLayoutParams(paramsTop);
       ViewGroup.LayoutParams paramsBot = layoutBot.getLayoutParams();
-      paramsBot.height = (int)(height*RATIO);
+      paramsBot.height = (int)(height*RATIO_BAR);
       layoutBot.setLayoutParams(paramsBot);
       }
 
@@ -380,6 +396,20 @@ public class RubikActivity extends TwistyActivity
       return mFirebaseAnalytics;
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public int getHeightUpperBar()
+      {
+      return mHeightUpperBar;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public int getHeightLowerBar()
+      {
+      return mHeightLowerBar;
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public TwistyObject getObject()
diff --git a/src/main/java/org/distorted/screens/RubikScreenPlay.java b/src/main/java/org/distorted/screens/RubikScreenPlay.java
index 07eddc0a..d26a0558 100644
--- a/src/main/java/org/distorted/screens/RubikScreenPlay.java
+++ b/src/main/java/org/distorted/screens/RubikScreenPlay.java
@@ -32,6 +32,7 @@ import android.widget.GridLayout;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
+import android.widget.ScrollView;
 
 import org.distorted.control.RubikControl;
 import org.distorted.dialogs.RubikDialogAbout;
@@ -72,7 +73,7 @@ public class RubikScreenPlay extends RubikScreenBase
   private int mObjectSize, mMenuLayoutWidth, mMenuLayoutHeight, mPlayLayoutWidth;
   private int mLevelValue;
   private float mButtonSize, mMenuItemSize, mMenuTextSize;
-  private int mColCount, mRowCount;
+  private int mColCount, mRowCount, mMaxRowCount;
   private LinearLayout mPlayLayout;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -87,6 +88,7 @@ public class RubikScreenPlay extends RubikScreenBase
   void enterScreen(final RubikActivity act)
     {
     float width = act.getScreenWidthInPixels();
+    float height= act.getScreenHeightInPixels();
 
     mMenuTextSize = width*RubikActivity.MENU_MED_TEXT_SIZE;
     mButtonSize   = width*RubikActivity.BUTTON_TEXT_SIZE;
@@ -99,7 +101,7 @@ public class RubikScreenPlay extends RubikScreenBase
     LinearLayout layoutTop = act.findViewById(R.id.upperBar);
     layoutTop.removeAllViews();
 
-    setupObjectWindow(act,width);
+    setupObjectWindow(act,width,height);
     setupObjectButton(act,width);
     layoutTop.addView(mObjButton);
 
@@ -128,24 +130,15 @@ public class RubikScreenPlay extends RubikScreenBase
       @Override
       public void onClick(View view)
         {
-        if(act.getPreRender().isUINotBlocked())
+        if( mObjectPopup!=null && act.getPreRender().isUINotBlocked())
           {
-          if( mObjectPopup==null )
-            {
-            // I completely don't understand it, but Firebase says occasionally mObjectPopup is null here. Recreate.
-            float width = act.getScreenWidthInPixels();
-            setupObjectWindow(act,width);
-            }
-
-          mObjectPopup.setFocusable(false);
-          mObjectPopup.update();
+          int rowCount = Math.min(mMaxRowCount,mRowCount);
 
           View popupView = mObjectPopup.getContentView();
           popupView.setSystemUiVisibility(RubikActivity.FLAGS);
 
           mObjectPopup.showAsDropDown(view, margin, margin);
-          mObjectPopup.update(view, mObjectSize*mColCount, mObjectSize*mRowCount);
-
+          mObjectPopup.update(view, mObjectSize*mColCount, mObjectSize*rowCount);
           mObjectPopup.setFocusable(true);
           mObjectPopup.update();
           }
@@ -165,18 +158,8 @@ public class RubikScreenPlay extends RubikScreenBase
       @Override
       public void onClick(View view)
         {
-        if(act.getPreRender().isUINotBlocked())
+        if( mPlayPopup!=null && act.getPreRender().isUINotBlocked())
           {
-          if( mPlayPopup==null )
-            {
-            // I completely don't understand it, but Firebase says occasionally mPlayPopup is null here. Recreate.
-            float width = act.getScreenWidthInPixels();
-            setupPlayWindow(act,width);
-            }
-
-          mPlayPopup.setFocusable(false);
-          mPlayPopup.update();
-
           View popupView = mPlayPopup.getContentView();
           popupView.setSystemUiVisibility(RubikActivity.FLAGS);
 
@@ -206,25 +189,14 @@ public class RubikScreenPlay extends RubikScreenBase
       @Override
       public void onClick(View view)
         {
-        if(act.getPreRender().isUINotBlocked())
+        if( mMenuPopup!=null && act.getPreRender().isUINotBlocked())
           {
-          if( mMenuPopup==null )
-            {
-            // I completely don't understand it, but Firebase says occasionally mMenuPopup is null here. Recreate.
-            float width = act.getScreenWidthInPixels();
-            setupMenuWindow(act,width);
-            }
-
-          mMenuPopup.setFocusable(false);
-          mMenuPopup.update();
-
           View popupView = mMenuPopup.getContentView();
           popupView.setSystemUiVisibility(RubikActivity.FLAGS);
 
           mMenuPopup.showAsDropDown(view, (int)(-width/12), margin, Gravity.CENTER);
           mMenuPopup.update(view, mMenuLayoutWidth, mMenuLayoutHeight);
           mMenuPopup.setFocusable(true);
-          mMenuPopup.update();
           }
         }
       });
@@ -232,11 +204,30 @@ public class RubikScreenPlay extends RubikScreenBase
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void setupObjectWindow(final RubikActivity act, final float width)
+  private void setupObjectWindow(final RubikActivity act, final float width, final float height)
     {
-    LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    final View layout = layoutInflater.inflate(R.layout.popup_objects, null);
-    GridLayout objectGrid = layout.findViewById(R.id.objectGrid);
+    int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube2,R.drawable.ui_medium_cube2, R.drawable.ui_big_cube2, R.drawable.ui_huge_cube2);
+
+    BitmapDrawable bd = (BitmapDrawable) act.getResources().getDrawable(icon);
+    int cubeWidth = bd.getIntrinsicWidth();
+    int margin = (int)(width*RubikActivity.LARGE_MARGIN);
+    mObjectSize = (int)(cubeWidth + 2*margin + 0.5f);
+    int upperBarHeight  = act.getHeightUpperBar();
+    mMaxRowCount = (int)((height-upperBarHeight)/mObjectSize);
+    GridLayout objectGrid = new GridLayout(act);
+    mObjectPopup = new PopupWindow(act);
+    mObjectPopup.setFocusable(true);
+
+    if( mMaxRowCount<mRowCount )
+      {
+      ScrollView scrollView = new ScrollView(act);
+      scrollView.addView(objectGrid);
+      mObjectPopup.setContentView(scrollView);
+      }
+    else
+      {
+      mObjectPopup.setContentView(objectGrid);
+      }
 
     int[] indices = ObjectList.getIndices();
 
@@ -258,16 +249,6 @@ public class RubikScreenPlay extends RubikScreenBase
       colSpecs[col] = GridLayout.spec(col);
       }
 
-    mObjectPopup = new PopupWindow(act);
-    mObjectPopup.setContentView(layout);
-    mObjectPopup.setFocusable(true);
-    int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube2,R.drawable.ui_medium_cube2, R.drawable.ui_big_cube2, R.drawable.ui_huge_cube2);
-
-    BitmapDrawable bd = (BitmapDrawable) act.getResources().getDrawable(icon);
-    int cubeWidth = bd.getIntrinsicWidth();
-    int margin = (int)(width*RubikActivity.LARGE_MARGIN);
-    mObjectSize = (int)(cubeWidth + 2*margin + 0.5f);
-
     for(int object=0; object< ObjectList.NUM_OBJECTS; object++)
       {
       final ObjectList list = ObjectList.getObject(object);
@@ -574,7 +555,7 @@ public class RubikScreenPlay extends RubikScreenBase
 
           if(pre.isUINotBlocked())
             {
-            mPlayPopup.dismiss();
+            if( mPlayPopup!=null ) mPlayPopup.dismiss();
             mLevelValue = level;
             pre.scrambleObject(scrambles);
             }
diff --git a/src/main/res/layout/popup_objects.xml b/src/main/res/layout/popup_objects.xml
deleted file mode 100644
index 3762dd64..00000000
--- a/src/main/res/layout/popup_objects.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-   android:id="@+id/objectGrid"
-   android:layout_width="wrap_content"
-   android:layout_height="wrap_content">
-</GridLayout>
\ No newline at end of file
