Check if onStop is called from user interaction, or screen dimming - android

I have a media player that stops playing whenever the user closes the app, either by pressing the home button, using the back button or simply opening another app.
To get this behavior, I added an onStop() to my main activity which tells my MediaPlayer(which is in a service) to stop playing music.
However, I would like the music to keep playing whenever the screen gets dimmed, either by using the power button to turn the screen off, or just by the screen auto dimming.
Right now the player also stops playing when the screen dims, meaning that the onStop() method also gets called then.
How can I check if the onStop() gets called by the screen diming?
I already applied a PARTIAL_WAKELOCK to my MediaPlayer object, which to the best of my knowledge, should make it possible for the player to keep running after the screen goes off.
Do I need to add a partial wakelock to my main activity as well?
Just applied a PARTIAL_WAKELOCK to both my main activity, as well as my media player.
Right now, the screen doesn't turn off by itself anymore, and when the user presses the power button the music still stops.
Obviously, this doesn't work as I thought it does.
Is there any way of achieving the behavior I'm looking for?

You can add
private boolean stoppedByUser = false;
field to your activity, set it to false in onStart(), to true in onBackPressed() and onUserLeaveHint() and check it's value in onStop() method.

Related

Programmatically put an Android activity in its "Stopped" state, without destroying it?

I'm creating a music app in Android with a background service playing the music, and a Home activity that has various fragments and is the UI of the app.
When I press the home button on my phone, this app gets put in the background of course, and the lifecycle methods get called down to onStop(), in which the UI gets disconnected from the Service in order to allow background playback, the user can keep using their device and do other things. When I get back to my UI Activity, onStart gets called and the UI and Service reconnect together, giving me back controls over the music. onStart gets me the same activity in the foreground, it doesn't create another instance of the same activity.
I'm trying to implement also a function for when I press the back button on my device, so the UI activity can have the same behavior as with the home button, i.e. simply put the UI in the background (onStop). Instead, the default behavior of the back button is to finish(), killing the current activity it's called from (thus calling onDestroy).
What could I do for that? Couldn't really find anything online. Seems such a simple function that every music app has (not killing the app when pressing back, but just send it into background)
You can override onBackPressed and move the Activity Task to back. Based on the documentation Activity'r order in the Task will also remain unchanged:
#Override
public void onBackPressed() {
this.moveTaskToBack(true);
}

Dealing with Android's MediaPlayer while rotating screen, pressing Home Button or App is interrupted

I'm in a tricky part of the workflow/design on my app.
I have a MediaPlayer that runs into a Service. I want the music to stop when user leaves (BUT NOT CLOSES) the App. That is, the Home Button.
So I implemented MediaPlayer's pause() and start() methods into Activity's onStop() and onResume(), respectively. That is working fine when testing with the button and relauching the App, but it also happens when the screen is rotated due to the Activity's lifecycle.
So, how can I avoid this in a efficient / elegant way? The music mustn't be interrupted when device is rotated. I thought in overriding Home Button's click method, pause there the MediaPlayer and setting a global boolean flag to check in onResume() if MediaPlayer must be resumed. But this seems to me like a hack or so, not a good practice.
I'm wrong with this? Is there a better way?
Any advice is appreciated.
There are a few options here:
If your minSdkVersion is at least 14, you can check the isChangingConfigurations() flag before stopping the media player:
#Override
protected void onStop() {
if (!isChangingConfigurations()) {
// Stop the Media Player
}
}
Otherwise, you could watch for onUserLeaveHint():
#Override
protected void onUserLeaveHint() {
// Stop the Media Player
}
Although that won't be called if another application is forcibly drawn to the foreground (e.g. a phone call comes in).
EDIT: As an alternative you might be able to rely on onWindowFocusChanged(). It is called with false when leaving the activity with Home or Back, but not on a configuration change. It should also be called when another activity is brought to front.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// Stop the MediaPlayer
}
As a side note, you should typically use symmetric lifecycle methods (e.g. instead of onPause(), onStart() use either onPause()/onResume() or onStop()/onStart())

Distinguishing between different Activity transitions

I have an Activity that plays some audio from within a ListActivity. The user can also click on the list item and go to a more detailed view of that data. I want the audio to keep playing during that transition from one activity to another and keep playing once the detail activity is active BUT I also need to pause the audio if my activity is being paused or stopped for any other reason.
My issue is that I currently pause the audio in onPause() in the ListActivity because I want the audio to be paused when the user navigates away from my activity. E.g. when they press Home or Back. However, I don't want the audio to pause when my detailed view activity gets started. onPause() is called in both instances, so how can I distinguish between the two cases?
Shouldn't you be doing that in a service instead? Wouldn't it be easier? Then you can stop the service when one or another activity is pausing or exiting (depending on which one you want). You could also check if it's started, and stop accordingly whenever you want.
Or sorry if I didn't understand your question. I see you have a lot of points here on SO, so perhaps I'm just confused.
--- edited since your third comment:
A Intent to B: send Intent with name of music.
B onCreate: get name of music from Intent. Set flag x to true.
B onResume: start playing music if from A or resumes from last known position if resuming from B.
B back button: override and set x to false. Actually, you'd cover all points where your activity finishes.
B onPause: stop the music if(x), store last known position of music in memory and stop service.
Here I assume that you want music to keep playing even when returning to A (that's what you said, that's the problem), not just up to B. Setting x is important early on, IMO, because if any other activity (phone call, anything) appears, activity will stop playing the music immediately (user expects that) on onPause. According to Android guidelines, you know that you're getting back to A only if user presses back button or if you finish() your activity. You can fine tuning checking the position of activities in your task (don't remember how to do that right now).
Personally, I also wouldn't want to resume playback on A (say, B->call->home->A, applying step 3 to A, too), because a disruption in the logical flow of things happens there.
CAVEAT: I would make sure that there is no other way. I would try to see if you can 1) know in advance which activity is about to be displayed. 2) get any music service to hook up to your task (is that even possible?).
Anyway, just use my solution if you can't find a clever way to do that. That would be my suggestion. Good luck.

How can I keep background music playing whilst changing Activity?

My application has some background music playing on a loop, using a MediaPlayer. I stop the music in the onPause of the Activity so it doesn't keep on playing if the user leaves the application by pressing the Home key, or if they receive a phone call, etc.
However, I now need the music to continue playing seamlessly when the user moves to certain other activities. That is, if they press button A then I add activity A to the stack and the music should continue; however if they press button B then I add activity B to the stack and the music should stop. Similarly the music should continue if they press the phone's Back button to return from activity A to the original activity.
I've tried starting the MediaPlayer again in the onResume of Activity A, but there's quite a noticeable gap in the music during the transition.
At the moment I've got onPause triggering a half-second delay before fading the music out over another quarter of a second; this can be cancelled from within another activity's onResume. This means the music stops just about quickly enough when the user's leaving the app; however when the user switches activities I still get a slight pause in the music on some slower devices. Furthermore it feels like a really dirty hack.
Is there a better way?
[Edit: if it helps, the MediaPlayer is held in a static class that I can access from anywhere in the application.]
The simplest solution that I can think of offhand if I needed to get this done would be to set a static flag variable in my global Application object (let's call it sStartingNewActivity). Wherever I'm starting an intent new activity (or pressing "back" from an activity that isn't the entry point, overriding the onBackPressed method), I'd set that value to true, and have onPause not stop the music if that flag is set. I'd set the value back to false in every activity's onCreate. I don't think a 1-2-second-pause-before-fadeout is a bad way to go, though -- that would actually behave pretty similarly to how it works when the user presses the "home" button in an iOS app that has background music.
EDIT: You can also try a service-based solution that "sniffs" for whether your activities are running by having your activities listen for a specific broadcast; there's some sample code online that I haven't tried but it's an interesting approach).

Service still bound to main activity when pressing home button, when viewing different activity

Ok, so the application I've written has a service (that tracks GPS data) with a single main activity that binds to it with bindService in it's onStart() method, and unbinds from the service in it's onStop() method using unbindService(ServiceConnection).
I also have an activity which is an options screen, that is launched by pressing a button on the main activity. On this options screen, I have a checkbox that says "Run in background", which, if set to true, means that when the user exits the application with either the Home or Back buttons, the service will continue running, not turning the GPS off.
I do this by calling this.startForeground onUnbind, and this.stopForeground onRebind, if the setting is set to true, and stopping and starting my location reader onUnbind and onRebind respectively if the setting is false.
If the service is running in the background, it also displays a notification to ensure the user understands that the GPS is still running and draining their power. This notification is displayed and stopped by relying on the startForeground and stopForeground methods.
So, the problem lies in the fact that whether or not this setting is true, if I'm viewing the options screen, I want the service to keep going, and I do not want that notification to appear. So I set a flag that is set to true if I've hit the button to go to the options screen, and do not call unbindService if the flag is true.
This works, except for one slight problem. If the user hits the home button while viewing the options screen, the service is not stopped if it is supposed to be (because it's still bound to the main screen), and if it is supposed to keep running, it does not display the warning notification (and of course, this means that the service is still considered to be in the background).
How should I go about getting this application to behave the way I want it to?
Ok, so I just found a solution that seems to work. I bind the options screen to the service in the activity's onStart() method, and unbind it again in onStop(). The previous activity's onStop() method isn't called until after the new one's onResume() method, so it works.
Does anyone have a better way though? It seems silly to bind an activity to a service that it doesn't actually need access to.

Categories

Resources