Project

General

Profile

Download (12.7 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / external / RubikScores.java @ 1ba56d95

1 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 1c327853 Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 acabdd83 Leszek Koltunski
package org.distorted.external;
11 f0e87514 Leszek Koltunski
12 a7d8c3cd Leszek Koltunski
import java.util.HashMap;
13 3f7a4363 Leszek Koltunski
import java.util.UUID;
14
15 82ce8e64 Leszek Koltunski
import android.content.Context;
16 f0e87514 Leszek Koltunski
import android.content.SharedPreferences;
17 82ce8e64 Leszek Koltunski
import android.telephony.TelephonyManager;
18 1c90c64a Leszek Koltunski
19 25445dcf Leszek Koltunski
import com.google.firebase.crashlytics.FirebaseCrashlytics;
20
21 3f7a4363 Leszek Koltunski
import org.distorted.main.BuildConfig;
22 a7d8c3cd Leszek Koltunski
import org.distorted.objects.RubikObject;
23
import org.distorted.objects.RubikObjectList;
24 f0e87514 Leszek Koltunski
25 5bda8973 Leszek Koltunski
import static org.distorted.objectlib.main.ObjectType.MAX_SCRAMBLES;
26 d433b50e Leszek Koltunski
27 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
28 82ce8e64 Leszek Koltunski
// hold my own scores, and some other statistics.
29 f0e87514 Leszek Koltunski
30
public class RubikScores
31
  {
32 5bda8973 Leszek Koltunski
  public static final int MAX_RECORD = 10;
33 a7d8c3cd Leszek Koltunski
  public static final int MULT = 1000000;
34 1c90c64a Leszek Koltunski
  public static final long NO_RECORD = Long.MAX_VALUE;
35 714292f1 Leszek Koltunski
  private static RubikScores mThis;
36
37 82ce8e64 Leszek Koltunski
  private String mName, mCountry;
38 c3ffcf58 Leszek Koltunski
  private boolean mNameIsVerified;
39
  private int mNumRuns;
40
  private int mNumPlays;
41 59aee296 Leszek Koltunski
  private int mNumWins;
42 82ce8e64 Leszek Koltunski
  private int mDeviceID;
43 f0e87514 Leszek Koltunski
44 a7d8c3cd Leszek Koltunski
  private static class MapValue
45
    {
46
    long record;
47
    boolean submitted;
48
49
    MapValue(long rec,int sub)
50
      {
51
      record    = rec;
52
      submitted = sub!=0;
53
      }
54
    }
55
56
  private final HashMap<Integer,MapValue> mMap;
57
58 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
59
60 714292f1 Leszek Koltunski
  private RubikScores()
61 f0e87514 Leszek Koltunski
    {
62 a7d8c3cd Leszek Koltunski
    mMap = new HashMap<>();
63 c3ffcf58 Leszek Koltunski
64 f895e77a Leszek Koltunski
    mName = "";
65 82ce8e64 Leszek Koltunski
    mCountry = "un";
66
67 c3ffcf58 Leszek Koltunski
    mNameIsVerified = false;
68 82ce8e64 Leszek Koltunski
69 59aee296 Leszek Koltunski
    mNumPlays= -1;
70
    mNumRuns = -1;
71
    mDeviceID= -1;
72
    mNumWins =  0;
73 f0e87514 Leszek Koltunski
    }
74
75 a7d8c3cd Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
76
77
  private int mapKey(int object,int level)
78
    {
79
    return object*MULT + level;
80
    }
81
82 17f9a695 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
83
84
  private int privateGetDeviceID()
85
    {
86
    int id;
87
88
    try
89
      {
90
      String s = UUID.randomUUID().toString();
91 874c37b1 Leszek Koltunski
      id = s.hashCode();
92 17f9a695 Leszek Koltunski
      }
93
    catch(Exception ex)
94
      {
95
      id = 0;
96
      android.util.Log.e("scores", "Exception in getDeviceID()");
97
      }
98
99
    return id<0 ? -id : id;
100
    }
101
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103 e06e1b7e Leszek Koltunski
104
  synchronized void successfulSubmit()
105
    {
106
    mNameIsVerified = true;
107
108 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
109
      {
110
      MapValue value = mMap.get(key);
111
      if( value!=null ) value.submitted = true;
112
      }
113 e06e1b7e Leszek Koltunski
    }
114
115 714292f1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
116
117 e06e1b7e Leszek Koltunski
  int getDeviceID()
118 714292f1 Leszek Koltunski
    {
119 e06e1b7e Leszek Koltunski
    return mDeviceID;
120
    }
121 714292f1 Leszek Koltunski
122 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
123
124 e06e1b7e Leszek Koltunski
  synchronized boolean thereAreUnsubmittedRecords()
125 f0e87514 Leszek Koltunski
    {
126 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
127
      {
128
      MapValue value = mMap.get(key);
129
      if( value!=null && !value.submitted && value.record<NO_RECORD) return true;
130
      }
131 c3ffcf58 Leszek Koltunski
132 e06e1b7e Leszek Koltunski
    return false;
133 f0e87514 Leszek Koltunski
    }
134
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136
137 e06e1b7e Leszek Koltunski
  synchronized String getRecordList(String strObj, String strLvl, String strTim)
138 f0e87514 Leszek Koltunski
    {
139 e06e1b7e Leszek Koltunski
    StringBuilder builderObj = new StringBuilder();
140
    StringBuilder builderLvl = new StringBuilder();
141
    StringBuilder builderTim = new StringBuilder();
142
    boolean first = true;
143 f0e87514 Leszek Koltunski
144 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
145 f0e87514 Leszek Koltunski
      {
146 a7d8c3cd Leszek Koltunski
      MapValue value = mMap.get(key);
147 f0e87514 Leszek Koltunski
148 a7d8c3cd Leszek Koltunski
      if( value!=null && !value.submitted && value.record<NO_RECORD)
149 f0e87514 Leszek Koltunski
        {
150 a7d8c3cd Leszek Koltunski
        if( !first )
151 f0e87514 Leszek Koltunski
          {
152 a7d8c3cd Leszek Koltunski
          builderObj.append(',');
153
          builderLvl.append(',');
154
          builderTim.append(',');
155
          }
156
        first=false;
157 7ac0ee88 Leszek Koltunski
158 a7d8c3cd Leszek Koltunski
        RubikObject object = RubikObjectList.getObject(key/MULT);
159
160
        if( object!=null )
161
          {
162 84d746d7 Leszek Koltunski
          builderObj.append(object.getUpperName());
163 a7d8c3cd Leszek Koltunski
          builderLvl.append(key%MULT);
164
          builderTim.append(value.record);
165 f0e87514 Leszek Koltunski
          }
166
        }
167
      }
168 c3ffcf58 Leszek Koltunski
169 e06e1b7e Leszek Koltunski
    return strObj+builderObj.toString()+strLvl+builderLvl.toString()+strTim+builderTim.toString();
170
    }
171 82ce8e64 Leszek Koltunski
172 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
173
// Public API
174 ee4e7896 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
175
176
  public boolean isVerified()
177
    {
178
    return mNameIsVerified;
179
    }
180
181 c3ffcf58 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
182
183 e06e1b7e Leszek Koltunski
  public int getNumPlays()
184 c3ffcf58 Leszek Koltunski
    {
185 e06e1b7e Leszek Koltunski
    return mNumPlays;
186 c3ffcf58 Leszek Koltunski
    }
187
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
190 e06e1b7e Leszek Koltunski
  public int getNumRuns()
191 c3ffcf58 Leszek Koltunski
    {
192 e06e1b7e Leszek Koltunski
    return mNumRuns;
193 c3ffcf58 Leszek Koltunski
    }
194
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
197 e06e1b7e Leszek Koltunski
  public String getName()
198 c3ffcf58 Leszek Koltunski
    {
199 e06e1b7e Leszek Koltunski
    return mName;
200
    }
201 1c90c64a Leszek Koltunski
202 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
203
204
  public String getCountry()
205
    {
206
    return mCountry;
207 1c90c64a Leszek Koltunski
    }
208
209 286d73ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
210
211 e06e1b7e Leszek Koltunski
  public void incrementNumPlays()
212 286d73ae Leszek Koltunski
    {
213 e06e1b7e Leszek Koltunski
    mNumPlays++;
214
    }
215 286d73ae Leszek Koltunski
216 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
217 82ce8e64 Leszek Koltunski
218 e06e1b7e Leszek Koltunski
  public void incrementNumRuns()
219
    {
220
    mNumRuns++;
221
    }
222 82ce8e64 Leszek Koltunski
223 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
224 82ce8e64 Leszek Koltunski
225 59aee296 Leszek Koltunski
  public int incrementNumWins()
226 e06e1b7e Leszek Koltunski
    {
227 59aee296 Leszek Koltunski
    mNumWins++;
228
    return mNumWins;
229 e06e1b7e Leszek Koltunski
    }
230
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232
233
  public void setName(String newName)
234
    {
235
    mName = newName;
236 82ce8e64 Leszek Koltunski
    }
237
238 d7e539d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
239
240 a7d8c3cd Leszek Koltunski
  public synchronized boolean setRecord(int object, int level, long record)
241
    {
242 83018ac4 Leszek Koltunski
    int key = mapKey(object,level);
243 a7d8c3cd Leszek Koltunski
    MapValue oldValue = mMap.get(key);
244
245
    if( oldValue==null )
246
      {
247
      MapValue value = new MapValue(record,0);
248
      mMap.put(key,value);
249
      return true;
250
      }
251
252
    long oldRecord = oldValue.record;
253
254
    if( oldRecord>record)
255
      {
256
      MapValue value = new MapValue(record,0);
257
      mMap.put(key,value);
258
      return true;
259
      }
260
261
    return false;
262
    }
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264
265
  public synchronized long getRecord(int object, int level)
266
    {
267
    int key = mapKey(object,level);
268
    MapValue value = mMap.get(key);
269
    return value!=null ? value.record : NO_RECORD;
270
    }
271
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
274
  public synchronized boolean isSolved(int object, int level)
275 d7e539d0 Leszek Koltunski
    {
276 a7d8c3cd Leszek Koltunski
    int key = mapKey(object,level);
277
    MapValue value = mMap.get(key);
278
    return value!=null && value.record<NO_RECORD;
279 d7e539d0 Leszek Koltunski
    }
280
281 714292f1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
282
283 e06e1b7e Leszek Koltunski
  public void setCountry(Context context)
284 714292f1 Leszek Koltunski
    {
285 e06e1b7e Leszek Koltunski
    TelephonyManager tM =((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
286 714292f1 Leszek Koltunski
287 e06e1b7e Leszek Koltunski
    if( tM!=null )
288 714292f1 Leszek Koltunski
      {
289 e06e1b7e Leszek Koltunski
      mCountry = tM.getSimCountryIso();
290
291
      if( mCountry==null || mCountry.length()<=1 )
292
        {
293
        mCountry = tM.getNetworkCountryIso();
294
        }
295 714292f1 Leszek Koltunski
      }
296
297 e06e1b7e Leszek Koltunski
    // Special case: Dominicana. Its ISO-3166-alpha-2 country code is 'do' which we can't have here
298
    // because we later on map this to a resource name (the flag) and 'do' is a reserved Java keyword
299
    // and can't be a resource name.
300
301
    if( mCountry.equals("do") ) mCountry = "dm";
302 714292f1 Leszek Koltunski
    }
303 c3ffcf58 Leszek Koltunski
304 c8249cf6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
305
306
  public void setCountry(String country)
307
    {
308
    mCountry = country;
309
310
    if( mCountry.equals("do") ) mCountry = "dm";  // see above
311
    }
312
313 286d73ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
314
315 e06e1b7e Leszek Koltunski
  public static RubikScores getInstance()
316 286d73ae Leszek Koltunski
    {
317 9333086d Leszek Koltunski
    if( mThis==null ) mThis = new RubikScores();
318 e06e1b7e Leszek Koltunski
    return mThis;
319 286d73ae Leszek Koltunski
    }
320
321 17f9a695 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
322
323 e06e1b7e Leszek Koltunski
  public synchronized void savePreferences(SharedPreferences.Editor editor)
324 17f9a695 Leszek Koltunski
    {
325 a7d8c3cd Leszek Koltunski
    int numObjects = RubikObjectList.getNumObjects();
326 e06e1b7e Leszek Koltunski
    StringBuilder builder = new StringBuilder();
327 1c90c64a Leszek Koltunski
328 5bda8973 Leszek Koltunski
    for(int level=0; level<=MAX_RECORD; level++)
329 e06e1b7e Leszek Koltunski
      {
330
      builder.setLength(0);
331 1c90c64a Leszek Koltunski
332 a7d8c3cd Leszek Koltunski
      for(int object=0; object<numObjects; object++)
333 e06e1b7e Leszek Koltunski
        {
334 a7d8c3cd Leszek Koltunski
        int key = mapKey(object,level);
335
        RubikObject obj = RubikObjectList.getObject(object);
336
        MapValue value = mMap.get(key);
337
338
        if( obj!=null && value!=null && value.record<NO_RECORD )
339
          {
340 84d746d7 Leszek Koltunski
          builder.append(obj.getUpperName());
341 a7d8c3cd Leszek Koltunski
          builder.append("=");
342
          builder.append(value.record);
343
          builder.append(",");
344
          builder.append(value.submitted ? 1:0 );
345
          builder.append(" ");
346
          }
347 e06e1b7e Leszek Koltunski
        }
348 c3ffcf58 Leszek Koltunski
349 e06e1b7e Leszek Koltunski
      editor.putString("scores_record"+level, builder.toString());
350
      }
351 c3ffcf58 Leszek Koltunski
352 e06e1b7e Leszek Koltunski
    editor.putString("scores_name"  , mName  );
353
    editor.putBoolean("scores_isVerified", mNameIsVerified);
354
    editor.putInt("scores_numPlays", mNumPlays);
355 59aee296 Leszek Koltunski
    editor.putInt("scores_numRuns" , mNumRuns );
356 e06e1b7e Leszek Koltunski
    editor.putInt("scores_deviceid", mDeviceID);
357 59aee296 Leszek Koltunski
    editor.putInt("scores_review"  , mNumWins );
358 c3ffcf58 Leszek Koltunski
    }
359
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361
362 e06e1b7e Leszek Koltunski
  public synchronized void restorePreferences(SharedPreferences preferences)
363 c3ffcf58 Leszek Koltunski
    {
364 9333086d Leszek Koltunski
    String recordStr, subStr, nameStr, timeStr, submStr, errorStr="";
365 5bda8973 Leszek Koltunski
    int start, end, equals, comma, ordinal, subm;
366 e06e1b7e Leszek Koltunski
    long time;
367 25445dcf Leszek Koltunski
    boolean thereWasError = false;
368 a7d8c3cd Leszek Koltunski
    int numObjects = RubikObjectList.getNumObjects();
369 c3ffcf58 Leszek Koltunski
370 5bda8973 Leszek Koltunski
    for(int level=0; level<=MAX_SCRAMBLES; level++)
371 e06e1b7e Leszek Koltunski
      {
372 5bda8973 Leszek Koltunski
      recordStr = preferences.getString("scores_record"+level, null);
373
      if( recordStr==null ) continue;
374 e06e1b7e Leszek Koltunski
      start = end = 0;
375 c3ffcf58 Leszek Koltunski
376 e06e1b7e Leszek Koltunski
      while( end!=-1 )
377
        {
378
        end = recordStr.indexOf(" ", start);
379 4895fff6 Leszek Koltunski
380 e06e1b7e Leszek Koltunski
        if( end==-1 ) subStr = recordStr.substring(start);
381
        else          subStr = recordStr.substring(start,end);
382 4895fff6 Leszek Koltunski
383 e06e1b7e Leszek Koltunski
        start = end+1;
384 4895fff6 Leszek Koltunski
385 e06e1b7e Leszek Koltunski
        equals = subStr.indexOf("=");
386 9333086d Leszek Koltunski
        comma  = subStr.indexOf(",");
387 4895fff6 Leszek Koltunski
388 9333086d Leszek Koltunski
        if( equals>=0 && comma>=0 )
389 4c0cd600 Leszek Koltunski
          {
390 9333086d Leszek Koltunski
          nameStr = subStr.substring(0,equals);
391 e06e1b7e Leszek Koltunski
          timeStr = subStr.substring(equals+1,comma);
392
          submStr = subStr.substring(comma+1);
393
394 5bda8973 Leszek Koltunski
          ordinal = RubikObjectList.getOrdinal(nameStr);
395 e06e1b7e Leszek Koltunski
396 5bda8973 Leszek Koltunski
          if( ordinal>=0 && ordinal<numObjects )
397 4895fff6 Leszek Koltunski
            {
398 e06e1b7e Leszek Koltunski
            time = Long.parseLong(timeStr);
399
            subm = Integer.parseInt(submStr);
400
401 7ac0ee88 Leszek Koltunski
            if( subm>=0 && subm<=1 )
402 e06e1b7e Leszek Koltunski
              {
403 a7d8c3cd Leszek Koltunski
              MapValue value = new MapValue(time,subm);
404 5bda8973 Leszek Koltunski
              int key = mapKey(ordinal,level);
405 a7d8c3cd Leszek Koltunski
              mMap.put(key,value);
406 e06e1b7e Leszek Koltunski
              }
407
            else
408
              {
409 9333086d Leszek Koltunski
              errorStr += ("error1: subm="+subm+" obj: "+nameStr+"\n");
410 25445dcf Leszek Koltunski
              thereWasError= true;
411 e06e1b7e Leszek Koltunski
              }
412
            }
413
          else
414
            {
415 5bda8973 Leszek Koltunski
            errorStr += ("error2: object="+ordinal+" obj: "+nameStr+"\n");
416 25445dcf Leszek Koltunski
            thereWasError = true;
417 4895fff6 Leszek Koltunski
            }
418 4c0cd600 Leszek Koltunski
          }
419 e06e1b7e Leszek Koltunski
        }
420 4895fff6 Leszek Koltunski
      }
421
422 e06e1b7e Leszek Koltunski
    mName           = preferences.getString("scores_name"  , "" );
423
    mNameIsVerified = preferences.getBoolean("scores_isVerified", false);
424
    mNumPlays       = preferences.getInt("scores_numPlays", 0);
425
    mNumRuns        = preferences.getInt("scores_numRuns" , 0);
426
    mDeviceID       = preferences.getInt("scores_deviceid",-1);
427 59aee296 Leszek Koltunski
    mNumWins        = preferences.getInt("scores_review"  , 0);
428 e06e1b7e Leszek Koltunski
429
    if( mDeviceID==-1 ) mDeviceID = privateGetDeviceID();
430 25445dcf Leszek Koltunski
431
    if( thereWasError ) recordDBError(errorStr);
432
    }
433
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435
436
  public void recordDBError(String message)
437
    {
438
    if( BuildConfig.DEBUG )
439
      {
440
      android.util.Log.e("scores", message);
441
      }
442
    else
443
      {
444
      Exception ex = new Exception(message);
445
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
446
      crashlytics.setCustomKey("scores" , message);
447
      crashlytics.recordException(ex);
448
      }
449 4895fff6 Leszek Koltunski
    }
450 f0e87514 Leszek Koltunski
  }