Project

General

Profile

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

magiccube / src / main / java / org / distorted / external / RubikScores.java @ 83018ac4

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