Project

General

Profile

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

magiccube / src / main / java / org / distorted / network / RubikScores.java @ 1d643a0e

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