commit a5972f924d3bcc2515039406be291f37289573b5
Author: leszek <leszek@koltunski.pl>
Date:   Sat Mar 30 23:46:57 2024 +0100

    common code from all activities to one BaseActivity

diff --git a/src/main/java/org/distorted/bandaged/BandagedActivity.java b/src/main/java/org/distorted/bandaged/BandagedActivity.java
index 82f968c9..a1ec4611 100644
--- a/src/main/java/org/distorted/bandaged/BandagedActivity.java
+++ b/src/main/java/org/distorted/bandaged/BandagedActivity.java
@@ -17,22 +17,17 @@ import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.dialogs.RubikDialogMessage;
 import org.distorted.external.RubikFiles;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.TwistyJson;
@@ -42,20 +37,16 @@ import org.distorted.playui.PlayActivity;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class BandagedActivity extends AppCompatActivity
+public class BandagedActivity extends BaseActivity
 {
     public static final float SPINNER_TEXT_SIZE = 0.03f;
     public static final float PADDING           = 0.010f;
-    public static final int FLAGS               = MainActivity.FLAGS;
     public static final float RATIO_SCROLL      = 0.30f;
 
     private static final int ACTIVITY_NUMBER    = 2;
-    private static final float RATIO_BAR        = MainActivity.RATIO_BAR;
     private static final float RATIO_BUT        = 0.07f;
     private static final int NUM_SCRAMBLES      = 300;
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
     private BandagedScreen mScreen;
     private boolean mRTL;
     private int mObjectOrdinal;
@@ -66,26 +57,20 @@ public class BandagedActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
 
-      Bundle b = getIntent().getExtras();
-      mObjectOrdinal = (b != null) ? b.getInt("obj") : 0;
-
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.bandaged);
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      Bundle b = getIntent().getExtras();
+      mObjectOrdinal = (b != null) ? b.getInt("obj") : 0;
       mDisplayMessageDialog = true;
 
       final Configuration config = getResources().getConfiguration();
       final int layoutDirection = config.getLayoutDirection();
       mRTL = layoutDirection==LAYOUT_DIRECTION_RTL;
 
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
       computeHeights();
@@ -125,56 +110,6 @@ public class BandagedActivity extends AppCompatActivity
       creator.setLayoutParams(paramsC);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
     @Override
@@ -353,20 +288,6 @@ public class BandagedActivity extends AppCompatActivity
       mScreen.iconCreationDone(this,bmp);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public int getObjectOrdinal()
diff --git a/src/main/java/org/distorted/config/ConfigActivity.java b/src/main/java/org/distorted/config/ConfigActivity.java
index eb0abf14..28b41a3e 100644
--- a/src/main/java/org/distorted/config/ConfigActivity.java
+++ b/src/main/java/org/distorted/config/ConfigActivity.java
@@ -10,21 +10,14 @@
 package org.distorted.config;
 
 import android.content.SharedPreferences;
-import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.dialogs.RubikDialogMessage;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
@@ -37,16 +30,11 @@ import java.io.InputStream;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class ConfigActivity extends AppCompatActivity
+public class ConfigActivity extends BaseActivity
 {
     private static final int ACTIVITY_NUMBER = 7;
-    private static final float RATIO_BAR  = MainActivity.RATIO_BAR;
-    public static final int FLAGS = MainActivity.FLAGS;
-
-    private static int mScreenWidth, mScreenHeight;
     private ConfigScreen mScreen;
     private ConfigScreenPane mPane;
-    private int mCurrentApiVersion;
     private int mObjectOrdinal;
     private boolean mSupportsAdjColors;
     private boolean mDisplayMessageDialog;
@@ -56,7 +44,6 @@ public class ConfigActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.config);
@@ -66,76 +53,10 @@ public class ConfigActivity extends AppCompatActivity
 
       mDisplayMessageDialog = true;
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
-      computeBarHeights();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this does not include possible insets
-
-    private void computeBarHeights()
-      {
-      int barHeight = (int)(mScreenHeight*RATIO_BAR);
-      LinearLayout layout = findViewById(R.id.lowerBar);
-      ViewGroup.LayoutParams params = layout.getLayoutParams();
-      params.height = barHeight;
-      layout.setLayoutParams(params);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
+      computeLowerBarHeight(RATIO_BAR);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -305,20 +226,6 @@ public class ConfigActivity extends AppCompatActivity
       mPane.resetUI(this);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public ObjectControl getControl()
diff --git a/src/main/java/org/distorted/helpers/BaseActivity.java b/src/main/java/org/distorted/helpers/BaseActivity.java
new file mode 100644
index 00000000..6745ff34
--- /dev/null
+++ b/src/main/java/org/distorted/helpers/BaseActivity.java
@@ -0,0 +1,161 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.helpers;
+
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import org.distorted.main.R;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class BaseActivity extends AppCompatActivity
+{
+    public static final float RATIO_BAR = 0.080f;
+    public static final int FLAGS =  View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                                   | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                                   | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                                   | View.SYSTEM_UI_FLAG_FULLSCREEN
+                                   | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+    private int mCurrentApiVersion;
+    protected int mScreenWidth, mScreenHeight;
+    protected int mHeightLowerBar, mHeightUpperBar;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    protected void onCreate(Bundle savedState)
+      {
+      setTheme(R.style.MaterialThemeNoActionBar);
+      super.onCreate(savedState);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    protected void getWindowWidth(Configuration conf)
+      {
+      int dpi = getResources().getDisplayMetrics().densityDpi;
+      float conv = ((float) dpi/DisplayMetrics.DENSITY_DEFAULT);
+
+      mScreenWidth = (int) (conf.screenWidthDp*conv + 0.5f);
+      mScreenHeight= (int) (conf.screenHeightDp*conv + 0.5f);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    protected void computeScreenDimensions()
+      {
+      DisplayMetrics displaymetrics = new DisplayMetrics();
+      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
+      mScreenWidth =displaymetrics.widthPixels;
+      mScreenHeight=displaymetrics.heightPixels;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    protected void computeLowerBarHeight(float ratio)
+      {
+      int barHeight = (int)(mScreenHeight*ratio);
+      mHeightLowerBar = barHeight;
+
+      LinearLayout layout = findViewById(R.id.lowerBar);
+      ViewGroup.LayoutParams params = layout.getLayoutParams();
+      params.height = barHeight;
+      layout.setLayoutParams(params);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// this does not include possible insets
+
+    protected void computeUpperBarHeight(float ratio)
+      {
+      int barHeight = (int)(mScreenHeight*ratio);
+      mHeightUpperBar = barHeight;
+
+      LinearLayout layout = findViewById(R.id.upperBar);
+      ViewGroup.LayoutParams params = layout.getLayoutParams();
+      params.height = barHeight;
+      layout.setLayoutParams(params);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    protected void hideNavigationBar()
+      {
+      mCurrentApiVersion = Build.VERSION.SDK_INT;
+
+      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
+        {
+        final View decorView = getWindow().getDecorView();
+
+        decorView.setSystemUiVisibility(FLAGS);
+
+        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
+          {
+          @Override
+          public void onSystemUiVisibilityChange(int visibility)
+            {
+            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
+              {
+              decorView.setSystemUiVisibility(FLAGS);
+              }
+            }
+          });
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// do not avoid cutouts
+
+    protected void cutoutHack()
+      {
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
+        {
+        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus)
+      {
+      super.onWindowFocusChanged(hasFocus);
+
+      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
+        {
+        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public int getScreenWidthInPixels()
+      {
+      return mScreenWidth;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public int getScreenHeightInPixels()
+      {
+      return mScreenHeight;
+      }
+
+}
diff --git a/src/main/java/org/distorted/info/InfoActivity.java b/src/main/java/org/distorted/info/InfoActivity.java
index 0401f3c1..ad7c1c62 100644
--- a/src/main/java/org/distorted/info/InfoActivity.java
+++ b/src/main/java/org/distorted/info/InfoActivity.java
@@ -11,17 +11,10 @@ package org.distorted.info;
 
 import java.io.InputStream;
 
-import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import androidx.appcompat.app.AppCompatActivity;
 
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
-import org.distorted.main.MainActivity;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.main.R;
@@ -32,104 +25,28 @@ import org.distorted.objects.RubikObjectList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class InfoActivity extends AppCompatActivity
+public class InfoActivity extends BaseActivity
 {
     private static final int ACTIVITY_NUMBER = 1;
-    private static final float RATIO_BAR  = MainActivity.RATIO_BAR;
-    public static final int FLAGS = MainActivity.FLAGS;
-
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
     private InfoScreen mScreen;
     private int mObjectOrdinal;
-    private int mHeightBar;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.info);
 
       Bundle b = getIntent().getExtras();
-
       if(b != null) mObjectOrdinal = b.getInt("obj");
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
-      computeBarHeights();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this does not include possible insets
-
-    private void computeBarHeights()
-      {
-      int barHeight = (int)(mScreenHeight*RATIO_BAR);
-      mHeightBar = barHeight;
-
-      LinearLayout layout = findViewById(R.id.lowerBar);
-      ViewGroup.LayoutParams params = layout.getLayoutParams();
-      params.height = barHeight;
-      layout.setLayoutParams(params);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
+      computeLowerBarHeight(RATIO_BAR);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -197,38 +114,6 @@ public class InfoActivity extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void changeObject(int ordinal)
-      {
-      mObjectOrdinal = ordinal;
-      RubikObject object = RubikObjectList.getObject(ordinal);
-      InfoSurfaceView view = findViewById(R.id.infoSurfaceView);
-      ObjectControl control = view.getObjectControl();
-      changeIfDifferent(object,ordinal,control);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getHeightBar()
-      {
-      return mHeightBar;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public ObjectControl getControl()
diff --git a/src/main/java/org/distorted/main/MainActivity.java b/src/main/java/org/distorted/main/MainActivity.java
index 447f0469..b507a096 100644
--- a/src/main/java/org/distorted/main/MainActivity.java
+++ b/src/main/java/org/distorted/main/MainActivity.java
@@ -16,18 +16,15 @@ import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import com.google.firebase.analytics.FirebaseAnalytics;
@@ -35,6 +32,7 @@ import com.google.firebase.inappmessaging.FirebaseInAppMessaging;
 
 import org.distorted.bandaged.BandagedActivity;
 import org.distorted.config.ConfigActivity;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.info.InfoActivity;
 import org.distorted.dialogs.RubikDialogAbout;
 import org.distorted.dialogs.RubikDialogCreators;
@@ -54,20 +52,11 @@ import org.distorted.tutorials.TutorialActivity;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class MainActivity extends AppCompatActivity implements RubikNetwork.Updatee, RubikDialogScores.ScoresInvoker
+public class MainActivity extends BaseActivity implements RubikNetwork.Updatee, RubikDialogScores.ScoresInvoker
 {
-    public static final float RATIO_BAR = 0.080f;
-    public static final int FLAGS =  View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                                   | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                                   | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
-                                   | View.SYSTEM_UI_FLAG_FULLSCREEN
-                                   | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-
     private boolean mJustStarted;
     private FirebaseAnalytics mFirebaseAnalytics;
-    private int mCurrentApiVersion;
     private String mOldVersion, mCurrVersion;
-    private int mScreenWidth, mScreenHeight;
     private TextView mBubbleUpdates;
     private int mNumUpdates;
     private int mCurrentObject;
@@ -79,15 +68,14 @@ public class MainActivity extends AppCompatActivity implements RubikNetwork.Upda
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       setContentView(R.layout.main);
-      hideNavigationBar();
 
       mCurrentObject = 0;
       mJustStarted = true;
       mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
 
+      hideNavigationBar();
       cutoutHack();
       computeHeights();
 
@@ -127,32 +115,6 @@ public class MainActivity extends AppCompatActivity implements RubikNetwork.Upda
       layoutBot.setLayoutParams(pL);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
@@ -182,41 +144,6 @@ public class MainActivity extends AppCompatActivity implements RubikNetwork.Upda
         }
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.P )
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void getWindowWidth(Configuration conf)
-      {
-      int dpi = getResources().getDisplayMetrics().densityDpi;
-      float conv = ((float) dpi/DisplayMetrics.DENSITY_DEFAULT);
-
-      mScreenWidth = (int) (conf.screenWidthDp*conv + 0.5f);
-      mScreenHeight= (int) (conf.screenHeightDp*conv + 0.5f);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if( mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus )
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
diff --git a/src/main/java/org/distorted/patternui/PatternActivity.java b/src/main/java/org/distorted/patternui/PatternActivity.java
index 71abf2ca..d90aa076 100644
--- a/src/main/java/org/distorted/patternui/PatternActivity.java
+++ b/src/main/java/org/distorted/patternui/PatternActivity.java
@@ -12,20 +12,16 @@ package org.distorted.patternui;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import org.distorted.dialogs.RubikDialogError;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedScreen;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
@@ -38,9 +34,9 @@ import java.io.InputStream;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class PatternActivity extends AppCompatActivity
+public class PatternActivity extends BaseActivity
 {
-    public static final float RATIO_BAR       = 0.100f;
+    public static final float RATIO_UPP       = 0.100f;
     public static final float PADDING         = 0.010f;
     public static final float SMALL_MARGIN    = 0.004f;
     public static final float BUTTON_TEXT_SIZE= 0.050f;
@@ -49,9 +45,6 @@ public class PatternActivity extends AppCompatActivity
     private static final int ACTIVITY_NUMBER = 5;
     private static final float RATIO_INSET= 0.09f;
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
-    private int mHeightUpperBar;
     private int mObjectOrdinal;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -59,67 +52,18 @@ public class PatternActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.pattern);
-      hideNavigationBar();
 
       Bundle b = getIntent().getExtras();
       mObjectOrdinal = b!=null ? b.getInt("obj") : 0;
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
+      hideNavigationBar();
       cutoutHack();
-      computeBarHeights();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this does not include possible insets
-
-    private void computeBarHeights()
-      {
-      int barHeight = (int)(mScreenHeight*RATIO_BAR);
-      mHeightUpperBar = barHeight;
-
-      LinearLayout layoutTop = findViewById(R.id.upperBar);
-      LinearLayout layoutBot = findViewById(R.id.lowerBar);
-
-      ViewGroup.LayoutParams paramsTop = layoutTop.getLayoutParams();
-      paramsTop.height = mHeightUpperBar;
-      layoutTop.setLayoutParams(paramsTop);
-      ViewGroup.LayoutParams paramsBot = layoutBot.getLayoutParams();
-      paramsBot.height = barHeight;
-      layoutBot.setLayoutParams(paramsBot);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(MainActivity.FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(MainActivity.FLAGS);
-              }
-            }
-          });
-        }
+      computeLowerBarHeight(RATIO_BAR);
+      computeUpperBarHeight(RATIO_UPP);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -138,31 +82,6 @@ public class PatternActivity extends AppCompatActivity
         ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams();
         paramsHid.height = (int)(insetHeight*RATIO_INSET);
         layoutHid.setLayoutParams(paramsHid);
-        mHeightUpperBar += paramsHid.height;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.P )
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if( mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus )
-        {
-        getWindow().getDecorView().setSystemUiVisibility(MainActivity.FLAGS);
         }
       }
 
@@ -263,20 +182,6 @@ public class PatternActivity extends AppCompatActivity
       return view.getObjectControl();
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public int getObjectOrdinal()
diff --git a/src/main/java/org/distorted/playui/PlayActivity.java b/src/main/java/org/distorted/playui/PlayActivity.java
index 6a381e61..c48979c0 100644
--- a/src/main/java/org/distorted/playui/PlayActivity.java
+++ b/src/main/java/org/distorted/playui/PlayActivity.java
@@ -14,27 +14,23 @@ import java.io.InputStream;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import com.google.firebase.analytics.FirebaseAnalytics;
 
 import org.distorted.dialogs.RubikDialogScores;
 import org.distorted.external.RubikScores;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.TwistyObject;
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.external.RubikFiles;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objects.RubikObject;
 import org.distorted.objects.RubikObjectList;
@@ -42,22 +38,17 @@ import org.distorted.os.OSInterface;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class PlayActivity extends AppCompatActivity implements RubikDialogScores.ScoresInvoker
+public class PlayActivity extends BaseActivity implements RubikDialogScores.ScoresInvoker
 {
-    public static final int FLAGS            = MainActivity.FLAGS;
     public static final float TITLE_TEXT_SIZE= 0.060f;
     private static final int ACTIVITY_NUMBER = 6;
-    private static final float RATIO_BAR     = MainActivity.RATIO_BAR;
     private static final float RATIO_INSET   = 0.09f;
 
     private static final String KEY_FREE = "movesController_free";
     private static final String KEY_SOLV = "movesController_solv";
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
     private String mObjectName;
     private int mNumScrambles;
-    private int mHeightUpperBar;
     private boolean mObjectLocal;
     private int mObjectOrdinal;
     private int mLevel;
@@ -70,7 +61,6 @@ public class PlayActivity extends AppCompatActivity implements RubikDialogScores
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.play);
@@ -99,59 +89,11 @@ public class PlayActivity extends AppCompatActivity implements RubikDialogScores
 
       mModeFree = (mLevel<0);
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
-      computeBarHeights();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this does not include possible insets
-
-    private void computeBarHeights()
-      {
-      int barHeight = (int)(mScreenHeight*RATIO_BAR);
-      mHeightUpperBar = barHeight;
-
-      LinearLayout layoutTop = findViewById(R.id.upperBar);
-      LinearLayout layoutBot = findViewById(R.id.lowerBar);
-
-      ViewGroup.LayoutParams paramsTop = layoutTop.getLayoutParams();
-      paramsTop.height = mHeightUpperBar;
-      layoutTop.setLayoutParams(paramsTop);
-      ViewGroup.LayoutParams paramsBot = layoutBot.getLayoutParams();
-      paramsBot.height = barHeight;
-      layoutBot.setLayoutParams(paramsBot);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
+      computeUpperBarHeight(RATIO_BAR);
+      computeLowerBarHeight(RATIO_BAR);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -170,31 +112,6 @@ public class PlayActivity extends AppCompatActivity implements RubikDialogScores
         ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams();
         paramsHid.height = (int)(insetHeight*RATIO_INSET);
         layoutHid.setLayoutParams(paramsHid);
-        mHeightUpperBar += paramsHid.height;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
         }
       }
 
@@ -369,20 +286,6 @@ public class PlayActivity extends AppCompatActivity implements RubikDialogScores
       return mFirebaseAnalytics;
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public int getNumScrambles()
diff --git a/src/main/java/org/distorted/purchase/PurchaseActivity.java b/src/main/java/org/distorted/purchase/PurchaseActivity.java
index 9320d0ea..6ac0f608 100644
--- a/src/main/java/org/distorted/purchase/PurchaseActivity.java
+++ b/src/main/java/org/distorted/purchase/PurchaseActivity.java
@@ -10,20 +10,16 @@
 package org.distorted.purchase;
 
 import android.content.SharedPreferences;
-import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.external.RubikScores;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
@@ -35,16 +31,13 @@ import java.io.InputStream;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class PurchaseActivity extends AppCompatActivity
+public class PurchaseActivity extends BaseActivity
 {
     private static final int ACTIVITY_NUMBER = 3;
     private static final float RATIO_UBAR = 0.14f;
     private static final float RATIO_LBAR = 0.10f;
     private static final float RATIO_VIEW = 0.50f;
-    public static final int FLAGS = MainActivity.FLAGS;
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
     private PurchaseScreen mScreen;
     private int mObjectOrdinal;
 
@@ -53,20 +46,14 @@ public class PurchaseActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.purchase);
 
       Bundle b = getIntent().getExtras();
-
       if(b != null) mObjectOrdinal = b.getInt("obj");
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
       setHeights();
@@ -103,56 +90,6 @@ public class PurchaseActivity extends AppCompatActivity
       setViewHeight(R.id.purchaseLayoutAll  , layHeight);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
     @Override
@@ -194,7 +131,6 @@ public class PurchaseActivity extends AppCompatActivity
       DistortedLibrary.onDestroy(ACTIVITY_NUMBER);
       }
 
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void savePreferences()
@@ -233,20 +169,6 @@ public class PurchaseActivity extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public ObjectControl getControl()
diff --git a/src/main/java/org/distorted/solverui/SolverActivity.java b/src/main/java/org/distorted/solverui/SolverActivity.java
index 3b469d13..172410c6 100644
--- a/src/main/java/org/distorted/solverui/SolverActivity.java
+++ b/src/main/java/org/distorted/solverui/SolverActivity.java
@@ -12,21 +12,17 @@ package org.distorted.solverui;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.preference.PreferenceManager;
 
 import org.distorted.dialogs.RubikDialogError;
 import org.distorted.dialogs.RubikDialogMessage;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedScreen;
-import org.distorted.main.MainActivity;
 import org.distorted.main.R;
 import org.distorted.objectlib.helpers.OperatingSystemInterface;
 import org.distorted.objectlib.main.InitAssets;
@@ -41,9 +37,9 @@ import java.io.InputStream;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class SolverActivity extends AppCompatActivity
+public class SolverActivity extends BaseActivity
 {
-    public static final float RATIO_BAR       = 0.100f;
+    public static final float RATIO_UPP       = 0.100f;
     public static final float PADDING         = 0.010f;
     public static final float SMALL_MARGIN    = 0.004f;
     public static final float BUTTON_TEXT_SIZE= 0.050f;
@@ -52,9 +48,6 @@ public class SolverActivity extends AppCompatActivity
     private static final int ACTIVITY_NUMBER = 4;
     private static final float RATIO_INSET= 0.09f;
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
-    private int mHeightUpperBar;
     private int mSolverOrdinal;
     private int mObjectOrdinal;
     private boolean mDisplayMessageDialog;
@@ -64,70 +57,20 @@ public class SolverActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
       setContentView(R.layout.solver);
-      hideNavigationBar();
 
       Bundle b = getIntent().getExtras();
       mObjectOrdinal = b!=null ? b.getInt("obj") : 0;
       mSolverOrdinal = ImplementedSolversList.getSolverOrdinal(mObjectOrdinal);
-
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
       mDisplayMessageDialog = true;
 
+      computeScreenDimensions();
+      hideNavigationBar();
       cutoutHack();
-      computeBarHeights();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this does not include possible insets
-
-    private void computeBarHeights()
-      {
-      int barHeight = (int)(mScreenHeight*RATIO_BAR);
-      mHeightUpperBar = barHeight;
-
-      LinearLayout layoutTop = findViewById(R.id.upperBar);
-      LinearLayout layoutBot = findViewById(R.id.lowerBar);
-
-      ViewGroup.LayoutParams paramsTop = layoutTop.getLayoutParams();
-      paramsTop.height = mHeightUpperBar;
-      layoutTop.setLayoutParams(paramsTop);
-      ViewGroup.LayoutParams paramsBot = layoutBot.getLayoutParams();
-      paramsBot.height = barHeight;
-      layoutBot.setLayoutParams(paramsBot);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(MainActivity.FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(MainActivity.FLAGS);
-              }
-            }
-          });
-        }
+      computeUpperBarHeight(RATIO_UPP);
+      computeLowerBarHeight(RATIO_BAR);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -146,31 +89,6 @@ public class SolverActivity extends AppCompatActivity
         ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams();
         paramsHid.height = (int)(insetHeight*RATIO_INSET);
         layoutHid.setLayoutParams(paramsHid);
-        mHeightUpperBar += paramsHid.height;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.P )
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if( mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus )
-        {
-        getWindow().getDecorView().setSystemUiVisibility(MainActivity.FLAGS);
         }
       }
 
@@ -296,20 +214,6 @@ public class SolverActivity extends AppCompatActivity
       return view.getObjectControl();
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public int getSolverOrdinal()
diff --git a/src/main/java/org/distorted/tutorials/TutorialActivity.java b/src/main/java/org/distorted/tutorials/TutorialActivity.java
index 8794b658..6740393f 100644
--- a/src/main/java/org/distorted/tutorials/TutorialActivity.java
+++ b/src/main/java/org/distorted/tutorials/TutorialActivity.java
@@ -11,21 +11,15 @@ package org.distorted.tutorials;
 
 import java.io.InputStream;
 
-import android.os.Build;
 import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.webkit.WebView;
 import android.widget.LinearLayout;
 
-import androidx.appcompat.app.AppCompatActivity;
-
 import org.distorted.dialogs.RubikDialogTutorial;
+import org.distorted.helpers.BaseActivity;
 import org.distorted.library.main.DistortedLibrary;
 
-import org.distorted.main.MainActivity;
 import org.distorted.objectlib.main.InitAssets;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.TwistyObject;
@@ -38,15 +32,12 @@ import org.distorted.os.OSInterface;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class TutorialActivity extends AppCompatActivity
+public class TutorialActivity extends BaseActivity
 {
     private static final String URL = "https://www.youtube.com/embed/";
     private static final int ACTIVITY_NUMBER = 0;
     public static final float BAR_RATIO = 0.17f;
-    public static final int FLAGS = MainActivity.FLAGS;
 
-    private static int mScreenWidth, mScreenHeight;
-    private int mCurrentApiVersion;
     private TutorialScreen mScreen;
     private int mObjectOrdinal;
     private TutorialWebView mWebView;
@@ -58,7 +49,6 @@ public class TutorialActivity extends AppCompatActivity
     @Override
     protected void onCreate(Bundle savedState)
       {
-      setTheme(R.style.MaterialThemeNoActionBar);
       super.onCreate(savedState);
       DistortedLibrary.onCreate(ACTIVITY_NUMBER);
 
@@ -84,11 +74,7 @@ public class TutorialActivity extends AppCompatActivity
         mIsFree = (obj!=null && obj.isFree());
         }
 
-      DisplayMetrics displaymetrics = new DisplayMetrics();
-      getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
-      mScreenWidth =displaymetrics.widthPixels;
-      mScreenHeight=displaymetrics.heightPixels;
-
+      computeScreenDimensions();
       hideNavigationBar();
       cutoutHack();
       showDialog();
@@ -108,32 +94,6 @@ public class TutorialActivity extends AppCompatActivity
         }
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void hideNavigationBar()
-      {
-      mCurrentApiVersion = Build.VERSION.SDK_INT;
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT)
-        {
-        final View decorView = getWindow().getDecorView();
-
-        decorView.setSystemUiVisibility(FLAGS);
-
-        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
-          {
-          @Override
-          public void onSystemUiVisibilityChange(int visibility)
-            {
-            if((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0)
-              {
-              decorView.setSystemUiVisibility(FLAGS);
-              }
-            }
-          });
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void loadTutorial(String url)
@@ -150,30 +110,6 @@ public class TutorialActivity extends AppCompatActivity
         }
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// do not avoid cutouts
-
-    private void cutoutHack()
-      {
-      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
-        {
-        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus)
-      {
-      super.onWindowFocusChanged(hasFocus);
-
-      if(mCurrentApiVersion >= Build.VERSION_CODES.KITKAT && hasFocus)
-        {
-        getWindow().getDecorView().setSystemUiVisibility(FLAGS);
-        }
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
     @Override
@@ -258,20 +194,6 @@ public class TutorialActivity extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenWidthInPixels()
-      {
-      return mScreenWidth;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public int getScreenHeightInPixels()
-      {
-      return mScreenHeight;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public boolean getIsFree()
