I have some troubles with creating a way to send notifications foreground when the timer hits 00:00.
I mean, i want that when the timer ends, it sends a notification event if the app is closed.
I already found a way to show notifications and to make a timer who works even if the app is closed.
But when i put the function to send notification at the end of the timer it only works when the app is opened.
There is my MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
notificationManager = NotificationManagerCompat.from(this);
mTextViewCountDown = findViewById(R.id.timerTv);
mButtonStartPause = findViewById(R.id.btn_start_pause);
mButtonReset = findViewById(R.id.btn_reset);
mButtonStartPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTimerRunning) {
pauseTimer();
} else {
startTimer();
}
}
});
mButtonReset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
resetTimer();
}
});
}
private void startTimer() {
mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimeLeftInMillis=0;
updateCountDownText();
mTimerRunning = false;
updateButtons();
Notification notification = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_money)
.setContentTitle("Test 1")
.setContentText("Important Message")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.build();
notificationManager.notify(1, notification);
}
}.start();
mTimerRunning = true;
updateButtons();
}
private void pauseTimer() {
mCountDownTimer.cancel();
mTimerRunning = false;
updateButtons();
}
private void resetTimer() {
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
private void updateButtons() {
if (mTimerRunning) {
mButtonReset.setVisibility(View.INVISIBLE);
mButtonStartPause.setText("Pause");
} else {
mButtonStartPause.setText("Start");
if (mTimeLeftInMillis < 1000) {
mButtonStartPause.setVisibility(View.INVISIBLE);
} else {
mButtonStartPause.setVisibility(View.VISIBLE);
}
if (mTimeLeftInMillis < START_TIME_IN_MILLIS) {
mButtonReset.setVisibility(View.VISIBLE);
} else {
mButtonReset.setVisibility(View.INVISIBLE);
}
}
}
#Override
public void onStop() {
super.onStop();
SharedPreferences prefs = getSharedPreferences("pref", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", mEndTime);
editor.apply();
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
}
#Override
public void onStart() {
super.onStart();
SharedPreferences prefs = getSharedPreferences("pref", MODE_PRIVATE);
mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
mTimerRunning = prefs.getBoolean("timerRunning", false);
updateCountDownText();
updateButtons();
if (mTimerRunning) {
mEndTime = prefs.getLong("endTime", 0);
mTimeLeftInMillis = mEndTime - System.currentTimeMillis();
if (mTimeLeftInMillis < 0) {
mTimeLeftInMillis = 0;
mTimerRunning = false;
updateCountDownText();
updateButtons();
} else {
startTimer();
}
}
}
}
App Java Class
public class App extends Application {
public static final String CHANNEL_1_ID = "channel1";
#Override
public void onCreate() {
super.onCreate();
createNotificationChannels();
}
private void createNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel1 = new NotificationChannel(
CHANNEL_1_ID,
"Channel 1",
NotificationManager.IMPORTANCE_HIGH
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel1);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.krisix.notificationtest">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".App"
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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ExampleService"/>
</application>
</manifest>
Thank you for your help !
Have a nice day
Krisix
Thank you for your help sorry i'm a beginner so i'm not sure i understand all the things you told me.
So do you mean something like this ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
notificationManager = NotificationManagerCompat.from(this);
mTextViewCountDown = findViewById(R.id.timerTv);
mButtonStartPause = findViewById(R.id.btn_start_pause);
mButtonReset = findViewById(R.id.btn_reset);
mButtonStartPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTimerRunning) {
pauseTimer();
} else {
startTimer();
}
}
});
mButtonReset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
resetTimer();
}
});
}
private void startTimer() {
mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimeLeftInMillis=0;
updateCountDownText();
mTimerRunning = false;
updateButtons();
if(mTimeLeftInMillis==0){
callNotification();
}
}
}.start();
mTimerRunning = true;
updateButtons();
}
private void pauseTimer() {
mCountDownTimer.cancel();
mTimerRunning = false;
updateButtons();
}
private void resetTimer() {
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
private void updateButtons() {
if (mTimerRunning) {
mButtonReset.setVisibility(View.INVISIBLE);
mButtonStartPause.setText("Pause");
} else {
mButtonStartPause.setText("Start");
if (mTimeLeftInMillis < 1000) {
mButtonStartPause.setVisibility(View.INVISIBLE);
} else {
mButtonStartPause.setVisibility(View.VISIBLE);
}
if (mTimeLeftInMillis < START_TIME_IN_MILLIS) {
mButtonReset.setVisibility(View.VISIBLE);
} else {
mButtonReset.setVisibility(View.INVISIBLE);
}
}
}
#Override
public void onStop() {
super.onStop();
SharedPreferences prefs = getSharedPreferences("pref", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", mEndTime);
editor.apply();
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
}
#Override
public void onStart() {
super.onStart();
SharedPreferences prefs = getSharedPreferences("pref", MODE_PRIVATE);
mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
mTimerRunning = prefs.getBoolean("timerRunning", false);
updateCountDownText();
updateButtons();
if (mTimerRunning) {
mEndTime = prefs.getLong("endTime", 0);
mTimeLeftInMillis = mEndTime - System.currentTimeMillis();
if (mTimeLeftInMillis < 0) {
mTimeLeftInMillis = 0;
mTimerRunning = false;
updateCountDownText();
updateButtons();
} else {
startTimer();
}
}
}
public void callNotification(){
Notification notification = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_money)
.setContentTitle("Test 1")
.setContentText("Important Message")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.build();
notificationManager.notify(1, notification);
}
}
Related
Hello so I have a App about a fact and tip each 24 hours it displays a fact or tip!
I am pretty new to Android studio anyways to keep track of the fact and tip the user is in I used a variabe "timing" in the start timer i put when the mTimeLeftInMillis == 0 then make timing = 1 and if timing == 1 then do that but ya for that it's not the case!
when the user leaves the timing variable resets and goes back to 124!
Could someone please help me! I tried to do shared perferences in it but It didn't work!
here is my java code!
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final long START_TIME_IN_MILLIS = 30000;
Button tip;
TextView texttip;
TextView textfact;
Button next;
Button back;
private TextView mTextViewCountDown;
private Button mButtonStartPause;
private Button mButtonStart;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis;
private long mEndTime;
private long timing = 124;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewCountDown = findViewById(R.id.text_view_countdown);
mButtonStartPause = findViewById(R.id.button_start_pause);
next = (Button)findViewById(R.id.next);
next.setOnClickListener(this);
back = (Button)findViewById(R.id.back);
back.setOnClickListener(this);
mButtonStart = findViewById(R.id.tip);
tip = (Button) findViewById(R.id.tip);
texttip = (TextView)findViewById(R.id.texttip);
textfact = (TextView)findViewById(R.id.textfact);
mButtonStartPause.setOnClickListener((new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mTimerRunning) {
mButtonStartPause.setText("fact ");
} else {
startTimer();
}
}
}));
mButtonStart.setOnClickListener((new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mTimerRunning) {
mButtonStart.setText("Tip");
} else {
startTimer();
}
}
}));
}
#Override
public void onClick(View view) {
if(view.getId() == R.id.next){
tip.setVisibility(view.INVISIBLE);
mButtonStartPause.setVisibility(View.INVISIBLE);
mButtonStart.setVisibility(View.INVISIBLE);
textfact.setVisibility(View.INVISIBLE);
texttip.setVisibility(View.INVISIBLE);
mTextViewCountDown.setVisibility(View.INVISIBLE);
next.setVisibility(View.INVISIBLE);
back.setVisibility(View.VISIBLE);
}
if (view.getId() == R.id.back){
tip.setVisibility(View.VISIBLE);
mButtonStart.setVisibility(View.VISIBLE);
mButtonStartPause.setVisibility(View.VISIBLE);
textfact.setVisibility(View.VISIBLE);
texttip.setVisibility(View.VISIBLE);
mTextViewCountDown.setVisibility(View.VISIBLE);
next.setVisibility(View.VISIBLE);
back.setVisibility(View.INVISIBLE);
}
}
private void startTimer() {
if (timing == 5) {
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("Makeup was invented by egypt");
texttip.setText("Spend time with a loved one");
} else{
mButtonStartPause.setText("fact ");
}
if (timing == 4) {
timing = 5;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("The US flag was designed by a student");
texttip.setText("Its okay to make mistakes because you will learn from them");
} else{
mButtonStartPause.setText("fact ");
}
if (timing == 3) {
timing = 4;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("DID YOU KNOW THAT SCOTLAND HAS 421 WORDS FOR SNOW!!!");
texttip.setText("Don't compare your self to others!");
} else{
mButtonStartPause.setText("fact ");
}
if (timing == 2) {
timing = 3;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("There is no q in all 50 states of US!");
texttip.setText("Do what you live. The purpose of life is to be happy!");
} else{
mButtonStartPause.setText("fact ");
}
if (timing == 1) {
timing = 2;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("The phillipines has about 7,641 islands!!");
texttip.setText("Develop good habits! Like running outside could benefit you and your mental health and your body by alot!");
} else{
mButtonStartPause.setText("fact ");
}
if (mTimeLeftInMillis == 0 && timing == 124) {
timing = 1;
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
updateButtons();
textfact.setText("Sudan has the most pyramids in the world");
texttip.setText("Look for knowledge not results");
textfact.setVisibility(View.VISIBLE);
texttip.setVisibility(View.VISIBLE);
} else{
mButtonStartPause.setText("fact ");
}
mEndTime = System.currentTimeMillis() + mTimeLeftInMillis;
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning= false;
updateButtons();
}
}.start();
mTimerRunning = true;
updateButtons();
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
private void updateButtons() {
if(mTimerRunning){
mButtonStartPause.setText("fact");
}else {
mButtonStartPause.setText("fact");
if (mTimeLeftInMillis < 1000) {
mButtonStartPause.setVisibility(View.VISIBLE);
} else {
mButtonStartPause.setVisibility(View.VISIBLE);
}
}
}
#Override
protected void onStop() {
super.onStop();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("millisLeft", mTimeLeftInMillis);
editor.putBoolean("timerRunning", mTimerRunning);
editor.putLong("endTime", mEndTime);
editor.apply();
}
#Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
mTimeLeftInMillis = prefs.getLong("millisLeft", START_TIME_IN_MILLIS);
mTimerRunning = prefs.getBoolean("timerRunning", false);
updateCountDownText();
updateButtons();
if (mTimerRunning) {
mEndTime = prefs.getLong("endTime", 0);
mTimeLeftInMillis = mEndTime - System.currentTimeMillis();
if (mTimeLeftInMillis < 0) {
mTimeLeftInMillis = 0;
mTimerRunning = false;
updateCountDownText();
updateButtons();
} else{
startTimer();
}
}
}
}
I tried making two timers and the other timer will save it because i know how to do shared preferences on timers but not on stuff like that but it didn't work also because errors started coming!
I wanted the timing thing to save.
Here is my fully functional code in which when I press the button, the button gets disabled and the countdown timer gets started and whenever it gets over button gets enabled. My problem is that if I leave that activity the process resets.
My question is how that can be done in the background so even if I close the application the timer runs in the background?
package com.mycompany.myapp;
import android.app.*;
import android.os.*;
import android.widget.*;
import android.view.View.*;
import android.view.*;
public class MainActivity extends Activity {
Button btnCountdown;
TextView tvCountdown;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnCountdown = findViewById(R.id.btnCountdown);
tvCountdown = findViewById(R.id.tvCountdown);
btnCountdown.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Timer();
btnCountdown.setEnabled(false);
}
});
}
private void Timer() {
new CountDownTimer(30*1000,1000) {
#Override
public void onTick(long millisUntilFinished) {
long second = (millisUntilFinished / 1000) % 60;
long minutes = (millisUntilFinished / (1000*60)) % 60;
tvCountdown.setText(minutes + ":" + second);
}
#Override
public void onFinish() {
tvCountdown.setText("Fin");
btnCountdown.setEnabled(true);
}
}.start();
}
}
Add to your AndroidManifest.xml
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
BroadcastReceiver.java
public class BroadcastReceiver extends AppCompatActivity {
TextView tvTimer, tvTimerRunningState, tvTimerFinishedState;
private static final String TAG = "CountdownTimer";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast_receiver);
}
public void handleStartTimer(View view) {
Intent intent = new Intent(this, BroadcastService.class);
intent.putExtra("inputExtra", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, intent);
} else {
this.startService(intent);
}
Log.i(TAG, "timerStarted");
}
public void handleCancelTimer (View view) {
Intent intent = new Intent(this, BroadcastService.class);
stopService(intent);
}
/* CountDown */
final private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateGUI(intent);
}
};
#Override
public void onResume() {
super.onResume();
registerReceiver(broadcastReceiver, new IntentFilter(BroadcastService.COUNTDOWN_BR));
Log.i(TAG, "Registered broadcast receiver");
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
Log.i(TAG, "Unregistered broadcast receiver");
}
#Override
public void onStop() {
try {
unregisterReceiver(broadcastReceiver);
} catch (Exception e) {
// Receiver was probably already stopped in onPause()
}
super.onStop();
}
private void updateGUI(Intent intent) {
if (intent.getExtras() != null) {
long millisUntilFinished = intent.getLongExtra("countdown", 0);
long seconds = (millisUntilFinished / 1000) % 60;
long minutes = (millisUntilFinished / (1000*60)) % 60;
long hours = (millisUntilFinished / (1000*60*60)) % 60;
String time = (hours + " : " + minutes + " : " + seconds);
tvTimer = findViewById(R.id.tvTimer);
tvTimer.setText(time);
boolean countdownTimerRunning = intent.getBooleanExtra("countdownTimerRunning", false);
tvTimerRunningState = findViewById(R.id.tvTimerRunningState);
if (countdownTimerRunning) {
tvTimerRunningState.setText("CountdownTimerRunning");
} else {
tvTimer.setText("0 : 0 : 0");
tvTimerRunningState.setText("CountdownTimerNotRunning");
}
boolean countdownTimerFinished = intent.getBooleanExtra("countdownTimerFinished", false);
tvTimerFinishedState = findViewById(R.id.tvTimerFinishedState);
if (countdownTimerFinished) {
tvTimerFinishedState.setText("Finished");
} else {
tvTimerFinishedState.setText("Unfinished");
}
}
}
activity_broadcast_receiver.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="#+id/btnStartJob"
android:onClick="handleStartTimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Timer" />
<Button
android:id="#+id/btnStopJob"
android:onClick="handleCancelTimer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Cancel Timer" />
<TextView
android:id="#+id/tvTimer"
android:text="0 : 0 : 0"
android:gravity="center"
android:textSize="30sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tvTimerFinishedState"
android:gravity="center"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tvTimerRunningState"
android:gravity="center"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
BroadcastService.java
public class BroadcastService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
private final static String TAG = "BroadcastService";
public static final String COUNTDOWN_BR = "your.package.name";
Intent bi = new Intent(COUNTDOWN_BR);
CountDownTimer cdt = null;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Starting timer...");
cdt = new CountDownTimer(30000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.i(TAG, "Countdown seconds remaining: " + millisUntilFinished / 1000);
bi.putExtra("countdown", millisUntilFinished);
bi.putExtra("countdownTimerRunning", true);
bi.putExtra("countdownTimerFinished", false);
sendBroadcast(bi);
}
#Override
public void onFinish() {
Log.i(TAG, "Timer finished");
bi.putExtra("countdownTimerFinished", true);
sendBroadcast(bi);
stopForeground(true);
stopSelf();
}
}; cdt.start();
}
#Override
public void onDestroy() {
cdt.cancel();
Log.i(TAG, "Timer cancelled");
bi.putExtra("countdownTimerRunning", false);
sendBroadcast(bi);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
/* Notification */
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, BroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
/* NotificationBuilder */
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
return START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent arg0) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
See I'm trying to get User input for time and using the user input trying to run the CountDownTimer function in Android studio 4.2.2
The problem is :-
case-1
when I pass Variable name in place of millisInFuture attribute of countDown timer function and trying to set textview accordingly , the TextView doesn't get set up anything.
public void timer() {
CountDownTimer countDownTimer = new CountDownTimer(**timeValueIntent**, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// mediaPlayer.setLooping(true);
//mediaPlayer.start();
timerValueTextView.setText(String.valueOf(millisUntilFinished / 1000) + "s");
}
#Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "Timed out", Toast.LENGTH_SHORT).show();
restartButton.setVisibility(View.VISIBLE);
restartButton.setEnabled(true);
quitButton.setVisibility(View.VISIBLE);
setBtnCond(true);
//mediaPlayer.stop();
}
}.start();
}`
case-2
But when I pass int value like 1000 etc in millisInFuture attribute of CountDownTimer and set up the textView , it gets successfully set up.
public void timer() {
CountDownTimer countDownTimer = new CountDownTimer(**300000**, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// mediaPlayer.setLooping(true);
//mediaPlayer.start();
timerValueTextView.setText(String.valueOf(millisUntilFinished / 1000) + "s");
}
#Override
public void onFinish() {
Toast.makeText(getApplicationContext(), "Timed out", Toast.LENGTH_SHORT).show();
restartButton.setVisibility(View.VISIBLE);
restartButton.setEnabled(true);
quitButton.setVisibility(View.VISIBLE);
setBtnCond(true);
//mediaPlayer.stop();
}
}.start();
}`
Can anyone please help to let me pass variable name instead of a hardcoded integer value in MillisInFuture attribute of CountDownTimer function.!!?
`
I have some source code similar to your questions just implement your project.
Init Variables
private static final long START_TIME_IN_MILLIS = 600000;
private TextView mTextViewCountDown;
private Button mButtonStartPause;
private Button mButtonReset;
private CountDownTimer mCountDownTimer;
private boolean mTimerRunning;
private long mTimeLeftInMillis = START_TIME_IN_MILLIS;
onCreate
//Init
mTextViewCountDown = findViewById(R.id.text_view_countdown);
mButtonStartPause = findViewById(R.id.button_start_pause);
mButtonReset = findViewById(R.id.button_reset);
mButtonStartPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTimerRunning) {
pauseTimer(); //pauseFunction
} else {
startTimer(); //StartFunction
}
}
});
mButtonReset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
resetTimer(); // resetFunction
}
});
updateCountDownText(); //updateEverySecond
startTimer()
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
mButtonStartPause.setText("Start");
mButtonStartPause.setVisibility(View.INVISIBLE);
mButtonReset.setVisibility(View.VISIBLE);
}
}.start();
mTimerRunning = true;
mButtonStartPause.setText("pause");
mButtonReset.setVisibility(View.INVISIBLE);
pauseTimer()
mCountDownTimer.cancel();
mTimerRunning = false;
mButtonStartPause.setText("Start");
mButtonReset.setVisibility(View.VISIBLE);
resetTimer()
mTimeLeftInMillis = START_TIME_IN_MILLIS;
updateCountDownText();
mButtonReset.setVisibility(View.INVISIBLE);
mButtonStartPause.setVisibility(View.VISIBLE);
updateCountDownText()
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
and Finally XML
<TextView
android:id="#+id/text_view_countdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="00:00"
android:textColor="#android:color/black"
android:textSize="60sp" />
<Button
android:id="#+id/button_start_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_view_countdown"
android:layout_centerHorizontal="true"
android:text="start" />
<Button
android:id="#+id/button_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_view_countdown"
android:layout_marginStart="11dp"
android:layout_toEndOf="#+id/button_start_pause"
android:text="reset"
android:visibility="invisible"
tools:visibility="visible" />
I hope you are all well. I've been having trouble with creating a notification service.
I have an audio app with recyclerviews and it's adapter class containing the viewholders. From the onBindviewholder I created an onclicklistener method that opens a player activity.
What I would like to happen is when you click on any item of the recyclerview, it starts the audio together with the foreground notification.
Please give your answers in written code as I am a novice in code jargon.
Thanks in advance.
Here's my code :
Player activity
public class Player extends AppCompatActivity implements MediaPlayer.OnCompletionListener {
TextView song_name, duration_played, total_duration;
ImageView nextbtn,prevbtn,shufflebtn,repeatbtn;
SeekBar seekBar;
FloatingActionButton playpausebtn;
Uri uri;
int position=-1;
int finalTime;
private cardhelper currentItem;
static MediaPlayer mMediaplayer;
static List<cardhelper>macam = new ArrayList<>();
private Handler handler = new Handler();
private Thread playThread, prevThread,nextThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
initViews();
getIntentMethod();
song_name.setText(macam.get(position).getSurah());
mMediaplayer.setOnCompletionListener(this);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mMediaplayer!=null && fromUser){
mMediaplayer.seekTo(progress * 1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
duration_played.setText(formattedTime(mCurrentposition));
finalTime = mMediaplayer.getDuration()/1000;
total_duration.setText(formattedTime(finalTime));
}
handler.postDelayed(this, 1000);
}
});
shufflebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(shuffleboolean){
shuffleboolean=false;
shufflebtn.setImageResource(R.drawable.ic_shuffle);
}else{
shuffleboolean=true;
shufflebtn.setImageResource(R.drawable.ic_shuffle_on);
}
}
});
repeatbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(repeatBoolean){
repeatBoolean=false;
repeatbtn.setImageResource(R.drawable.ic_repeat);
}else{
repeatBoolean=true;
repeatbtn.setImageResource(R.drawable.ic_repeat_on);
}
}
});
}
#Override
protected void onResume() {
playThreadbtn();
nextThreadbtn();
prevThreadbtn();
super.onResume();
}
private void playThreadbtn() {
playThread= new Thread(){
#Override
public void run() {
super.run();
playpausebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playpausebtnClicked();
}
});
}
};
playThread.start();
}
private void playpausebtnClicked() {
if(mMediaplayer.isPlaying()){
playpausebtn.setImageResource(R.drawable.ic_play);
mMediaplayer.pause();
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
}else{
playpausebtn.setImageResource(R.drawable.ic_baseline_pause_24);
mMediaplayer.start();
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
}
}
private void nextThreadbtn() {
nextThread= new Thread(){
#Override
public void run() {
super.run();
nextbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
nextbtnClicked();
}
});
}
};
nextThread.start();
}
private void nextbtnClicked() {
if(mMediaplayer.isPlaying()){
mMediaplayer.stop();
mMediaplayer.release();
if(shuffleboolean && !repeatBoolean){
position= getRandom(macam.size() - 1);
}
else if (! shuffleboolean && ! repeatBoolean){
position=((position + 1)% macam.size());
}
//else position will be position..
int cardhelper= macam.get(position).getAudio();
mMediaplayer= MediaPlayer.create(getApplicationContext(), cardhelper);
song_name.setText(macam.get(position).getSurah());
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
mMediaplayer.setOnCompletionListener(this);
playpausebtn.setBackgroundResource(R.drawable.ic_baseline_pause_24);
mMediaplayer.start();
}else {
mMediaplayer.stop();
mMediaplayer.release();
if(shuffleboolean && !repeatBoolean){
position= getRandom(macam.size() - 1);
}
else if (! shuffleboolean && ! repeatBoolean){
position=((position + 1)% macam.size());
}
int cardhelper= macam.get(position).getAudio();
mMediaplayer= MediaPlayer.create(getApplicationContext(), cardhelper);
song_name.setText(macam.get(position).getSurah());
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
mMediaplayer.setOnCompletionListener(this);
playpausebtn.setBackgroundResource(R.drawable.ic_play);
}
}
private int getRandom(int i) {
Random random = new Random();
return random.nextInt(i+ 1);
}
private void prevThreadbtn() {
prevThread= new Thread(){
#Override
public void run() {
super.run();
prevbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prevbtnClicked();
}
});
}
};
prevThread.start();
}
private void prevbtnClicked() {
if(mMediaplayer.isPlaying()){
mMediaplayer.stop();
mMediaplayer.release();
position=((position-1) < 0 ? (macam.size() -1 ): (position - 1));
int cardhelper= macam.get(position).getAudio();
mMediaplayer= MediaPlayer.create(getApplicationContext(), cardhelper);
song_name.setText(macam.get(position).getSurah());
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
mMediaplayer.setOnCompletionListener(this);
playpausebtn.setBackgroundResource(R.drawable.ic_baseline_pause_24);
mMediaplayer.start();
}else {
mMediaplayer.stop();
mMediaplayer.release();
position=((position-1) < 0 ? (macam.size() -1 ): (position - 1));
int cardhelper= macam.get(position).getAudio();
mMediaplayer= MediaPlayer.create(getApplicationContext(), cardhelper);
song_name.setText(macam.get(position).getSurah());
seekBar.setMax(mMediaplayer.getDuration()/1000);
Player.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if(mMediaplayer!=null){
int mCurrentposition = mMediaplayer.getCurrentPosition()/1000;
seekBar.setProgress(mCurrentposition);
}
handler.postDelayed(this, 1000);
}
});
mMediaplayer.setOnCompletionListener(this);
playpausebtn.setBackgroundResource(R.drawable.ic_play);
}
}
private String formattedTime(int mCurrentposition) {
String totalout = "";
String totalNew = "";
String seconds = String.valueOf(mCurrentposition % 60);
String minutes = String.valueOf(mCurrentposition / 60);
totalout = minutes + ":" + seconds;
totalNew = minutes + ":" + "0" + seconds;
if(seconds.length() == 1){
return totalNew;
}
else {
return totalout;
}
}
private void getIntentMethod() {
position= getIntent().getIntExtra("position",-1);
macam=cardalbums;
macam=malbie;
if(macam!=null ){
playpausebtn.setImageResource(R.drawable.ic_baseline_pause_24);
currentItem = cardalbums.get(position);
currentItem = malbie.get(position);
}
if(mMediaplayer!=null){
mMediaplayer.stop();
mMediaplayer.release();
mMediaplayer= MediaPlayer.create(getApplicationContext(),currentItem.getAudio());
mMediaplayer.start();
}else{
mMediaplayer= MediaPlayer.create(getApplicationContext(),currentItem.getAudio());
mMediaplayer.start();
}
seekBar.setMax(mMediaplayer.getDuration()/ 1000);
}
private void initViews() {
song_name=findViewById(R.id.textTitle);
duration_played=findViewById(R.id.textCurrentTime);
total_duration=findViewById(R.id.textTotalTime);
nextbtn=findViewById(R.id.buttonNext);
prevbtn=findViewById(R.id.buttonPrevious);
shufflebtn=findViewById(R.id.buttonShuffle);
repeatbtn=findViewById(R.id.buttonRepeat);
seekBar=findViewById(R.id.playerSeekbar);
playpausebtn=findViewById(R.id.buttonPlay);
}
#Override
public void onCompletion(MediaPlayer mp) {
nextbtnClicked();
if(mMediaplayer!=null){
int cardhelper= macam.get(position).getAudio();
mMediaplayer= MediaPlayer.create(getApplicationContext(), cardhelper);
mMediaplayer.start();
mMediaplayer.setOnCompletionListener(this);
}
}
}
Fragment Adapter Class
public class musicadapter extends RecyclerView.Adapter<musicadapter.cardViewHolder>implements Filterable {
List<cardhelper> mcardalbums;
List<cardhelper>filteredData;
Filter filter;
int audio;
int position;
Context mcontext;
musicadapter(Context mcontext, List<cardhelper> mcardalbums) {
this.mcardalbums = mcardalbums;
this.mcontext=mcontext;
this.filteredData=mcardalbums;
}
#Override
public cardViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.card_design, parent, false);
cardViewHolder cvh= new cardViewHolder(v);
return cvh;
}
#Override
public void onBindViewHolder(#NonNull cardViewHolder holder, int position) {
cardhelper currentItem = mcardalbums.get(position);
holder.surah.setText(currentItem.getSurah());
holder.count.setText(currentItem.getNumOfSongs());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mcontext, Player.class);
intent.putExtra("position", position);
mcontext.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mcardalbums.size();
}
#Override
public Filter getFilter() {
return new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mcardalbums = (List<cardhelper>) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<cardhelper> filteredResults = null;
if (constraint.length() == 0) {
filteredResults = filteredData;
} else {
filteredResults = getFilteredResults(constraint.toString().toLowerCase());
}
FilterResults results = new FilterResults();
results.values = filteredResults;
return results;
}
};
}
protected List<cardhelper> getFilteredResults(String constraint) {
List<cardhelper> results = new ArrayList<>();
for (cardhelper item : filteredData) {
if (item.getSurah().toLowerCase().contains(constraint)) {
results.add(item);
}
}
return results;
}
public static class cardViewHolder extends RecyclerView.ViewHolder {
TextView count,surah;
#SuppressLint("ResourceType")
public cardViewHolder(View itemView) {
super(itemView);
count = itemView.findViewById(R.id.card_count);
surah = itemView.findViewById(R.id.card_surah);
}
}
}
so after a few weeks of research i found out how to this. Please bear in my I'm a novice but this is what i got from my observation:
You don't need a Service Class to create a notification because it can be created anywhere and called from button clicks inside a method. It will obligatorily need a channel, and addAction button to appear:
public void showNotification(int playpausebtn) {
final Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.new_disc);
macam= (ArrayList<cardhelper>) malbie;
macam= (ArrayList<cardhelper>) cardalbums;
if (macam != null) {
currentItem = malbie.get(position);
currentItem = cardalbums.get(position);
}
Intent previousIntent = new Intent(ACTION_PREVIOUS);
previousIntent.setAction(ACTION_PREVIOUS);
PendingIntent ppreviousIntent = PendingIntent.getBroadcast(this, 1, previousIntent, 0);
Intent playIntent = new Intent(ACTION_PLAY);
playIntent.setAction(ACTION_PLAY);
PendingIntent pplayIntent = PendingIntent.getBroadcast(this, 2, playIntent, 0);
Intent nextIntent = new Intent(ACTION_NEXT);
nextIntent.setAction(ACTION_NEXT);
PendingIntent pnextIntent = PendingIntent.getBroadcast(this, 3, nextIntent, 0);
// Create a new MediaSession
final MediaSession mediaSession = new MediaSession(this, "debug tag");
// Update the current metadata
mediaSession.setMetadata(new MediaMetadata.Builder()
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, icon)
.putString(MediaMetadata.METADATA_KEY_ARTIST, "Pink Floyd")
.putString(MediaMetadata.METADATA_KEY_TITLE, "The Great Gig in the Sky")
.build());
// Indicate you're ready to receive media commands:
Intent intentOpenApp = new Intent(getApplicationContext(), Userxui.class);
PendingIntent pendingIntentOpenApp = PendingIntent.getActivity(getApplicationContext(), 0,
intentOpenApp, 0);
// Create a new Notification
NotificationCompat.Builder noti = new NotificationCompat.Builder(getApplicationContext(), "CHANNEl_ID");
// Hide the timestamp
noti.setShowWhen(false);
noti.setLargeIcon(icon);
noti.setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC);
// Set the Notification style
noti.setContentTitle(currentItem.getSurah());
noti.addAction(R.drawable.ic_previous, "previous", ppreviousIntent);
noti.addAction(playpausebtn, "pause", pplayIntent);
noti.addAction(R.drawable.ic_next, "next", pnextIntent);
noti.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
.setMediaSession(MediaSessionCompat.Token.fromToken(mediaSession.getSessionToken())));
noti.setContentIntent(pendingIntentOpenApp);
noti.setSmallIcon(R.drawable.only);
noti.setOnlyAlertOnce(true);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"Siraa",
NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
noti.setChannelId(CHANNEL_ID);
}
notificationManager.notify(0, noti.build());
}
To implement notification action button you need to create Strings :
public static final String ACTION_PLAY = "action_play";
public static final String ACTION_NEXT = "action_next";
public static final String ACTION_PREVIOUS = "action_previous";
public static final String CHANNEL_ID = "Channel1";
NotificationManager notificationManager;
3.Register these actions inside a Broadcast receiver with intentfilters:
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_PLAY);
filter.addAction(ACTION_NEXT);
filter.addAction(ACTION_PREVIOUS);
receiver=new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String actioname = intent.getAction();
if(actioname!=null){
switch (actioname){
case ACTION_PLAY:
Toast.makeText(context,"Click play",Toast.LENGTH_SHORT).show();
\\\ implement whatever
playpausebtnClicked();
break;
case ACTION_NEXT:
Toast.makeText(context,"Clicked next",Toast.LENGTH_SHORT).show();
nextbtnClicked();
break;
case ACTION_PREVIOUS:
Toast.makeText(context,"Clicked previous",Toast.LENGTH_SHORT).show();
prevbtnClicked();
break;
}
}
}
};
registerReceiver(receiver,filter);
and open themethod in my buttonclick event.
That's it no need to register in the manifest file. Hope this helped.
Hi I am making simple countdown timer and I would like to resume it after pause. Very important for me is that I won't put my countdown timer to public void method.
mTextViewCountDown = findViewById(R.id.text_view_countdown);
mButtonStartPause = findViewById(R.id.button_start_pause);
mButtonStartPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTimerRunning) {
pauseTimer();
} else {
startTimer();
}
}
});
updateCountDownText();
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
mTimerRunning = false;
}
}.start();
}
private void startTimer() {
mTimerRunning = true;
mCountDownTimer.start();
}
private void pauseTimer() {
mCountDownTimer.cancel();
mTimerRunning = false;
mButtonStartPause.setText("Start");
}
private void updateCountDownText() {
int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountDown.setText(timeLeftFormatted);
}
it is but you need to make a new instance of the timer and passing the current paused time
read the details here :
Pausing/stopping and starting/resuming Java TimerTask continuously?