Skip to content

Developer Documentation โ€“ Shake Game Feature

This document provides technical details for developers working on the Shake Game feature of z.Mantra. It explains the structure, logic, and extensibility of the ShakeFragment and related components.


๐Ÿ“‚ Location

com.zendalona.zmantra.presentation.features.game.shake

๐Ÿ“„ Core Class: ShakeFragment

The ShakeFragment implements a game where the player answers questions by shaking the device.

It extends:

  • BaseGameFragment โ†’ provides shared game logic (TTS, answer submission, game flow).
  • SensorEventListener โ†’ listens to accelerometer data for detecting shakes.

๐Ÿ—๏ธ Lifecycle & Flow

  1. Initialization

  2. SensorManager and accelerometer sensor are registered in onResume.

  3. GIF animation (rotate your phone) is loaded if defined.

  4. Loading Questions

  5. onQuestionsLoaded() receives a list of GameQuestion objects.

  6. Each question specifies:

    • expression: Instruction (e.g., "Shake 3 times").
    • answer: Correct shake count.
    • timeLimit: Allowed time to complete (default = 10s if undefined).
  7. Starting a Question

  8. startQuestion():

    • Resets counters (count, wrongAttempts, answerChecked).
    • Updates UI (ringMeTv, ringCount).
    • Announces question using TTS + accessibility.
  9. Shake Detection

  10. onSensorChanged() calculates acceleration from accelerometer values:

    kotlin val acceleration = sqrt((x*x + y*y + z*z).toDouble()).toFloat() if (acceleration > 12f) onShakeDetected() * Threshold = 12f (tuned to filter small device movements).

  11. Shake Handling

  12. onShakeDetected():

    • Increments count.
    • Announces count via TTS + Accessibility.
    • If count exceeds expected โ†’ triggers checkAnswer(forceWrong = true).
    • If count == expected โ†’ delayed checkAnswer() after 1.5s.
  13. Answer Checking

  14. checkAnswer() compares count with question.answer.

  15. If correct โ†’ calls proceedToNextQuestion().
  16. If wrong โ†’ resets and retries (after 1s).
  17. Time is measured using firstShakeTime.

  18. Game Completion

  19. When all questions are done, endGame() is triggered from BaseGameFragment.


๐Ÿ”‘ Important Variables

Variable Purpose
count Current shake count.
wrongAttempts Tracks how many times the user failed before retrying.
answerChecked Prevents duplicate validation calls.
firstShakeTime Timestamp of first shake for time measurement.
isShakingAllowed Prevents multiple detections within 500ms.
shakeHandler Controls shake debounce.
gameHandler Controls answer validation timing.

๐ŸŽฏ Accessibility Support

  • Each question instruction (ringMeTv) has contentDescription set and announced via announce().
  • Each shake count (ringCount) is announced live.
  • Focus automatically moves to the instruction on the first question.

โš™๏ธ Extensibility

1. Change Shake Sensitivity

Adjust threshold in onSensorChanged():

if (acceleration > 10f) { ... } // More sensitive

2. Custom Shake Animation

Replace GIF in getGifResource():

override fun getGifResource(): Int = R.drawable.my_custom_shake_gif

3. Add Difficulty Levels

Modify shake threshold/time limit dynamically based on question difficulty.

4. Data Model (GameQuestion)

Ensure GameQuestion has:

expression: String
answer: Int
timeLimit: Double?

๐Ÿงช Testing Notes

  • Manual Testing

  • Verify shake counts are detected properly on different devices.

  • Check that accessibility announcements trigger correctly.
  • Test edge cases: 0 shakes, excessive shakes, timeouts.

  • Automated Testing

  • Use SensorManager mocks for shake detection.

  • Validate game flow with sample GameQuestion inputs.

๐Ÿ“Œ Example Question Flow

  1. App loads GameQuestion("Shake 3 times", 3, 10).
  2. Instruction announced: "Shake 3 times".
  3. Player shakes:

  4. Shake 1 โ†’ Count = 1

  5. Shake 2 โ†’ Count = 2
  6. Shake 3 โ†’ Count = 3 โ†’ Validation after 1.5s.
  7. Correct โ†’ Next question.