Project

General

Profile

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

magiccube / src / main / java / org / distorted / playui / PlayLibInterface.java @ a5972f92

1 9530f6b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2 7ee8337b leszek
// Copyright 2023 Leszek Koltunski                                                               //
3 9530f6b0 Leszek Koltunski
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 44fec653 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 9530f6b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 7ee8337b leszek
package org.distorted.playui;
11 ce31f774 Leszek Koltunski
12 18b0ae9c leszek
import static org.distorted.external.RubikScores.RECORD_FIRST;
13
import static org.distorted.external.RubikScores.RECORD_NEW;
14
import static org.distorted.external.RubikScores.RECORD_NOT_NEW;
15
16
import android.os.Bundle;
17
18
import androidx.annotation.NonNull;
19
20 88b94310 Leszek Koltunski
import java.lang.ref.WeakReference;
21
22 18b0ae9c leszek
import com.google.android.play.core.review.ReviewInfo;
23
import com.google.android.play.core.review.ReviewManager;
24
import com.google.android.play.core.review.ReviewManagerFactory;
25
import com.google.android.play.core.tasks.OnCompleteListener;
26
import com.google.android.play.core.tasks.OnFailureListener;
27
import com.google.android.play.core.tasks.Task;
28
import com.google.firebase.analytics.FirebaseAnalytics;
29 9530f6b0 Leszek Koltunski
import com.google.firebase.crashlytics.FirebaseCrashlytics;
30
31 18b0ae9c leszek
import org.distorted.dialogs.RubikDialogNewRecord;
32
import org.distorted.dialogs.RubikDialogScoresView;
33
import org.distorted.dialogs.RubikDialogSolved;
34
import org.distorted.external.RubikNetwork;
35
import org.distorted.external.RubikScores;
36 9530f6b0 Leszek Koltunski
import org.distorted.library.message.EffectMessageSender;
37
import org.distorted.objectlib.helpers.BlockController;
38
import org.distorted.objectlib.helpers.ObjectLibInterface;
39 18b0ae9c leszek
import org.distorted.objectlib.main.ObjectControl;
40 c6e27c65 leszek
import org.distorted.objectlib.main.TwistyObject;
41 e09119d8 Leszek Koltunski
import org.distorted.objects.RubikObject;
42
import org.distorted.objects.RubikObjectList;
43 7ee8337b leszek
import org.distorted.main.BuildConfig;
44 9530f6b0 Leszek Koltunski
45
///////////////////////////////////////////////////////////////////////////////////////////////////
46
47 7ee8337b leszek
public class PlayLibInterface implements ObjectLibInterface
48 9530f6b0 Leszek Koltunski
{
49 7ee8337b leszek
  private final WeakReference<PlayActivity> mAct;
50 18b0ae9c leszek
  private int mIsNewRecord;
51
  private int mNewRecord;
52
  private boolean mReviewAsked;
53
  private int mNumRotations, mNumScrambles;
54 88b94310 Leszek Koltunski
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56
57 7ee8337b leszek
  PlayLibInterface(PlayActivity act)
58 88b94310 Leszek Koltunski
    {
59
    mAct = new WeakReference<>(act);
60 18b0ae9c leszek
    mReviewAsked = false;
61
    mNumRotations = 0;
62
    mNumScrambles = 0;
63 88b94310 Leszek Koltunski
    }
64
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66
67 9530f6b0 Leszek Koltunski
  public void onObjectCreated(long time) { }
68
  public void onReplaceModeDown(int cubit, int face) { }
69
  public void onReplaceModeUp() { }
70 88b94310 Leszek Koltunski
71 18b0ae9c leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
72
73
  private void analyticsReport(PlayActivity act, String message, String name, long timeBegin)
74
    {
75
    long elapsed = System.currentTimeMillis() - timeBegin;
76
    String msg = message+" startTime: "+timeBegin+" elapsed: "+elapsed+" name: "+name;
77
78
    if( BuildConfig.DEBUG )
79
      {
80
      android.util.Log.d("libInterface", msg);
81
      }
82
    else
83
      {
84
      FirebaseAnalytics analytics = act.getAnalytics();
85
86
      if( analytics!=null )
87
        {
88
        Bundle bundle = new Bundle();
89
        bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, msg);
90
        analytics.logEvent(FirebaseAnalytics.Event.SHARE, bundle);
91
        }
92
      }
93
    }
94
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96
97
  private void reportRecord(PlayActivity act, long startTime, long endTime, String debug, int scrambleNum)
98
    {
99
    RubikScores scores  = RubikScores.getInstance();
100 c02235d5 leszek
    int objectOrdinal = act.getObjectOrdinal();
101 18b0ae9c leszek
    String name = scores.getName();
102 c02235d5 leszek
    RubikObject obj = RubikObjectList.getObject(objectOrdinal);
103 18b0ae9c leszek
    String objName = obj==null ? "NULL" : obj.getUpperName();
104
105
    String record = objName+" time "+mNewRecord+" isNew: "+mIsNewRecord+" scrambleNum: "+scrambleNum;
106
107
    if( BuildConfig.DEBUG )
108
      {
109
      android.util.Log.e("libInterface", debug);
110
      android.util.Log.e("libInterface", name);
111
      android.util.Log.e("libInterface", record);
112
      }
113
    else
114
      {
115
      if( scrambleNum>=9 && mNewRecord<300*scrambleNum )
116
        {
117
        long timeNow = System.currentTimeMillis();
118
        long elapsed = timeNow - startTime;
119
        String suspicious ="start"+startTime+"end"+endTime+"elapsed"+elapsed+"obj"+objName+"record"+mNewRecord+"scrambles"+scrambleNum+debug;
120
        RubikNetwork network = RubikNetwork.getInstance();
121
        network.suspicious(suspicious,act);
122
        }
123
124
      FirebaseAnalytics analytics = act.getAnalytics();
125
126
      if( analytics!=null )
127
        {
128
        Bundle bundle = new Bundle();
129
        bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, debug);
130
        bundle.putString(FirebaseAnalytics.Param.CHARACTER, name);
131
        bundle.putString(FirebaseAnalytics.Param.LEVEL, record);
132
        analytics.logEvent(FirebaseAnalytics.Event.LEVEL_UP, bundle);
133
        }
134
      }
135
    }
136
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138
139
  private Bundle createDialogBundle()
140
    {
141
    Bundle bundle = new Bundle();
142
    String arg = RubikDialogScoresView.formatRecord(mNewRecord);
143
    bundle.putString("argument", arg );
144
    return bundle;
145
    }
146
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148
149
  private void requestReview(PlayActivity act)
150
    {
151
    android.util.Log.e("D", "ASKING FOR REVIEW");
152
153
    mReviewAsked = true;
154
    final String name = RubikScores.getInstance().getName();
155
    final long timeBegin = System.currentTimeMillis();
156
    final ReviewManager manager = ReviewManagerFactory.create(act);
157
    Task<ReviewInfo> request = manager.requestReviewFlow();
158
159
    request.addOnCompleteListener(new OnCompleteListener<ReviewInfo>()
160
      {
161
      @Override
162
      public void onComplete (@NonNull Task<ReviewInfo> task)
163
        {
164
        if (task.isSuccessful())
165
          {
166
          ReviewInfo reviewInfo = task.getResult();
167
          Task<Void> flow = manager.launchReviewFlow(act, reviewInfo);
168
169
          flow.addOnFailureListener(new OnFailureListener()
170
            {
171
            @Override
172
            public void onFailure(Exception e)
173
            {
174
            analyticsReport(act,"Failed", name, timeBegin);
175
            }
176
            });
177
178
          flow.addOnCompleteListener(new OnCompleteListener<Void>()
179
            {
180
            @Override
181
            public void onComplete(@NonNull Task<Void> task)
182
              {
183
              analyticsReport(act,"Complete", name, timeBegin);
184
              }
185
            });
186
          }
187
        else analyticsReport(act,"Not Successful", name, timeBegin);
188
        }
189
      });
190
    }
191
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
194
  public void onScrambleEffectFinished()
195
    {
196
    if( ScreenList.getCurrentScreen()==ScreenList.SCRA )
197
      {
198
      PlayActivity act = mAct.get();
199
      RubikScores.getInstance().incrementNumPlays();
200
201
      act.runOnUiThread(new Runnable()
202
        {
203
        @Override
204
        public void run()
205
          {
206 e9397ae9 leszek
          ScreenList.switchScreen(act,ScreenList.READ);
207 18b0ae9c leszek
          ObjectControl control = act.getControl();
208
          control.unblockEverything();
209
          }
210
        });
211
      }
212
213
    mNumScrambles++;
214
215
    if( mNumScrambles==10 && !mReviewAsked )
216
      {
217
      PlayActivity act = mAct.get();
218
      requestReview(act);
219
      }
220
    }
221
222 88b94310 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
223
224 4c6cbfa2 leszek
  public void onRemoveRotation(int axis, int row, int angle)
225 88b94310 Leszek Koltunski
    {
226 18b0ae9c leszek
    mNumRotations++;
227 7ee8337b leszek
    PlayActivity act = mAct.get();
228 88b94310 Leszek Koltunski
229
    if( act!=null )
230
      {
231 15ed3429 leszek
      ScreenList screen = ScreenList.getCurrentScreen();
232
233 18b0ae9c leszek
      if( screen==ScreenList.FREE ||
234
          screen==ScreenList.SOLV  ) ((ScreenBase)screen.getScreenClass()).addMove(act,axis,row,angle);
235
      }
236
237
    if( mNumRotations==40 && !mReviewAsked )
238
      {
239
      requestReview(act);
240
      }
241
    }
242
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244
245
  public void onBeginRotation()
246
    {
247 e9397ae9 leszek
    if( ScreenList.getCurrentScreen()==ScreenList.READ )
248 18b0ae9c leszek
      {
249
      ScreenSolving solving = (ScreenSolving) ScreenList.SOLV.getScreenClass();
250
      solving.resetElapsed();
251
      PlayActivity act = mAct.get();
252 e9397ae9 leszek
      ScreenList.switchScreen( act,ScreenList.SOLV );
253 88b94310 Leszek Koltunski
      }
254
    }
255
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
258
  public void failedToDrag()
259
    {
260 7ee8337b leszek
    PlayActivity act = mAct.get();
261 88b94310 Leszek Koltunski
262
    if( act!=null )
263
      {
264 15ed3429 leszek
      ScreenList screen = ScreenList.getCurrentScreen();
265
266 18b0ae9c leszek
      if( screen==ScreenList.FREE ||
267
          screen==ScreenList.SOLV ||
268
          screen==ScreenList.SCRA  ) ((ScreenBase)screen.getScreenClass()).reddenLock(act);
269
      }
270
    }
271
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
274
  public void onSolved()
275
    {
276
    if( ScreenList.getCurrentScreen()==ScreenList.SOLV )
277
      {
278 c02235d5 leszek
      PlayActivity act = mAct.get();
279 ff377568 leszek
      ObjectControl control = act.getControl();
280
      TwistyObject obj = control.getObject();
281
      boolean submittable = obj.isSubmittable();
282 c02235d5 leszek
      int objectOrdinal = act.getObjectOrdinal();
283 18b0ae9c leszek
      ScreenSolving solving = (ScreenSolving)ScreenList.SOLV.getScreenClass();
284
      mNewRecord = solving.stopTimerAndGetRecord();
285 ff377568 leszek
      mIsNewRecord = submittable ? solving.setRecord(objectOrdinal) : RECORD_NOT_NEW;
286 18b0ae9c leszek
      }
287
    }
288
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
291
  public void onWinEffectFinished(long startTime, long endTime, String debug, int scrambleNum)
292
    {
293
    if( ScreenList.getCurrentScreen()==ScreenList.SOLV )
294
      {
295
      PlayActivity act = mAct.get();
296 ff377568 leszek
      ObjectControl control = act.getControl();
297
      TwistyObject obj = control.getObject();
298
      boolean submittable = obj.isSubmittable();
299
300
      if( submittable ) reportRecord(act,startTime,endTime,debug,scrambleNum);
301 18b0ae9c leszek
302
      RubikScores scores = RubikScores.getInstance();
303
      int numWins = scores.incrementNumWins();
304
      int numRuns = scores.getNumRuns();
305
306
      if( numRuns==3 || numRuns==6 || numWins==4 || numWins==20 || numWins==50 || numWins==80 || numWins==100)
307
        {
308
        requestReview(act);
309
        }
310
311
      switch(mIsNewRecord)
312
        {
313
        case RECORD_FIRST  :
314 ff377568 leszek
        case RECORD_NEW    : Bundle byes = createDialogBundle();
315
                             RubikDialogNewRecord dyes = new RubikDialogNewRecord();
316
                             dyes.setArguments(byes);
317
                             dyes.show( act.getSupportFragmentManager(), RubikDialogNewRecord.getDialogTag() );
318 18b0ae9c leszek
                             break;
319
        case RECORD_NOT_NEW: Bundle bno = createDialogBundle();
320
                             RubikDialogSolved dno = new RubikDialogSolved();
321
                             dno.setArguments(bno);
322
                             dno.show( act.getSupportFragmentManager(), RubikDialogSolved.getDialogTag() );
323
        break;
324
        }
325
326
      act.runOnUiThread(new Runnable()
327
        {
328
        @Override
329
        public void run()
330
          {
331
          ScreenList.switchScreen( act,ScreenList.DONE );
332
          }
333
        });
334 88b94310 Leszek Koltunski
      }
335
    }
336 9530f6b0 Leszek Koltunski
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338
339
  public void reportProblem(String problem, boolean reportException)
340
    {
341
    if( BuildConfig.DEBUG )
342
      {
343
      android.util.Log.e("interface", problem);
344
      }
345
    else
346
      {
347
      if( reportException )
348
        {
349
        Exception ex = new Exception(problem);
350
        FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
351
        crashlytics.setCustomKey("problem" , problem);
352
        crashlytics.recordException(ex);
353
        }
354
      else
355
        {
356
        FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
357
        crashlytics.log(problem);
358
        }
359
      }
360
    }
361
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363
364 919b830e Leszek Koltunski
  private void reportScramblingProblem(int place, long pause, long resume, long time)
365 9530f6b0 Leszek Koltunski
    {
366 919b830e Leszek Koltunski
    String error = "SCRAMBLING BLOCK "+place+" blocked for "+time;
367 9530f6b0 Leszek Koltunski
368
    if( BuildConfig.DEBUG )
369
       {
370
       android.util.Log.e("D", error);
371
       }
372
    else
373
      {
374
      Exception ex = new Exception(error);
375
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
376
      crashlytics.setCustomKey("pause" , pause );
377
      crashlytics.setCustomKey("resume", resume );
378
      crashlytics.recordException(ex);
379
      }
380
    }
381
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
384 919b830e Leszek Koltunski
  private void reportRotationProblem(int place, long pause, long resume, long time)
385 9530f6b0 Leszek Koltunski
    {
386 919b830e Leszek Koltunski
    String error = "ROTATION BLOCK "+place+" blocked for "+time;
387 9530f6b0 Leszek Koltunski
388
    if( BuildConfig.DEBUG )
389
       {
390
       android.util.Log.e("D", error);
391
       }
392
    else
393
      {
394
      Exception ex = new Exception(error);
395
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
396
      crashlytics.setCustomKey("pause" , pause );
397
      crashlytics.setCustomKey("resume", resume);
398
      crashlytics.recordException(ex);
399
      }
400
    }
401
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403
404
  private void reportThreadProblem(int place, long pause, long resume, long time)
405
    {
406
    String error = EffectMessageSender.reportState();
407
408
    if( BuildConfig.DEBUG )
409
       {
410
       android.util.Log.e("D", error);
411
       }
412
    else
413
      {
414
      Exception ex = new Exception(error);
415
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
416
      crashlytics.setCustomKey("pause" , pause  );
417
      crashlytics.setCustomKey("resume", resume );
418
      crashlytics.recordException(ex);
419
      }
420
    }
421
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423
424
  public void reportBlockProblem(int type, int place, long pause, long resume, long time)
425
    {
426
    switch(type)
427
      {
428 919b830e Leszek Koltunski
      case BlockController.TYPE_SCRAMBLING: reportScramblingProblem(place,pause,resume,time); break;
429
      case BlockController.TYPE_ROTATION  : reportRotationProblem(place,pause,resume,time); break;
430
      case BlockController.TYPE_THREAD    : reportThreadProblem(place,pause,resume,time); break;
431 9530f6b0 Leszek Koltunski
      }
432
    }
433 e09119d8 Leszek Koltunski
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435
436
  public void reportJSONError(String error, int ordinal)
437
    {
438
    RubikObject object = RubikObjectList.getObject(ordinal);
439
    String name = object==null ? "NULL" : object.getUpperName();
440
441
    if( BuildConfig.DEBUG )
442
       {
443
       android.util.Log.e("libInterface", "name="+name+" JSON error: "+error);
444
       }
445
    else
446
      {
447
      Exception ex = new Exception(error);
448
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
449
      crashlytics.setCustomKey("name" , name );
450
      crashlytics.setCustomKey("JSONerror", error );
451
      crashlytics.recordException(ex);
452
      }
453
    }
454 9530f6b0 Leszek Koltunski
}