Created
July 22, 2026 00:27
-
-
Save mouldybread/ff4a1c6970073944c032d4ed6c42f667 to your computer and use it in GitHub Desktop.
Tarkov Time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Display in game time on an android device, relies upon a font placed in /res/font | |
| package com.tpn.tarkovtime | |
| import android.app.Activity | |
| import android.graphics.Color | |
| import android.os.Bundle | |
| import android.os.Handler | |
| import android.os.Looper | |
| import android.view.View | |
| import android.view.WindowManager | |
| import android.widget.TextView | |
| import androidx.core.view.WindowCompat | |
| import androidx.core.view.WindowInsetsCompat | |
| import androidx.core.view.WindowInsetsControllerCompat | |
| import java.util.Calendar | |
| import java.util.TimeZone | |
| class MainActivity : Activity() { | |
| private lateinit var leftTimeView: TextView | |
| private lateinit var rightTimeView: TextView | |
| private lateinit var realTimeView: TextView | |
| private lateinit var blankOverlay: View | |
| private val handler = Handler(Looper.getMainLooper()) | |
| private var lastRealSecond = -1 | |
| private val updateRunnable = object : Runnable { | |
| override fun run() { | |
| updateTimes() | |
| handler.postDelayed(this, TICK_INTERVAL_MS) | |
| } | |
| } | |
| private val blankCycleRunnable = object : Runnable { | |
| override fun run() { | |
| blankScreen() | |
| handler.postDelayed(this, SIX_HOURS_MS) | |
| } | |
| } | |
| override fun onCreate(savedInstanceState: Bundle?) { | |
| super.onCreate(savedInstanceState) | |
| window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) | |
| setMaxBrightness() | |
| WindowCompat.setDecorFitsSystemWindows(window, false) | |
| val insetsController = WindowInsetsControllerCompat(window, window.decorView) | |
| insetsController.hide(WindowInsetsCompat.Type.systemBars()) | |
| insetsController.systemBarsBehavior = | |
| WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE | |
| setContentView(R.layout.activity_main) | |
| leftTimeView = findViewById(R.id.leftTime) | |
| rightTimeView = findViewById(R.id.rightTime) | |
| realTimeView = findViewById(R.id.realTime) | |
| blankOverlay = findViewById(R.id.blankOverlay) | |
| applyGlow(leftTimeView, Color.parseColor("#FF2A2A"), 25f) | |
| applyGlow(rightTimeView, Color.parseColor("#FF2A2A"), 25f) | |
| applyGlow(realTimeView, Color.parseColor("#883333"), 12f) | |
| } | |
| private fun setMaxBrightness() { | |
| val params = window.attributes | |
| params.screenBrightness = 1.0f | |
| window.attributes = params | |
| } | |
| private fun applyGlow(view: TextView, glowColor: Int, radius: Float) { | |
| view.setLayerType(TextView.LAYER_TYPE_SOFTWARE, null) | |
| view.setShadowLayer(radius, 0f, 0f, glowColor) | |
| } | |
| private fun blankScreen() { | |
| blankOverlay.visibility = View.VISIBLE | |
| handler.postDelayed({ | |
| blankOverlay.visibility = View.GONE | |
| }, BLANK_DURATION_MS) | |
| } | |
| override fun onResume() { | |
| super.onResume() | |
| handler.post(updateRunnable) | |
| handler.postDelayed(blankCycleRunnable, SIX_HOURS_MS) | |
| val insetsController = WindowInsetsControllerCompat(window, window.decorView) | |
| insetsController.hide(WindowInsetsCompat.Type.systemBars()) | |
| setMaxBrightness() | |
| } | |
| override fun onPause() { | |
| super.onPause() | |
| handler.removeCallbacks(updateRunnable) | |
| handler.removeCallbacks(blankCycleRunnable) | |
| } | |
| private fun updateTimes() { | |
| val utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC")) | |
| val utcMillisOfDay = utcCal.get(Calendar.HOUR_OF_DAY) * 3_600_000L + | |
| utcCal.get(Calendar.MINUTE) * 60_000L + | |
| utcCal.get(Calendar.SECOND) * 1000L + | |
| utcCal.get(Calendar.MILLISECOND) | |
| val millisInDay = 86_400_000L | |
| val russiaOffsetMillis = 3 * 3_600_000L | |
| val leftTarkovMillis = ((utcMillisOfDay * 7) + russiaOffsetMillis) % millisInDay | |
| val rightTarkovMillis = ((utcMillisOfDay * 7) + russiaOffsetMillis + 43_200_000L) % millisInDay | |
| leftTimeView.text = formatTime((leftTarkovMillis / 1000).toInt()) | |
| rightTimeView.text = formatTime((rightTarkovMillis / 1000).toInt()) | |
| val localCal = Calendar.getInstance() | |
| val localSecond = localCal.get(Calendar.SECOND) | |
| if (localSecond != lastRealSecond) { | |
| lastRealSecond = localSecond | |
| val localH = localCal.get(Calendar.HOUR_OF_DAY) | |
| val localM = localCal.get(Calendar.MINUTE) | |
| realTimeView.text = "Real: %02d:%02d:%02d".format(localH, localM, localSecond) | |
| } | |
| } | |
| private fun formatTime(seconds: Int): String { | |
| val h = seconds / 3600 | |
| val m = (seconds % 3600) / 60 | |
| val s = seconds % 60 | |
| return "%02d:%02d:%02d".format(h, m, s) | |
| } | |
| companion object { | |
| private const val SIX_HOURS_MS = 6 * 60 * 60 * 1000L | |
| private const val BLANK_DURATION_MS = 60_000L | |
| private const val TICK_INTERVAL_MS = 143L | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment