Skip to content

Commit

Permalink
Updating hello-jnicallback to support large screen devices
Browse files Browse the repository at this point in the history
Timer does not restart on configuration changes and utilizes a ViewModel to preserve state. Button added to start and stop.
Small naming convention fix with stopTimer
  • Loading branch information
Matt Monasch authored and DanAlbert committed May 3, 2024
1 parent ece52f2 commit 6110460
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 32 deletions.
10 changes: 5 additions & 5 deletions hello-jniCallback/app/src/main/cpp/hello-jnicallback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,98 @@

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();
}

/*
* A function calling from JNI to update current timer
*/
@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());
}
});
}
Expand All @@ -75,5 +117,5 @@ public void run() {
}
public native String stringFromJNI();
public native void startTicks();
public native void StopTicks();
public native void stopTicks();
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
11 changes: 11 additions & 0 deletions hello-jniCallback/app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,16 @@
app:layout_constraintBottom_toBottomOf="@+id/activity_hello_jnicallback"
tools:layout_constraintBottom_creator="0" />

<Button
android:id="@+id/pauseBtn"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="32dp"
android:onClick="onPauseBtn"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tickView" />


</androidx.constraintlayout.widget.ConstraintLayout>
2 changes: 2 additions & 0 deletions hello-jniCallback/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<resources>
<string name="app_name">Hello-jniCallback</string>
<string name="pause">PAUSE</string>
<string name="resume">RESUME</string>
</resources>

0 comments on commit 6110460

Please sign in to comment.