Project

General

Profile

« Previous | Next » 

Revision 809c3432

Added by Leszek Koltunski over 3 years ago

Introduce a BlockController - a watchdog which makes sure the Touch and UI blocks do not take too long.
If it detecs a long block, it unblocks and reports the situation to Crashylytics.

View differences:

src/main/java/org/distorted/control/RubikControl.java
19 19

  
20 20
package org.distorted.control;
21 21

  
22
import org.distorted.helpers.BlockController;
22 23
import org.distorted.library.main.DistortedNode;
23 24
import org.distorted.library.main.DistortedScreen;
24 25
import org.distorted.library.message.EffectListener;
......
174 175

  
175 176
  public void animateAll(RubikActivity act)
176 177
    {
177
    act.blockEverything();
178
    act.blockEverything(BlockController.CONTROL_PLACE_0);
178 179
    mRefAct = new WeakReference<>(act);
179 180

  
180 181
    mWholeReturned = false;
......
187 188

  
188 189
  public void animateRotate(RubikActivity act)
189 190
    {
190
    act.blockEverything();
191
    act.blockEverything(BlockController.CONTROL_PLACE_1);
191 192
    mRefAct = new WeakReference<>(act);
192 193

  
193 194
    mWholeReturned = true;
src/main/java/org/distorted/helpers/BlockController.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 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
package org.distorted.helpers;
21

  
22
import com.google.firebase.crashlytics.FirebaseCrashlytics;
23

  
24
import org.distorted.main.BuildConfig;
25

  
26
import java.lang.ref.WeakReference;
27
import java.util.Timer;
28
import java.util.TimerTask;
29

  
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

  
32
public class BlockController
33
  {
34
  public static final int RUBIK_PLACE_0 =0;
35
  public static final int RUBIK_PLACE_1 =1;
36
  public static final int RUBIK_PLACE_2 =2;
37
  public static final int RUBIK_PLACE_3 =3;
38
  public static final int RUBIK_PLACE_4 =4;
39
  public static final int TUTORIAL_PLACE_0 =10;
40
  public static final int TUTORIAL_PLACE_1 =11;
41
  public static final int TUTORIAL_PLACE_2 =12;
42
  public static final int TUTORIAL_PLACE_3 =13;
43
  public static final int TUTORIAL_PLACE_4 =14;
44
  public static final int CONTROL_PLACE_0 =20;
45
  public static final int CONTROL_PLACE_1 =21;
46
  public static final int MOVES_PLACE_0 =30;
47

  
48
  private static final long THRESHHOLD_0 =  5000;
49
  private static final long THRESHHOLD_1 = 25000;
50

  
51
  private static long mPauseTime, mResumeTime;
52

  
53
  private long mTouchBlockTime, mUIBlockTime;
54
  private int mLastTouchPlace, mLastUIPlace;
55

  
56
  private final WeakReference<TwistyActivity> mAct;
57

  
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

  
60
  public static void onPause()
61
    {
62
    mPauseTime = System.currentTimeMillis();
63
    }
64

  
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

  
67
  public static void onResume()
68
    {
69
    mResumeTime = System.currentTimeMillis();
70
    }
71

  
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73

  
74
  public BlockController(TwistyActivity act)
75
    {
76
    mAct = new WeakReference<>(act);
77

  
78
    Timer timer = new Timer();
79

  
80
    timer.scheduleAtFixedRate(new TimerTask()
81
      {
82
      @Override
83
      public void run()
84
        {
85
        act.runOnUiThread(new Runnable()
86
          {
87
          @Override
88
          public void run()
89
            {
90
            checkingThread();
91
            }
92
          });
93
        }
94
      }, 0, 1000);
95
    }
96

  
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98
// RUBIK_PLACE_3 and TUTORIAL_PLACE_3 are scrambles, those can take up to 20 seconds.
99

  
100
  private void checkingThread()
101
    {
102
    long now = System.currentTimeMillis();
103

  
104
    long touchThreshhold = (mLastTouchPlace==RUBIK_PLACE_3 || mLastTouchPlace==TUTORIAL_PLACE_3) ? THRESHHOLD_1 : THRESHHOLD_0;
105

  
106
    if( mTouchBlockTime>mPauseTime && now-mTouchBlockTime>touchThreshhold )
107
      {
108
      TwistyActivity act = mAct.get();
109

  
110
      if( act!=null )
111
        {
112
        TwistyPreRender pre = act.getTwistyPreRender();
113
        if( pre!=null ) pre.unblockTouch();
114
        }
115

  
116
      reportTouchProblem(touchThreshhold);
117
      }
118

  
119
    long uiThreshhold = (mLastUIPlace==RUBIK_PLACE_3 || mLastUIPlace==TUTORIAL_PLACE_3) ? THRESHHOLD_1 : THRESHHOLD_0;
120

  
121
    if( mUIBlockTime>mPauseTime && now-mUIBlockTime>uiThreshhold )
122
      {
123
      TwistyActivity act = mAct.get();
124

  
125
      if( act!=null )
126
        {
127
        TwistyPreRender pre = act.getTwistyPreRender();
128
        if( pre!=null ) pre.unblockUI();
129
        }
130

  
131
      reportUIProblem(uiThreshhold);
132
      }
133
    }
134

  
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

  
137
  private void reportTouchProblem(long time)
138
    {
139
    String error = "TOUCH BLOCK "+mLastTouchPlace+" blocked for "+time+" milliseconds!";
140

  
141
    if( BuildConfig.DEBUG )
142
       {
143
       android.util.Log.e("D", error);
144
       }
145
    else
146
      {
147
      Exception ex = new Exception(error);
148
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
149
      crashlytics.setCustomKey("type"  , "Touch" );
150
      crashlytics.setCustomKey("place" , mLastTouchPlace );
151
      crashlytics.recordException(ex);
152
      }
153
    }
154

  
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

  
157
  private void reportUIProblem(long time)
158
    {
159
    String error = "UI BLOCK "+mLastUIPlace+" blocked for "+time+" milliseconds!";
160

  
161
    if( BuildConfig.DEBUG )
162
       {
163
       android.util.Log.e("D", error);
164
       }
165
    else
166
      {
167
      Exception ex = new Exception(error);
168
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
169
      crashlytics.setCustomKey("type"  , "UI" );
170
      crashlytics.setCustomKey("place" , mLastUIPlace );
171
      crashlytics.recordException(ex);
172
      }
173
    }
174

  
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

  
177
  public void touchBlocked(int place)
178
    {
179
    mTouchBlockTime = System.currentTimeMillis();
180
    mLastTouchPlace = place;
181
    }
182

  
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

  
185
  public void uiBlocked(int place)
186
    {
187
    mUIBlockTime = System.currentTimeMillis();
188
    mLastUIPlace = place;
189
    }
190

  
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

  
193
  public void touchUnblocked()
194
    {
195
    mTouchBlockTime = 0;
196
    }
197

  
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

  
200
  public void uiUnblocked()
201
    {
202
    mUIBlockTime = 0;
203
    }
204
  }
src/main/java/org/distorted/helpers/MovesAndLockController.java
148 148
          {
149 149
          mCanPrevMove = false;
150 150
          mPre = act.getTwistyPreRender();
151
          mPre.blockTouch();
151
          mPre.blockTouch(BlockController.MOVES_PLACE_0);
152 152
          mPre.addRotation(this, axis, row, -angle, duration);
153 153
          }
154 154
        else
src/main/java/org/distorted/helpers/TwistyPreRender.java
23 23

  
24 24
public interface TwistyPreRender
25 25
  {
26
  void blockTouch();
26
  void blockTouch(int place);
27 27
  void unblockTouch();
28
  void blockEverything();
28
  void blockEverything(int place);
29 29
  void unblockEverything();
30
  void unblockUI();
30 31
  void addRotation(MovesFinished listener, int axis, int rowBitmap, int angle, long duration);
31 32
  void solveObject();
32 33
  }
src/main/java/org/distorted/main/RubikActivity.java
38 38
import org.distorted.dialogs.RubikDialogError;
39 39
import org.distorted.dialogs.RubikDialogPrivacy;
40 40
import org.distorted.effects.BaseEffect;
41
import org.distorted.helpers.BlockController;
41 42
import org.distorted.helpers.TwistyActivity;
42 43
import org.distorted.helpers.TwistyPreRender;
43 44
import org.distorted.library.main.DistortedLibrary;
......
228 229
      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
229 230
      view.onPause();
230 231
      DistortedLibrary.onPause(0);
232
      BlockController.onPause();
231 233
      RubikNetwork.onPause();
232 234
      savePreferences();
233 235
      }
......
239 241
      {
240 242
      super.onResume();
241 243
      DistortedLibrary.onResume(0);
244
      BlockController.onResume();
242 245
      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
243 246
      view.onResume();
244 247
      view.initialize();
......
571 574

  
572 575
///////////////////////////////////////////////////////////////////////////////////////////////////
573 576

  
574
    public void blockEverything()
577
    public void blockEverything(int place)
575 578
      {
576 579
      setLock();
577 580

  
578 581
      TwistyPreRender pre = getPreRender();
579
      pre.blockEverything();
582
      pre.blockEverything(place);
580 583

  
581 584
      RubikScreenPlay play = (RubikScreenPlay) ScreenList.PLAY.getScreenClass();
582 585
      play.setLockState(this);
src/main/java/org/distorted/main/RubikPreRender.java
39 39
import org.distorted.effects.BaseEffect;
40 40
import org.distorted.effects.EffectController;
41 41
import org.distorted.effects.scramble.ScrambleEffect;
42
import org.distorted.helpers.BlockController;
42 43
import org.distorted.helpers.MovesFinished;
43 44
import org.distorted.helpers.TwistyPreRender;
44 45
import org.distorted.objects.TwistyObject;
......
77 78
  private int mNearestAngle;
78 79
  private String mDebug;
79 80
  private long mDebugStartTime;
81
  private final BlockController mBlockController;
80 82

  
81 83
///////////////////////////////////////////////////////////////////////////////////////////////////
82 84

  
......
94 96
    mSolveObject          = false;
95 97
    mScrambleObject       = false;
96 98

  
97
    unblockEverything();
98

  
99 99
    mOldObject = null;
100 100
    mNewObject = null;
101 101

  
......
105 105
    mEffectID = new long[BaseEffect.Type.LENGTH];
106 106

  
107 107
    mDebug = "";
108

  
109
    RubikActivity act = (RubikActivity)mView.getContext();
110
    mBlockController = new BlockController(act);
111
    unblockEverything();
108 112
    }
109 113

  
110 114
///////////////////////////////////////////////////////////////////////////////////////////////////
......
234 238
  private void finishRotationNow()
235 239
    {
236 240
    mFinishRotation = false;
237
    blockEverything();
241
    blockEverything(BlockController.RUBIK_PLACE_0);
238 242
    mRotationFinishedID = mNewObject.finishRotationNow(this, mNearestAngle);
239 243

  
240 244
    if( mRotationFinishedID==0 ) // failed to add effect - should never happen
......
251 255

  
252 256
    if ( mNewObject==null || mNewObject.getObjectList()!=mNextObject || mNewObject.getNumLayers()!=mNextSize)
253 257
      {
254
      blockEverything();
258
      blockEverything(BlockController.RUBIK_PLACE_1);
255 259
      createObjectNow(mNextObject, mNextSize, null);
256 260
      doEffectNow( BaseEffect.Type.SIZECHANGE );
257 261
      }
......
265 269

  
266 270
    if ( mNewObject==null || mNewObject.getObjectList()!=mNextObject || mNewObject.getNumLayers()!=mNextSize)
267 271
      {
268
      blockEverything();
272
      blockEverything(BlockController.RUBIK_PLACE_2);
269 273
      createObjectNow(mNextObject, mNextSize, mNextMoves);
270 274
      doEffectNow( BaseEffect.Type.SIZECHANGE );
271 275
      }
......
281 285
    {
282 286
    mScrambleObject = false;
283 287
    mIsSolved       = false;
284
    blockEverything();
288
    blockEverything(BlockController.RUBIK_PLACE_3);
285 289
    RubikScores.getInstance().incrementNumPlays();
286 290
    doEffectNow( BaseEffect.Type.SCRAMBLE );
287 291
    }
......
291 295
  private void solveObjectNow()
292 296
    {
293 297
    mSolveObject = false;
294
    blockEverything();
298
    blockEverything(BlockController.RUBIK_PLACE_4);
295 299
    doEffectNow( BaseEffect.Type.SOLVE );
296 300
    }
297 301

  
......
542 546

  
543 547
///////////////////////////////////////////////////////////////////////////////////////////////////
544 548

  
545
  public void blockEverything()
549
  public void blockEverything(int place)
546 550
    {
547 551
    mUIBlocked   = true;
548 552
    mTouchBlocked= true;
553
    mBlockController.touchBlocked(place);
554
    mBlockController.uiBlocked(place);
549 555
    }
550 556

  
551 557
///////////////////////////////////////////////////////////////////////////////////////////////////
552 558

  
553
  public void blockTouch()
559
  public void blockTouch(int place)
554 560
    {
555 561
    mTouchBlocked= true;
562
    mBlockController.touchBlocked(place);
556 563
    }
557 564

  
558 565
///////////////////////////////////////////////////////////////////////////////////////////////////
......
561 568
    {
562 569
    mUIBlocked   = false;
563 570
    mTouchBlocked= false;
571
    mBlockController.touchUnblocked();
572
    mBlockController.uiUnblocked();
564 573
    }
565 574

  
566 575
///////////////////////////////////////////////////////////////////////////////////////////////////
......
568 577
  public void unblockTouch()
569 578
    {
570 579
    mTouchBlocked= false;
580
    mBlockController.touchUnblocked();
581
    }
582

  
583
///////////////////////////////////////////////////////////////////////////////////////////////////
584

  
585
  public void unblockUI()
586
    {
587
    mUIBlocked= false;
588
    mBlockController.uiUnblocked();
571 589
    }
572 590

  
573 591
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/tutorials/TutorialPreRender.java
24 24

  
25 25
import org.distorted.effects.BaseEffect;
26 26
import org.distorted.effects.EffectController;
27
import org.distorted.helpers.BlockController;
27 28
import org.distorted.helpers.MovesFinished;
28 29
import org.distorted.helpers.TwistyPreRender;
29 30
import org.distorted.objects.ObjectList;
......
50 51
  private long mAddRotationID, mRemoveRotationID;
51 52
  private int mNearestAngle;
52 53
  private int mScrambleObjectNum;
54
  private final BlockController mBlockController;
53 55

  
54 56
///////////////////////////////////////////////////////////////////////////////////////////////////
55 57

  
......
66 68
    mSolveObject    = false;
67 69
    mScrambleObject = false;
68 70

  
69
    unblockEverything();
70

  
71 71
    mOldObject      = null;
72 72
    mNewObject      = null;
73 73

  
......
75 75
    mScrambleObjectNum = 0;
76 76

  
77 77
    mRemovePatternRotation= false;
78

  
79
    TutorialActivity act = (TutorialActivity)mView.getContext();
80
    mBlockController = new BlockController(act);
81
    unblockEverything();
78 82
    }
79 83

  
80 84
///////////////////////////////////////////////////////////////////////////////////////////////////
......
174 178
  private void finishRotationNow()
175 179
    {
176 180
    mFinishRotation = false;
177
    blockEverything();
181
    blockEverything(BlockController.TUTORIAL_PLACE_0);
178 182
    mRotationFinishedID = mNewObject.finishRotationNow(this, mNearestAngle);
179 183

  
180 184
    if( mRotationFinishedID==0 ) // failed to add effect - should never happen
......
191 195

  
192 196
    if ( mNewObject==null || mNewObject.getObjectList()!=mNextObject || mNewObject.getNumLayers()!=mNextSize)
193 197
      {
194
      blockEverything();
198
      blockEverything(BlockController.TUTORIAL_PLACE_1);
195 199
      createObjectNow(mNextObject, mNextSize);
196 200
      doEffectNow( BaseEffect.Type.SIZECHANGE );
197 201
      }
......
205 209

  
206 210
    if ( mNewObject==null || mNewObject.getObjectList()!=mNextObject || mNewObject.getNumLayers()!=mNextSize)
207 211
      {
208
      blockEverything();
212
      blockEverything(BlockController.TUTORIAL_PLACE_2);
209 213
      createObjectNow(mNextObject, mNextSize);
210 214
      doEffectNow( BaseEffect.Type.SIZECHANGE );
211 215
      }
......
221 225
    {
222 226
    mScrambleObject = false;
223 227
    mIsSolved       = false;
224
    blockEverything();
228
    blockEverything(BlockController.TUTORIAL_PLACE_3);
225 229
    doEffectNow( BaseEffect.Type.SCRAMBLE );
226 230
    }
227 231

  
......
230 234
  private void solveObjectNow()
231 235
    {
232 236
    mSolveObject = false;
233
    blockEverything();
237
    blockEverything(BlockController.TUTORIAL_PLACE_4);
234 238
    doEffectNow( BaseEffect.Type.SOLVE );
235 239
    }
236 240

  
......
336 340

  
337 341
///////////////////////////////////////////////////////////////////////////////////////////////////
338 342

  
339
  public void blockEverything()
343
  public void blockEverything(int place)
340 344
    {
341 345
    mUIBlocked   = true;
342 346
    mTouchBlocked= true;
347
    mBlockController.touchBlocked(place);
348
    mBlockController.uiBlocked(place);
343 349
    }
344 350

  
345 351
///////////////////////////////////////////////////////////////////////////////////////////////////
346 352

  
347
  public void blockTouch()
353
  public void blockTouch(int place)
348 354
    {
349 355
    mTouchBlocked= true;
356
    mBlockController.touchBlocked(place);
350 357
    }
351 358

  
352 359
///////////////////////////////////////////////////////////////////////////////////////////////////
......
355 362
    {
356 363
    mUIBlocked   = false;
357 364
    mTouchBlocked= false;
365
    mBlockController.touchUnblocked();
366
    mBlockController.uiUnblocked();
358 367
    }
359 368

  
360 369
///////////////////////////////////////////////////////////////////////////////////////////////////
......
362 371
  public void unblockTouch()
363 372
    {
364 373
    mTouchBlocked= false;
374
    mBlockController.touchUnblocked();
375
    }
376

  
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

  
379
  public void unblockUI()
380
    {
381
    mUIBlocked= false;
382
    mBlockController.uiUnblocked();
365 383
    }
366 384

  
367 385
///////////////////////////////////////////////////////////////////////////////////////////////////

Also available in: Unified diff