1 package net.osdn.gokigen.joggingtimer.stopwatch
3 import android.content.Intent
4 import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
5 import android.graphics.Color
6 import android.os.Bundle
7 import android.util.Log
8 import android.view.KeyEvent
9 import android.view.View
10 import android.widget.ImageButton
11 import android.widget.ListView
12 import android.widget.TextView
13 import android.widget.Toast
14 import androidx.appcompat.app.AppCompatActivity
15 import androidx.constraintlayout.widget.ConstraintLayout
16 import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
17 import androidx.core.widget.NestedScrollView
18 import androidx.wear.ambient.AmbientModeSupport
19 import net.osdn.gokigen.joggingtimer.R
20 import net.osdn.gokigen.joggingtimer.recordlist.ListActivity
21 import net.osdn.gokigen.joggingtimer.stopwatch.MyTimerCounter.ICounterStatusNotify
22 import net.osdn.gokigen.joggingtimer.stopwatch.MyTimerTrigger.ITimeoutReceiver
23 import net.osdn.gokigen.joggingtimer.stopwatch.graphview.LapTimeGraphView
24 import net.osdn.gokigen.joggingtimer.utilities.SelectReferenceViewModeDialog
25 import net.osdn.gokigen.joggingtimer.utilities.SelectReferenceViewModeDialog.SelectReferenceCallback
26 import net.osdn.gokigen.joggingtimer.utilities.TimeStringConvert
27 import java.text.SimpleDateFormat
29 import java.util.Locale
35 class MainActivity : AppCompatActivity(), IClickCallback, ITimeoutReceiver, ICounterStatusNotify, AmbientModeSupport.AmbientCallbackProvider, SelectReferenceCallback
37 private val controller: IWearableActivityControl = WearableActivityController()
38 private val counter = MyTimerCounter()
39 private var isCounterLapTime = true
40 private var isLaptimeView = true
41 private var pendingStart = false
42 private var currentLapCount = 0
43 private var currentReferenceId = 0
44 private var stopTrigger: ITimerStopTrigger? = null
49 override fun onCreate(savedInstanceState: Bundle?)
53 ///////// SHOW SPLASH SCREEN : call before super.onCreate() /////////
60 super.onCreate(savedInstanceState)
61 Log.v(TAG, "onCreate()")
65 setContentView(R.layout.activity_main)
66 controller.setup(this, this, counter)
75 val ambientController = AmbientModeSupport.attach(this)
76 ambientController.setAutoResumeEnabled(true)
85 private fun importReceivedIntent()
91 IntentSendImporter(this.applicationContext, intent).start()
92 val title = intent.getStringExtra(Intent.EXTRA_SUBJECT)
94 Toast.makeText(this, getString(R.string.data_imported) + title, Toast.LENGTH_SHORT).show()
95 //setResult(RESULT_OK, intent)
110 override fun onResume()
116 val action = intent.action
117 Log.v(TAG, "onResume() : $action")
118 var isStartTimer = false
124 if (Intent.ACTION_SEND == action)
126 val flags = intent.flags
127 val checkFlags = FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY // + FLAG_ACTIVITY_BROUGHT_TO_FRONT
128 Log.v(TAG, "INTENT : $intent")
129 if ((flags.and(checkFlags)) == 0)
131 Log.v(TAG, " IMPORT DATA ")
132 importReceivedIntent()
135 else if (action == "com.google.android.wearable.action.STOPWATCH")
139 else if (action == "vnd.google.fitness.TRACK")
141 if (intent.getStringExtra("actionStatus") == "ActiveActionStatus")
153 isLaptimeView = controller.displayMode
154 currentReferenceId = controller.referenceTimerSelection
155 controller.setupReferenceData()
165 override fun onPause()
168 Log.v(TAG, "onPause()")
175 public override fun onStart()
178 Log.v(TAG, "onStart()")
181 counter.setCallback(this)
182 controller.setupDatabase(this, false)
189 public override fun onStop()
192 Log.v(TAG, "onStop()")
193 stopTrigger?.forceStop()
194 controller.exitApplication(this)
200 private fun updateTimerLabel()
202 val timerCounter: ITimerCounter = counter
204 val insetLayout = findViewById<NestedScrollView>(R.id.top_layout)
205 val layout = findViewById<ConstraintLayout>(R.id.main_layout)
206 val btn1 = findViewById<ImageButton>(R.id.btn1)
207 val btn2 = findViewById<ImageButton>(R.id.btn2)
208 val btn3 = findViewById<ImageButton>(R.id.btn3)
209 updateMainSubCounter()
210 if (timerCounter.isStarted)
212 bgColor = Color.BLACK
213 insetLayout.setBackgroundColor(bgColor)
214 insetLayout.invalidate()
215 layout.setBackgroundColor(bgColor)
217 btn1.setImageResource(R.drawable.ic_flag_black_24dp)
218 btn1.setBackgroundColor(bgColor)
220 // チャタリング防止(ラップタイムとして、3秒以内は記録しないようボタンを消しておく)
221 val currentElapsedTime = timerCounter.currentElapsedTime
222 btn1.visibility = if (currentElapsedTime > 3000) View.VISIBLE else View.INVISIBLE
224 btn2.setImageResource(R.drawable.ic_stop_black_24dp)
225 btn2.setBackgroundColor(bgColor)
226 btn2.visibility = View.VISIBLE
228 btn3.setImageResource(R.drawable.ic_block_black_24dp)
229 btn3.setBackgroundColor(bgColor)
230 btn3.visibility = View.INVISIBLE
233 else if (timerCounter.isReset)
235 bgColor = Color.BLACK
236 insetLayout.setBackgroundColor(bgColor)
237 insetLayout.invalidate()
238 layout.setBackgroundColor(bgColor)
240 btn1.setImageResource(R.drawable.ic_play_arrow_black_24dp)
241 btn1.setBackgroundColor(bgColor)
242 btn1.visibility = View.VISIBLE
244 btn2.setImageResource(R.drawable.ic_format_list_bulleted_black_24dp)
245 btn2.setBackgroundColor(bgColor)
246 btn2.visibility = View.VISIBLE
248 btn3.setImageResource(R.drawable.ic_refresh_black_24dp)
249 btn3.setBackgroundColor(bgColor)
250 btn3.visibility = View.INVISIBLE
255 bgColor = Color.BLACK
256 insetLayout.setBackgroundColor(bgColor)
257 insetLayout.invalidate()
258 layout.setBackgroundColor(bgColor)
260 btn1.setImageResource(R.drawable.ic_play_arrow_black_24dp)
261 btn1.visibility = View.VISIBLE
262 btn1.setBackgroundColor(bgColor)
264 btn2.setImageResource(R.drawable.ic_format_list_bulleted_black_24dp)
265 btn2.visibility = View.VISIBLE
266 btn2.setBackgroundColor(bgColor)
268 btn3.setImageResource(R.drawable.ic_refresh_black_24dp)
269 btn3.visibility = View.VISIBLE
270 btn3.setBackgroundColor(bgColor)
276 override fun clickedCounter()
279 isCounterLapTime = !isCounterLapTime
285 override fun clickedBtn1()
294 private fun startTimer()
298 val timerCounter: ITimerCounter = counter
299 val graphView = findViewById<LapTimeGraphView>(R.id.graph_area)
300 if (timerCounter.isStarted)
302 Log.v(TAG, "startTimer() LAP TIME")
303 val currentElapsedTime = timerCounter.currentElapsedTime
304 if (currentElapsedTime > 3000) // チャタリング防止(ラップタイムとして、3秒以内は記録しないようにする)
307 val lapTime = timerCounter.timeStamp()
308 val refLapTime = timerCounter.getReferenceLapTime(currentLapCount)
309 val diffTime = if (refLapTime == 0L) 0 else currentElapsedTime - refLapTime
310 controller.vibrate(50)
311 controller.dataEntry.appendTimeData(lapTime)
312 controller.addTimeStamp(currentLapCount.toLong(), currentElapsedTime, diffTime)
313 graphView?.notifyLapTime()
316 Log.v(TAG, "startTimer() START")
317 controller.clearTimeStamp()
319 val trigger = MyTimerTrigger(this, 100, timerCounter)
322 stopTrigger = trigger
323 controller.timerStarted(true)
324 controller.vibrate(120)
326 val sdf1 = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
327 val title = sdf1.format(date)
328 val startTime = timerCounter.startTime
329 controller.dataEntry.createIndex(title, startTime)
330 graphView?.notifyStarted(startTime)
344 private fun stopTimer(): Boolean
349 val timerCounter: ITimerCounter = counter
350 if (timerCounter.isStarted)
353 controller.timerStarted(false)
354 controller.vibrate(120)
355 controller.dataEntry.finishTimeData(timerCounter.startTime, timerCounter.stopTime)
356 val lapCount = currentLapCount + 1
357 val currentElapsedTime = timerCounter.lastElapsedTime - timerCounter.getElapsedTime(currentLapCount)
358 val refLapTime = timerCounter.getReferenceLapTime(lapCount)
359 val diffTime = if (refLapTime == 0L) 0 else currentElapsedTime - refLapTime
360 controller.addTimeStamp(lapCount.toLong(), currentElapsedTime, diffTime)
362 val graphView = findViewById<LapTimeGraphView>(R.id.graph_area)
363 graphView?.notifyStopped()
377 override fun clickedBtn2()
379 if (!(counter as ITimerCounter).isStarted)
385 controller.vibrate(35)
393 override fun clickedBtn3()
395 val timerCounter: ITimerCounter = counter
396 if (!timerCounter.isStarted)
399 controller.vibrate(50)
400 controller.clearTimeStamp()
402 val graphView = findViewById<LapTimeGraphView>(R.id.graph_area)
403 graphView?.notifyReset()
408 override fun clickedArea()
410 Log.v(TAG, "clickedArea()")
413 override fun pushedBtn1(): Boolean
418 override fun pushedBtn2(): Boolean
423 override fun pushedBtn3(): Boolean
428 override fun pushedArea(): Boolean
433 val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(
436 val viewMode = preferences.getBoolean(
437 SelectReferenceViewModeDialog.PREF_KEY_DISPLAY_LAPGRAPHIC,
440 val selectionId = preferences.getInt(
441 SelectReferenceViewModeDialog.PREF_KEY_REFERENCE_TIME_SELECTION,
444 val callback: SelectReferenceCallback = this
447 // 基準値&表示モード設定ダイアログを表示する
449 SelectReferenceViewModeDialog.newInstance(viewMode, selectionId, callback)
450 val manager = supportFragmentManager
451 dialog.show(manager, "dialog")
452 } catch (e: Exception) {
456 } catch (e: Exception) {
466 override fun timeout()
470 runOnUiThread { updateTimerLabel() }
482 private fun updateMainSubCounter()
484 val main = findViewById<TextView>(R.id.main_counter)
485 val sub = findViewById<TextView>(R.id.sub_counter1)
486 val timerCounter: ITimerCounter = counter
487 val time1 = timerCounter.pastTime
488 val str1 = TimeStringConvert.getTimeString(time1)
489 var str2: CharSequence = ""
490 if (timerCounter.isStarted)
492 val time2 = timerCounter.currentElapsedTime
493 val lapCount = timerCounter.elapsedCount
494 if (time2 >= 100 &&(lapCount > 1))
496 str2 = "[" + lapCount + "] " + TimeStringConvert.getTimeString(time2)
499 if (str2.isNotEmpty() && this.isCounterLapTime)
518 private fun updateElapsedTimes()
522 updateElapsedTimesGraph()
526 updateElapsedTimesText()
534 private fun updateElapsedTimesGraph()
536 val view = findViewById<LapTimeGraphView>(R.id.graph_area)
544 private fun updateElapsedTimesText()
546 // Log.v(TAG, "updateElapsedTimesText()");
550 * Launch ListActivity
553 private fun launchListActivity()
555 Log.v(TAG, "launchListActivity()")
558 val intent = Intent(this, ListActivity::class.java)
559 startActivity(intent)
571 override fun onUserLeaveHint()
573 Log.v(TAG, "onUserLeaveHint() ")
574 // ハードキー(ホームボタン)が押されたとき、これがひろえるが...
581 override fun dispatchKeyEvent(event: KeyEvent): Boolean
583 Log.v(TAG, "dispatchKeyEvent() : " + event.action + " (" + event.keyCode + ")")
584 return super.dispatchKeyEvent(event)
591 override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean
593 Log.v(TAG, "onKeyDown() : " + event.action + " (" + event.keyCode + ")" + keyCode)
594 if (event.repeatCount == 0)
597 KeyEvent.KEYCODE_STEM_1 -> {
601 KeyEvent.KEYCODE_STEM_2 -> {
605 KeyEvent.KEYCODE_STEM_3 -> {
611 return super.onKeyDown(keyCode, event)
618 override fun counterStatusChanged(forceStartTimer: Boolean)
624 val graphView = findViewById<LapTimeGraphView>(R.id.graph_area)
625 val trigger = MyTimerTrigger(this, 100, counter)
627 stopTrigger = trigger
628 graphView?.notifyLapTime()
643 reloadLapTimeList(forceStartTimer)
646 changeGraphicView(isLaptimeView)
657 private fun reloadLapTimeList(forceStartTimer: Boolean)
659 if (!forceStartTimer)
664 // Adapter と TimerCounterの整合性を確認
667 val lapTimeList: List<Long> = (counter as ITimerCounter).lapTimeList
668 val lapCount = lapTimeList.size
669 val listCount = controller.lapTimeCount
670 if (lapCount != listCount)
672 Log.v(TAG, "LAP COUNT IS MISMATCH!!! lap:$lapCount vs list:$listCount")
674 controller.clearTimeStamp()
675 var prevTime = lapTimeList[0]
676 for (lapTime in lapTimeList)
679 if (prevTime != lapTime)
681 val refLapTime = counter.getReferenceLapTime(index - 1)
682 val curLapTime = lapTime - prevTime
683 val calcRefLapTime = if (refLapTime == 0L) 0 else curLapTime - refLapTime
684 controller.addTimeStamp((index - 1).toLong(), curLapTime, calcRefLapTime)
688 currentLapCount = lapCount - 1
701 private fun changeGraphicView(isGraphics: Boolean)
705 val graphView = findViewById<LapTimeGraphView>(R.id.graph_area)
706 val listView = findViewById<ListView>(R.id.laptime_list_area)
709 graphView.setITimerCounter(counter)
710 graphView.visibility = View.VISIBLE
711 listView.visibility = View.INVISIBLE
715 graphView.visibility = View.INVISIBLE
716 listView.visibility = View.VISIBLE
718 //controller.vibrate(30);
726 override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback
728 return object : AmbientModeSupport.AmbientCallback() {
729 override fun onEnterAmbient(ambientDetails: Bundle) {
730 Log.v(TAG, "onEnterAmbient()")
735 override fun selectedReferenceViewMode(referenceId: Int, viewMode: Int)
737 isLaptimeView = viewMode != 0
738 currentReferenceId = referenceId
739 controller.displayMode = isLaptimeView
740 controller.referenceTimerSelection = currentReferenceId
741 controller.setupReferenceData()
742 Log.v(TAG, "pushedArea() : $isLaptimeView REF: $currentReferenceId")
745 reloadLapTimeList(true)
748 changeGraphicView(isLaptimeView)
757 private val TAG = MainActivity::class.java.simpleName
758 //private const val REQUEST_CODE_PERMISSIONS = 10
759 //private val REQUIRED_PERMISSIONS = arrayOf(
760 // Manifest.permission.VIBRATE,
761 // Manifest.permission.WAKE_LOCK,