diff --git a/hello-jniCallback/app/src/main/cpp/hello-jnicallback.c b/hello-jniCallback/app/src/main/cpp/hello-jnicallback.c index 86738e720..e644a6e8b 100644 --- a/hello-jniCallback/app/src/main/cpp/hello-jnicallback.c +++ b/hello-jniCallback/app/src/main/cpp/hello-jnicallback.c @@ -278,11 +278,11 @@ Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv *env, * we need to hold and make sure our native thread has finished before return * for a clean shutdown. The caller is from onPause */ -JNIEXPORT void JNICALL Java_com_example_hellojnicallback_MainActivity_StopTicks( - JNIEnv *env, jobject instance) { - pthread_mutex_lock(&g_ctx.lock); - g_ctx.done = 1; - pthread_mutex_unlock(&g_ctx.lock); +JNIEXPORT void JNICALL +Java_com_example_hellojnicallback_MainActivity_stopTicks(JNIEnv *env, jobject instance) { + pthread_mutex_lock(&g_ctx.lock); + g_ctx.done = 1; + pthread_mutex_unlock(&g_ctx.lock); // waiting for ticking thread to flip the done flag struct timespec sleepTime; diff --git a/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java b/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java index cff89cb39..2c8b39fcc 100644 --- a/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java +++ b/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java @@ -17,33 +17,86 @@ import androidx.annotation.Keep; import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory; + import android.os.Bundle; +import android.view.View; +import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { - int hour = 0; - int minute = 0; - int second = 0; + MainViewModel model; TextView tickView; + TextView helloJniMsg; + Button pauseBtn; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - tickView = (TextView) findViewById(R.id.tickView); + tickView = findViewById(R.id.tickView); + helloJniMsg = findViewById(R.id.hellojniMsg); + pauseBtn = findViewById(R.id.pauseBtn); + + // Fetch the ViewModel, or have one instantiated + model = new ViewModelProvider(this, + AndroidViewModelFactory.getInstance(this.getApplication()) + ).get(MainViewModel.class); + + // if the timer has yet to be started, toggle it's state to trigger it's first run + // otherwise, and only if it was previously running, start the jni thread for tick callbacks + if(!model.started) { + model.started = true; + toggleTimerState(); + } else { + if(model.running) { + startTicks(); + } + } + + setText(); } + + /* + * onDestroy gets called for configuration changes. + * We make sure that the jni context cleans up so we don't lose track of threads. + */ @Override - public void onResume() { - super.onResume(); - hour = minute = second = 0; - ((TextView)findViewById(R.id.hellojniMsg)).setText(stringFromJNI()); - startTicks(); + protected void onDestroy(){ + super.onDestroy(); + if(model.running) { + stopTicks(); + } } - @Override - public void onPause () { - super.onPause(); - StopTicks(); + private void toggleTimerState() { + model.running = !model.running; + setText(); + if(model.running){ + model.resetTimer(); + startTicks(); + } else { + stopTicks(); + } + } + + private void setText() { + helloJniMsg.setText(stringFromJNI()); + tickView.setText(model.time()); + + if(model.running) { + pauseBtn.setText(R.string.pause); + } else { + pauseBtn.setText(R.string.resume); + } + + + } + + public void onPauseBtn(View v){ + toggleTimerState(); } /* @@ -51,22 +104,11 @@ public void onPause () { */ @Keep private void updateTimer() { - ++second; - if(second >= 60) { - ++minute; - second -= 60; - if(minute >= 60) { - ++hour; - minute -= 60; - } - } + model.updateTimer(); runOnUiThread(new Runnable() { @Override public void run() { - String ticks = "" + MainActivity.this.hour + ":" + - MainActivity.this.minute + ":" + - MainActivity.this.second; - MainActivity.this.tickView.setText(ticks); + MainActivity.this.tickView.setText(model.time()); } }); } @@ -75,5 +117,5 @@ public void run() { } public native String stringFromJNI(); public native void startTicks(); - public native void StopTicks(); + public native void stopTicks(); } diff --git a/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainViewModel.java b/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainViewModel.java new file mode 100644 index 000000000..839b098e7 --- /dev/null +++ b/hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainViewModel.java @@ -0,0 +1,31 @@ +package com.example.hellojnicallback; + +import androidx.lifecycle.ViewModel; + +public class MainViewModel extends ViewModel { + private int hour = 0; + private int minute = 0; + private int second = 0; + public boolean started = false; + public boolean running = false; + + public void updateTimer() { + ++second; + if(second >= 60) { + ++minute; + second -= 60; + if(minute >= 60) { + ++hour; + minute -= 60; + } + } + } + + public void resetTimer() { + hour = minute = second = 0; + } + + public String time() { + return hour + ":" + minute + ":" + second; + } +} diff --git a/hello-jniCallback/app/src/main/res/layout/activity_main.xml b/hello-jniCallback/app/src/main/res/layout/activity_main.xml index 4f5f3e2c0..774a5f9f3 100644 --- a/hello-jniCallback/app/src/main/res/layout/activity_main.xml +++ b/hello-jniCallback/app/src/main/res/layout/activity_main.xml @@ -43,5 +43,16 @@ app:layout_constraintBottom_toBottomOf="@+id/activity_hello_jnicallback" tools:layout_constraintBottom_creator="0" /> +