I've implemented something similar to Android notification of screen off/on, but it's not working the way it should. All I want to do is stop music when the screen is turned off. I created a screen action class like this
public class ScreenAction extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// DO WHATEVER YOU NEED TO DO HERE
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// AND DO WHATEVER YOU NEED TO DO HERE
wasScreenOn = true;
}
}
}
Then, in my main activities on create I have this
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenAction();
registerReceiver(mReceiver, filter);
In my main activities onPause, I have something like this:
public void onPause() {
super.onPause();
if (ScreenAction.wasScreenOn) {
final MediaPlayer mp = MediaPlayer.create(this, R.raw.pcmouseclick1);
mp.setVolume(.1f, .1f);
mp.start();
if (buttonState) {
mServ.reduceVolume();
}
}
}
I found this from an online source, but I am having issues. It seems that the screen state is always set as true, and I'm not sure how to change this.
How do I utilize this ScreenAction class to turn off music in on Pause ONLY when the user has locked the screen? I feel like I am missing something in the onPause because in onCreate I link to the class.
#Override
protected void onPause() {
// when the screen is about to turn off
// or when user is switching to another application
super.onPause();
}
#Override
protected void onResume() {
// only when screen turns on
// or when user returns to application
super.onResume();
}
Here you can see the entire lifecycle of an Activity in android:
Activity Lifecycle
Maybe you could also start and stop your music directly from the receiver:
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Pause music player
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Resume music player
}
}
You're checking ScreenAction.wasScreenOn in onPause, but that's happening before the BroadcastReceiver is called to notify you that the screen is being turned off. So at that point, ScreenAction.wasScreenOn is still true, and then it's set to false, but onPause has already run, so your music never gets paused.
To solve this, you should take the action directly in response to the screen turning off in the BroadcastReceiver. If you need to interact with your UI, consider a solution like LiveData as an abstraction so that you're not reliant on your Activity being paused at the exact moment the screen is turned off (consider also that the onPause solution wouldn't work if your Activity weren't currently visible).
Related
I'm building an app that plays music on the background with service. The music is muted when the user is not in the app and unmuted when he is back. I used the onPause() and onResume() methods to do this.
The problem is - every time the user enters a new activity, the music pauses for a second and then resumes, because for a second the current activity is paused.
another problem - for the first run of the activity, the onResume() and onCreate() both works, which makes my service stops from the onResume() without it even being created from the onCreate() (which makes the app shut down).
is there a way to use onPause() without the intent part (or another similar way?)
is there a way to use onCreate() without to onResume() on the first run?
protected void onCreate(Bundle savedInstanceState) {
counter++;
if (counter==1) {
alliesSPEditor.putBoolean("isAllies", true);
alliesSPEditor.commit();
startService(new Intent(this,MusicService.class));
}
#Override
protected void onPause() {
super.onPause();
MusicService.getMP().mute();
}
#Override
protected void onResume() {
super.onResume();
if (counter!=1) //because the counter is still 1, the app won't shut down this way but it will not unmute the music.
MusicService.getMP().unMute();
}
onResume() is always called after onCreate() before the activity starts running
See https://developer.android.com/guide/components/activities/activity-lifecycle
I see some ways to solve this:
the problem is - every time the user enters a new activity, the music pauses for a second and then resumes, because for a second the current activity is paused
The first is you set a flag in the handler that start your new activity and
check in your onPause() method the value of de flag, if false, do nothing othewise mute de music.
public static boolean openOtherActivity = false;
#Override
protected void onPause() {
super.onPause();
if (!openOtherActivity) {
MusicService.getMP().mute();
}
}
You can use Preferences too if you preferrer
To resolve de onCreate() and onResume() problem, you can use the same logic
creates a flag for the services started and control when you needs unmute the music in anothers methods
public static boolean isServiceCreated = false; // In your activity that start the service
protected void onCreate(Bundle savedInstanceState) {
counter++;
if (counter==1) {
alliesSPEditor.putBoolean("isAllies", true);
alliesSPEditor.commit();
startService(new Intent(this,MusicService.class));
isServiceCreated = true; // set the flag to true
}
}
OnResume() method you can check if the service is started an create your logic
I have kind of a game with 2 activities: Start Activity (with high score, start button and tutorial button) and main game activity which is is based on countdown timer, when time is up, game returns to start activity.
Problem is when user starts game and then hits home button and goes back to home screen (just leaving game by home button) Everything is ok until time is up, then Start activity appears on screen with lost message.
I've tried various combined methods like onPause witch finish(); inside and so on but it doesn't work or causes app force close.
I can't handle home button click like in onBackPressed() which I did in that case.
Is there any way to suspend app and pause all threads while it isn't in foreground?
I suggest two way
1
Create global variable like
private isInForgrand = false;
And in onStop() or onPause() and onResume() change it
#Override
public void onStop() {
isInForgrand = false;
super.onStop();
}
#Override
public void onResume() {
super.onResume();
isInForgrand = true;
}
And in onFinish() check it
#Override
public void onFinish() {
if(isInForgrand){
//do what you want
}else{
//your app NOT in Forgrannd
}
2
You can cancel CountDownTimer in onStop()
#Override
public void onStop() {
super.onStop();
mCountDownTimer.cancel();
}
I have an AlertActivity and an Activity. When a broadcast is received, both activities needs to finish. But the below code results Black screen if AlertActivity is on top of Activity.
Below is the code in Activity:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("BROADCAST_INTENT")){
if(alertActvity != null)
alertActivity.finish();
finish();
}
}
And code in AlertActivity:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("BROADCAST_INTENT"))
finish();
}
}
First, Activity's onStop() is getting called before AlertActivity's onStop() is called which results in Black screen, even AlertActivity's finish() called before Activity's finish().
Please help me in this regard.
Finally, I found a solution for this:
Finishing an Activity with a delay of 1 second which really works. By that time, AlertActivity finishes and black screen cannot be displayed.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
finish();
}
}, 1000);
as in both AlertActivity and Activity, you are checking for same action "BROADCAST_INTENT", I assume you registered both receiver in their own class.
If you did so, then actually you have two broadcast receiver waiting for same event. when this event occurs, both of your receiver are going to get it.
So in your AlertActivity is getting finished twice.
I think #Amit K. Saha, is right, your AlertActivity may be finishing twice
Solution :
If your application is running >= API 16 then you can use finishAffinity() method :
Finish this activity as well as all activities immediately below it in the current task that have the same affinity. This is typically used when an application can be launched on to another task (such as from an ACTION_VIEW of a content type it understands) and the user has used the up navigation to switch out of the current task and in to its own task. In this case, if the user has navigated down into any other activities of the second application, all of those should be removed from the original task as part of the task switch.
Note that this finish does not allow you to deliver results to the
previous activity, and an exception will be thrown if you are trying
to do so.
You can call finishAffinity() from AlertActivity because it is on top of Activity. This will finish AlertActivity as well as Activity
My transparent Activity finish results black screen, after a search, i find it is caused by activity switching animation in Android 4.4. But above android 5.1 the phenomenon does not show up.
So I add the below code:
#Override
public void finish() {
super.finish();
overridePendingTransition(0, 0);
}
The black screen after finish is gone.
I think this may be helpful.
try this
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("BROADCAST_INTENT"))
context.finish();
}
}
I have a service that is, among other things, downloading images from internet. When this is done I want to show this image in a custom Activity that has a dialog theme. But I only want to use this pop up if the app is running, otherwise I just want to create a notification.
But I get an exception when I try to start an activity from my service and i feel that maybe this isn't the right way to do it?
It says:
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
So my question is if this is the right way to do this by setting that flag or how should I get my downloaded image from my service to an activity. Can I in some way tell an activity to start a new activity from my service class?
I think using Broadcast Receiver is better option for you.
Add Below Method in Service and call this method when image Download Complete.
private void updateMyActivity(Context context) {
if(MainActivity.activityStatusFlag){
//update the activity if activityStatusFlag=true;
Intent intent = new Intent("mUpdateActivity");
context.sendBroadcast(intent);
}else{
//display notification if activityStatusFlag=false;
}
}
In Activity Add Following Code.
public class MainActivity extends Activity{
public static boolean activityStatusFlag= false;
//define this variable to check if activity is running or not.
#Override
protected void onResume() {
super.onResume();
activityStatusFlag = true;
this.getApplicationContext().
registerReceiver(mMessageReceiver,new IntentFilter("mUpdateActivity"));
}
#Override
protected void onPause() {
super.onPause();
activityStatusFlag = false;
this.getApplicationContext().unregisterReceiver(mMessageReceiver);
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Display Popup or update Activity
}
};
}
I want to play an audio file in the background of my app. Easy enough. I want the music to persist and NOT stop or pause while switching between activities in my app. Also fairly easy and accomplished simply by doing this in the onCreate method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mp = MediaPlayer.create(MainActivity.this, R.raw.lostmexicancity);
mp.setLooping(true);
mp.start();
}
The problem? Getting the music to stop when I press the HOME button.
Killing the sound when the user presses the back button seems easy. Here's what I have for that and works great:
public void onPause() {
if(this.isFinishing()){ //BACK was pressed from this activity
mp.stop();
}
super.onPause(); }
Not complicated, but this does not catch presses of the HOME button. If the Home button is pressed, the music keeps playing even while the user no longer sees my app.
I have seen answers that involve setting permission in the manifest to Get Tasks which I shouldn't have to do and appears dangerous to users. Besides that, the solution didn't even work. I've seen solutions that involve using a service, but none of those work either because the home button STILL plays the music just like before because there doesn't seem to be a way to catch it and it doesn't 'finish' the app (not to mention that every time someone suggest using a service for this task multiple people come in and state that this is not a proper use for services)
It seems the only way to kill the music when the Home button is pressed is to use a non-conditional stop() within onPause, but that's no good because that's called when I swap activities with intents, causing the music to end between activities which is no good.
I have trouble imagining that such a common function like background music is this hard, but I've seen post after post with the same issue as me and no proper answers other than ones that would kill the music between activities within the app.
How do all the other apps on the Google play store accomplish this and yet there appears to be no clear answer online? I could just stop and start the music with each onPause(), but that would cause unprofessional gaps in audio not to mention it would start the background audio from the beginning over and over again which is unacceptable.
I'm a bit new to Android Programming (few months) and today, I faced the same problem you did (maybe you still do?)
I made it work as the following :
Lets say I have MainActivity, and in MainActivity I have Btn2 which leads to SecondActivity, and Btn3 which leads to ThirdActivity.
I declared at the beginning of MainActivity :
public static boolean shouldPlay = false;
I then implemented my onStop() method :
public void onStop() {
super.onStop();
if (!shouldPlay) { // it won't pause music if shouldPlay is true
player.pause();
player = null;
}
}
If the boolean shouldPlay is set to true, then my onStop() won't be called entirely and my music won't turn off. I then have to decide when I set it to true. When I switch from MainActivity to SecondActivity, I do it through an Intent and that's when I'll set shouldPlay to true :
Button Btn2 = (Button) findViewById(R.id.Btn2);
Btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
shouldPlay = true;
startActivity(intent);
}
});
And the same is done for Btn3.
Now, the last thing we want to be looking for is that if I was to go back to MainActivity after visiting SecondActivity or ThirdActivity, shouldPlay would then have been set to true. The first thing I tried was to set it to false as soon as Second and ThirdActivity are called (in their onCreate()) but it want to work, maybe because the onStop() from Main and onCreate() from others are called simultaneously (frankly I don't really get life cycle for now).
What worked is simply to set shouldPlay to false every time we launch onCreate() of Main :
shouldPlay = false;
This works properly for me.
Let me know if it does for you,
Cheers,
bRo.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_HOME){
Log.d("Jorgesys", "Home button pressed!!!");
}
return super.onKeyDown(keyCode, event);
}
but hey! This no longer works as of 4.0 + , Read this: Capture Home Key Event
Try with Back button:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK ) {
Log.d("Jorgesys", "Back button pressed!!!");
}
return super.onKeyDown(keyCode, event);
}
To stop the media player, you are using the method:
isFinishing(): if the activity is finishing, returns true; else
returns false, but you are only pausing the activity not finishing the
activity.
public void onPause() {
if(this.isFinishing()){ //INCORRECT, Here you are pausing you activity not finishing.
mp.stop();
}
super.onPause();
}
so change to:
public void onPause() {
if(mp.isPlaying())
{
mp.stop();
}
super.onPause();
}
When your activity is on pause, evaluates if your MediaPlayer is playing, if this is true then stops the audio.