commit c020555eb328e2772e4fa58edc285f0296b5f126
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Jul 12 15:28:14 2022 +0200

    Do not crash when something's wrong with the JSON file - handle this gracefully, do not change the object then, and report this to Firebase.

diff --git a/src/main/java/org/distorted/bandaged/BandagedCreatorActivity.java b/src/main/java/org/distorted/bandaged/BandagedCreatorActivity.java
index 4274ef45..59d4dac0 100644
--- a/src/main/java/org/distorted/bandaged/BandagedCreatorActivity.java
+++ b/src/main/java/org/distorted/bandaged/BandagedCreatorActivity.java
@@ -292,7 +292,7 @@ public class BandagedCreatorActivity extends AppCompatActivity
         SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
         SharedPreferences.Editor editor = preferences.edit();
         TwistyObject object = new TwistyJson( jsonStream, meshState, iconMode, null, null, 1.0f, null);
-        object.removePreferences(editor);
+        if( !object.getError() ) object.removePreferences(editor);
         editor.apply();
         }
 
diff --git a/src/main/java/org/distorted/bandaged/BandagedPlayLibInterface.java b/src/main/java/org/distorted/bandaged/BandagedPlayLibInterface.java
index 93f68fc6..57837d1e 100644
--- a/src/main/java/org/distorted/bandaged/BandagedPlayLibInterface.java
+++ b/src/main/java/org/distorted/bandaged/BandagedPlayLibInterface.java
@@ -50,6 +50,7 @@ public class BandagedPlayLibInterface implements ObjectLibInterface
   public void onObjectCreated(long time) { }
   public void onReplaceModeDown(int cubit, int face) { }
   public void onReplaceModeUp() { }
+  public void reportJSONError(String error, int ordinal) { }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/config/ConfigObjectLibInterface.java b/src/main/java/org/distorted/config/ConfigObjectLibInterface.java
index adf8f2ad..5d77626c 100644
--- a/src/main/java/org/distorted/config/ConfigObjectLibInterface.java
+++ b/src/main/java/org/distorted/config/ConfigObjectLibInterface.java
@@ -39,6 +39,7 @@ public class ConfigObjectLibInterface implements ObjectLibInterface
   public void onReplaceModeUp() { }
   public void onFinishRotation(int axis, int row, int angle) { }
   public void failedToDrag() { }
+  public void reportJSONError(String error, int ordinal) { }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/config/ConfigScreenPane.java b/src/main/java/org/distorted/config/ConfigScreenPane.java
index 91d4f576..20ed152d 100644
--- a/src/main/java/org/distorted/config/ConfigScreenPane.java
+++ b/src/main/java/org/distorted/config/ConfigScreenPane.java
@@ -78,11 +78,25 @@ public class ConfigScreenPane
 
       mObjectOrdinal = objectOrdinal;
       JsonReader reader = JsonReader.getInstance();
-      reader.parseJsonFileMetadata(stream);
+      String name,author;
+      int year, difficulty;
+
+      try
+        {
+        reader.parseJsonFileMetadata(stream);
+        name       = reader.getObjectName();
+        author     = reader.getInventor();
+        year       = reader.getYearOfInvention();
+        difficulty = reader.getComplexity();
+        }
+      catch(Exception ex)
+        {
+        name = "?";
+        author = "?";
+        year = 0;
+        difficulty = 0;
+        }
 
-      String name = reader.getObjectName();
-      String author = reader.getInventor();
-      int year = reader.getYearOfInvention();
       String both = year>0 ? author+" "+year : author;
 
       LinearLayout layout = act.findViewById(R.id.configLayout);
@@ -91,8 +105,6 @@ public class ConfigScreenPane
       view = layout.findViewById(R.id.configDetailsAuthor2);
       view.setText(both);
 
-      int difficulty = reader.getComplexity();
-
       if( difficulty<0          ) difficulty=0;
       if( difficulty>NUM_IMAGES ) difficulty=NUM_IMAGES;
 
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogTutorialView.java b/src/main/java/org/distorted/dialogs/RubikDialogTutorialView.java
index b3c1d95c..780999d0 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogTutorialView.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogTutorialView.java
@@ -77,9 +77,16 @@ public class RubikDialogTutorialView extends FrameLayout
 
     if( jsonStream!=null )
       {
-      JsonReader reader = JsonReader.getInstance();
-      reader.parseJsonTutorial(jsonStream);
-      tutorials = reader.getTutorials();
+      try
+        {
+        JsonReader reader = JsonReader.getInstance();
+        reader.parseJsonTutorial(jsonStream);
+        tutorials = reader.getTutorials();
+        }
+      catch(Exception ex)
+        {
+        tutorials = null;
+        }
       }
 
     if( tutorials!=null )
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
index 80e56864..44178d85 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogUpdateView.java
@@ -201,10 +201,17 @@ public class RubikDialogUpdateView implements RubikNetwork.Downloadee
 
         if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Saving JSON "+name+" to a file "+oSuccess);
 
-        JsonReader reader = JsonReader.getInstance();
-        mInfo.mNumScrambles = reader.readNumScrambles(act,name);
-
-        if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Read from JSON numScrambles="+mInfo.mNumScrambles);
+        try
+          {
+          JsonReader reader = JsonReader.getInstance();
+          mInfo.mNumScrambles = reader.readNumScrambles(act,name);
+          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Read from JSON numScrambles="+mInfo.mNumScrambles);
+          }
+        catch(Exception ex)
+          {
+          mInfo.mNumScrambles = 25;
+          if( SHOW_DOWNLOADED_DEBUG ) android.util.Log.e("D", "Error reading numScrambles");
+          }
         }
 
       if( mInfo.mExtrasStream!=null )
diff --git a/src/main/java/org/distorted/main/RubikObjectLibInterface.java b/src/main/java/org/distorted/main/RubikObjectLibInterface.java
index db78e448..ab548373 100644
--- a/src/main/java/org/distorted/main/RubikObjectLibInterface.java
+++ b/src/main/java/org/distorted/main/RubikObjectLibInterface.java
@@ -436,6 +436,27 @@ public class RubikObjectLibInterface implements ObjectLibInterface
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void reportJSONError(String error, int ordinal)
+    {
+    RubikObject object = RubikObjectList.getObject(ordinal);
+    String name = object==null ? "NULL" : object.getUpperName();
+
+    if( BuildConfig.DEBUG )
+       {
+       android.util.Log.e("libInterface", "name="+name+" JSON error: "+error);
+       }
+    else
+      {
+      Exception ex = new Exception(error);
+      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
+      crashlytics.setCustomKey("name" , name );
+      crashlytics.setCustomKey("JSONerror", error );
+      crashlytics.recordException(ex);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void onReplaceModeDown(int cubit, int face)
diff --git a/src/main/java/org/distorted/tutorials/TutorialObjectLibInterface.java b/src/main/java/org/distorted/tutorials/TutorialObjectLibInterface.java
index 52f6bf2e..09a1bf50 100644
--- a/src/main/java/org/distorted/tutorials/TutorialObjectLibInterface.java
+++ b/src/main/java/org/distorted/tutorials/TutorialObjectLibInterface.java
@@ -48,6 +48,7 @@ public class TutorialObjectLibInterface implements ObjectLibInterface
   public void onObjectCreated(long time) { }
   public void onReplaceModeDown(int cubit, int face) { }
   public void onReplaceModeUp() { }
+  public void reportJSONError(String error, int ordinal) { }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
