commit 6570171b2ef46361d4407736722e85288ecd647c
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Sep 28 22:28:09 2020 +0100

    Make the RubikScores class thread-safe.

diff --git a/src/main/java/org/distorted/scores/RubikScores.java b/src/main/java/org/distorted/scores/RubikScores.java
index 45c01fcc..d2c1cf5b 100644
--- a/src/main/java/org/distorted/scores/RubikScores.java
+++ b/src/main/java/org/distorted/scores/RubikScores.java
@@ -93,50 +93,6 @@ public class RubikScores
     return id<0 ? -id : id;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private String getUnsubmittedList(int mode)
-    {
-    ObjectList list;
-    StringBuilder builder = new StringBuilder();
-    boolean first = true;
-    int[] sizes;
-    int length;
-
-    for(int object=0; object<NUM_OBJECTS; object++)
-      {
-      list = ObjectList.getObject(object);
-      sizes = list.getSizes();
-      length = sizes.length;
-
-      for(int size=0; size<length; size++)
-        {
-        for(int level=0; level<MAX_LEVEL; level++)
-          {
-          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
-            {
-            if( !first ) builder.append(',');
-            else         first=false;
-
-            switch(mode)
-              {
-              case 0: builder.append(list.name());
-                      builder.append("_");
-                      builder.append(sizes[size]);
-                      break;
-              case 1: builder.append(level);
-                      break;
-              case 2: builder.append(mRecords[object][size][level]);
-                      break;
-              }
-            }
-          }
-        }
-      }
-
-    return builder.toString();
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -153,7 +109,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void savePreferences(SharedPreferences.Editor editor)
+  public synchronized void savePreferences(SharedPreferences.Editor editor)
     {
     StringBuilder builder = new StringBuilder();
     ObjectList list;
@@ -195,7 +151,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void restorePreferences(SharedPreferences preferences)
+  public synchronized void restorePreferences(SharedPreferences preferences)
     {
     String recordStr, subStr, nameStr, sizeStr, timeStr, submStr;
     int start, end, equals, underscore, comma;
@@ -242,12 +198,12 @@ public class RubikScores
               }
             else
               {
-              android.util.Log.e("solv", "error: size="+sizeIndex+" subm="+subm);
+              android.util.Log.e("scores", "error: size="+sizeIndex+" subm="+subm);
               }
             }
           else
             {
-            android.util.Log.e("solv", "error: object="+object);
+            android.util.Log.e("scores", "error: object="+object);
             }
           }
         }
@@ -264,7 +220,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public boolean setRecord(int object, int size, int level, long timeTaken)
+  public synchronized boolean setRecord(int object, int size, int level, long timeTaken)
     {
     int maxsize = ObjectList.getObject(object).getSizes().length;
 
@@ -304,7 +260,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void successfulSubmit()
+  synchronized void successfulSubmit()
     {
     mNameIsVerified = true;
 
@@ -350,7 +306,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public boolean isSolved(int object, int size, int level)
+  public synchronized boolean isSolved(int object, int size, int level)
     {
     int maxsize = ObjectList.getObject(object).getSizes().length;
 
@@ -364,7 +320,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public long getRecord(int object, int size, int level)
+  public synchronized long getRecord(int object, int size, int level)
     {
     int maxsize = ObjectList.getObject(object).getSizes().length;
 
@@ -378,7 +334,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public boolean isSubmitted(int object, int size, int level)
+  public synchronized boolean isSubmitted(int object, int size, int level)
     {
     int maxsize = ObjectList.getObject(object).getSizes().length;
 
@@ -434,7 +390,7 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  boolean thereAreUnsubmittedRecords()
+  synchronized boolean thereAreUnsubmittedRecords()
     {
     ObjectList list;
     int length;
@@ -459,22 +415,49 @@ public class RubikScores
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  String getUnsubmittedObjlist()
+  synchronized String getRecordList(String strObj, String strLvl, String strTim)
     {
-    return getUnsubmittedList(0);
-    }
+    ObjectList list;
+    StringBuilder builderObj = new StringBuilder();
+    StringBuilder builderLvl = new StringBuilder();
+    StringBuilder builderTim = new StringBuilder();
+    boolean first = true;
+    int[] sizes;
+    int length;
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    for(int object=0; object<NUM_OBJECTS; object++)
+      {
+      list = ObjectList.getObject(object);
+      sizes = list.getSizes();
+      length = sizes.length;
 
-  String getUnsubmittedLevellist()
-    {
-    return getUnsubmittedList(1);
-    }
+      for(int size=0; size<length; size++)
+        {
+        for(int level=0; level<MAX_LEVEL; level++)
+          {
+          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
+            {
+            if( !first )
+              {
+              builderObj.append(',');
+              builderLvl.append(',');
+              builderTim.append(',');
+              }
+            else
+              {
+              first=false;
+              }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+            builderObj.append(list.name());
+            builderObj.append("_");
+            builderObj.append(sizes[size]);
+            builderLvl.append(level);
+            builderTim.append(mRecords[object][size][level]);
+            }
+          }
+        }
+      }
 
-  String getUnsubmittedTimelist()
-    {
-    return getUnsubmittedList(2);
+    return strObj+builderObj.toString()+strLvl+builderLvl.toString()+strTim+builderTim.toString();
     }
   }
diff --git a/src/main/java/org/distorted/scores/RubikScoresDownloader.java b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
index 235deea6..c525ba30 100644
--- a/src/main/java/org/distorted/scores/RubikScoresDownloader.java
+++ b/src/main/java/org/distorted/scores/RubikScoresDownloader.java
@@ -285,8 +285,6 @@ public class RubikScoresDownloader implements Runnable
 
   private boolean network(String url)
     {
-    //android.util.Log.e("down", "url: "+url);
-
     try
       {
       java.net.URL connectURL = new URL(url);
@@ -368,18 +366,15 @@ public class RubikScoresDownloader implements Runnable
     int numRuns = scores.getNumRuns();
     int numPlay = scores.getNumPlays();
     int deviceID= scores.getDeviceID();
-    String objlist = scores.getUnsubmittedObjlist();
-    String lvllist = scores.getUnsubmittedLevellist();
-    String timlist = scores.getUnsubmittedTimelist();
+    String reclist = scores.getRecordList("&o=","&l=","&t=");
     String country = scores.getCountry();
     long epoch = System.currentTimeMillis();
     String salt = "cuboid";
 
     String url1="https://distorted.org/magic/cgi-bin/submit.cgi";
     String url2 = "n="+name+"&v="+veri+"&r="+numRuns+"&p="+numPlay+"&i="+deviceID+"&e="+mVersion+"d";
-    url2 += "&o="+objlist+"&l="+lvllist+"&t="+timlist+"&c="+country+"&f="+epoch;
-    url2 += "&oo="+ ObjectList.getObjectList()+"&min=0&max="+MAX_LEVEL+"&lo="+MAX_PLACES;
-    url2 += "&h="+computeHash( url2, salt.getBytes() );
+    url2 += reclist+"&c="+country+"&f="+epoch+"&oo="+ ObjectList.getObjectList();
+    url2 += "&min=0&max="+MAX_LEVEL+"&lo="+MAX_PLACES+"&h="+computeHash( url2, salt.getBytes() );
 
     return url1 + "?" + url2;
     }
@@ -479,7 +474,7 @@ public class RubikScoresDownloader implements Runnable
       }
     catch (PackageManager.NameNotFoundException e)
       {
-      mVersion = "1.1.2";
+      mVersion = "0.9.2";
       }
 
     Thread networkThrd = new Thread(this);
