Create a stop watch or counter using broadcast and notification in foreground service in Android

This video shows the steps to create to a stop watch App which can also be used as a decreasing counter. In this App the user can set an initial value which is decreased until it reaches to 0. The decrements happen in Service class. Notification for this foreground service is also created in this App and thus the counter/ stop watch values can be seen in the notification areas as well.

For any query, suggestions or appreciations, we will be glad to hear from you at: programmerworld1990@gmail.com

Source Code:

package com.example.mystopwatchserviceclass;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import static android.Manifest.permission.FOREGROUND_SERVICE;

public class MainActivity extends AppCompatActivity {
private TextView textView;
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, new String[]{FOREGROUND_SERVICE}, PackageManager.PERMISSION_GRANTED);
textView = findViewById(R.id.textView);
editText = findViewById(R.id.editText);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(“Counter”);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Integer integerTime = intent.getIntExtra(“TimeRemaining”, 0);
textView.setText(integerTime.toString());
}
};
registerReceiver(broadcastReceiver, intentFilter);
}

public void startButton(View view){
Intent intentService = new Intent(this, myService.class);
Integer integerTimeSet = Integer.parseInt(editText.getText().toString());
intentService.putExtra(“TimeValue”, integerTimeSet);
startService(intentService);
}
}

package com.example.mystopwatchserviceclass;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import java.util.Timer;
import java.util.TimerTask;

public class myService extends Service {
private static final String CHANNEL_ID = “NotificationChannelID”;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

final Integer[] timeRemaining = {intent.getIntExtra(“TimeValue”, 0)};
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Intent intent1local = new Intent();
intent1local.setAction(“Counter”);
timeRemaining[0]–;
NotificationUpdate(timeRemaining[0]);
if (timeRemaining[0] LESS_THAN= 0){
timer.cancel();
}
intent1local.putExtra(“TimeRemaining”, timeRemaining[0]);
sendBroadcast(intent1local);
}
}, 0,1000);
return super.onStartCommand(intent, flags, startId);
}

public void NotificationUpdate(Integer timeLeft){
try {
Intent notificationIntent = new Intent(this, MainActivity.class);
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
final Notification[] notification = {new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(“My Stop Watch”)
.setContentText(“Time Remaing : ” + timeLeft.toString())
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.build()};
startForeground(1, notification[0]);
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, “My Counter Service”, NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(notificationChannel);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
package=”com.example.mystopwatchserviceclass”>

<uses-permission android:name=”android.permission.FOREGROUND_SERVICE”/>

<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round”
android:supportsRtl=”true”
android:theme=”@style/AppTheme”>
<service android:name=”.myService”/>
<activity android:name=”.MainActivity”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>

</manifest>

<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
xmlns:app=”http://schemas.android.com/apk/res-auto&#8221;
xmlns:tools=”http://schemas.android.com/tools&#8221;
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.MainActivity”>

<TextView
android:id=”@+id/textView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginStart=”100dp”
android:layout_marginTop=”200dp”
android:text=”@string/_0″
android:textSize=”36sp”
android:textStyle=”bold”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintRight_toRightOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />

<Button
android:id=”@+id/button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginStart=”100dp”
android:layout_marginTop=”100dp”
android:onClick=”startButton”
android:text=”@string/start” />

<EditText
android:id=”@+id/editText”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginStart=”100dp”
android:layout_marginTop=”50dp”
android:ems=”10″
android:hint=”@string/timer_value”
android:inputType=”textPersonName”
android:text=”@string/_0″
android:autofillHints=”” />

</RelativeLayout>

3 comments

  1. thank you for the tutorial, i would like to ask, how would you here implement a pause function, so where the user clicks the pause button the timer will be paused and can be resumed afterwards.

    1. I think using stopService() call for the intent will stop the “stopwatch” service class.

      To implement the pause functionality, before stopping the service just pass the parameter value back to the main class (from service class) and save it as a SharedPreferences in the App. A use case on shared preference can be found in below link:
      https://programmerworld.co/android/how-to-create-walking-step-counter-app-using-accelerometer-sensor-and-shared-preference-in-android/

      I hope the above helps.

      Good Luck
      Programmer World

  2. thank you for the fast reply, if i have understood you correctly, i should then override the onDestroy function in the service, is there any better way to do that, because i already use the onDestroy function in another context

Leave a Reply

%d bloggers like this: