I am working on an app, wherein when a new activity is started, it should start playing a sound.
So I used mediaplayer to play the sound in oncreate and It worked fine. But when I tried to use soundpool instead, by loading and playing it in oncreate of the activity.
Its is not playing.
I choose soundpool, since its better than mediaplayer.
what might be the issue? doesn't soundpool work in oncreate?
Maybe you just need to put a sleep in the onCreate method.
I had pretty much same problem trying to write an app that would sometimes need to play a sound as soon as it woke up. Eventually after much trial and error I discovered that it was putting the error "sample NOT READY" in the log output. The problem was that loading a sound file happens asynchronously, and if you try to play the sound before it has loaded it fails.
There is supposedly a mechanism you can use called setOnLoadCompleteListener, but I've yet to see an example of how this is actually useful. In the example shown above from mirroredAbstraction (assuming it works as advertised) all that would happen if the sound is not loaded yet is that it would not play the sound, which is pretty much the same as what you have now.
If that example somehow magically "fixed" your problem then I would suggest that it was only because all the extra overhead in the two method calls basically give your sound time to load before it was played. You could probably have achieved the same outcome with a simple SystemClock.sleep(100) in your onCreate between the load the play.
Depending on the size of your sound you might need to lengthen the delay, but a bit of experimentation with differing delays should tell you how much you need.
Alternatively , you could override OnWindowFocusChanged to play the file when the Activity starts ...
Something like this ...
public class YourActivity extends Activity {
.
.
.
private Handler mHandler;
public void onCreate(Bundle savedInstanceState) {
.
.
.
this.mHandler = new Handler();
.
.
.
}
public void onWindowFocusChanged(boolean paramBoolean)
{
if (paramBoolean)
{
this.mHandler.postDelayed(new Runnable()
{
public void run()
{
// Refer to the answer above to create the play function for your soundfile ...
YourActivity.this.play("The sound from the sound pool");
}
}
, 1000L);
}
}
You can play it anywhere,
Ill demonstrate with a simple example
Create a method initializeSoundPool
private void initializeSoundPool(){
mSoundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
loaded = true;
}
});
soundID = mSoundPool.load(this, R.raw.glassbreak, 1);
}
Then create a method playFile
private void playFile(){
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
float actualVolume = (float) audioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
float maxVolume = (float) audioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = actualVolume / maxVolume;
if (loaded) {
mSoundPool.play(soundID, volume, volume, 1, 0, 1f);
Log.e("Test", "Played sound");
}
}
Then in onCreate call them like this
private SoundPool mSoundPool;
private int soundID;
boolean loaded = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spxml);
initializeSoundPool();
playFile();
}
Or even better call initializeSoundPool in onCreate and then call playFile in onResume.
Related
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).
I am working on an application for research purposes. We want to track some user activity on the phone: if some actions are easily detactable with broadcast receivers, we want also to check current running applications.
This application works only on Android devices that runs android 5.0 or lower.
My problem is that I post a Runnable Obj in a handler, Runnable posts again itself in handler after HALF_SECOND (see code for details). In runnable I get information and send them to IntentService to perform work.
Everything works fine: app starts at boot, handler and runnable do their job in background UNLESS I open the main Activity.
The app is able to keep going for days, but if I open the main Activity and then close it from "recent open activities" with a swipe, or from the memory task manager, handler and runnable stop, even if they are not called/accessed by the activity (they are in a Separate Service).
Moreover, not always a call to onDestroy (of the activity or Service) is made.
Reading online I understand that swipe or task manager remove the app from memory abrouptly thus not always calling onDestory.
What I want to achive is to make the handler start again soon after the main activity is closed.
What I have tried is to put some check in onPause method of the activity, making sure to remove this check if onStart is called again (like in case the the app switches from vertical to horizontal layout, or if home button is pressed and then app is opend again). Also implemented a way to make the handler send "ImAlive" intent to a broadcast receiver, which should restart the service that starts the handler, if intents do not arrive before a count down is finished. Unfortunately, as soon the main activty stops existing, even the broadcast is automatically unregistered and destroyed.
My question is, is there a way to create something that is able to make my handler restart if the activity is closed? Or is there some other pattern that can help me as workaround for what I want to achieve? Because I am polling data every half second I read is better to use handler, because Timer augments small interval to a greater interval, and AlarmManager is not precise enough for very small interval.
What I want to achieve is something similar to Facebook, Instagram, Whatsapp, Telegram app, that are always in memory, and even if you force to terminate them, after a few seconds are back again there... how?
We are not interested in battery issues because of continuous polling to data. As for research purposes we don't mind if the phone on which we are testing last 2 days straight, 1 day or 12 hours or less.
Here the code: OnBootService is started from broadcast receiver, declared in manifest when onBootCompleted and ShutDown actions are received, in order to start and stop handler.
public class OnBootService extends Service{
private static final Handler handler = new Handler();
private final long HALF_SEC = 500;
private RunnableTest r = null;
private Context myContext = this;
private final String TAG = "BootService";
// Extras
public static final String START = "start";
public static final String STOP = "stop";
#Override
public IBinder onBind(Intent intent){
return null;
}
#Override
public int onStartCommand(Intent intent, int flag, int startId){
String action = intent.getAction();
switch(action){
case START: startHandler();
break;
case STOP: stopHandler();
break;
}
return START_NOT_STICKY;
}
private void startHandler(){
if(r == null){
r = new RunnableTest();
handler.post(r);
Log.i(TAG, "----Handler started!");
}
}
private void stopHandler(){
if(r != null){
Log.i(TAG, "----calling STOP");
handler.removeCallbacks(r);
r = null;
}
}
private class RunnableTest implements Runnable {
private String TAG = "RunnableTest";
public RunnableTest(){}
#Override
public void run(){
handler.removeCallbacks(this);
// Do stuff
Intent i = new Intent(myContext, MyIntentService.class);
i.putExtra("addStuff", myStuff);
myContext.startService(i);
handler.postDelayed(this, HALF_SEC);
}
}
Activity is empty: all method overridden just to understand proper Activity lifecycle, but else is empty for now.
public class MainActivity extends AppCompatActivity {
private final String TAG = "Activity";
private Context myContext = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// access a file and get stored information to show
setContentView(R.layout.activity_main);
Toast.makeText(getBaseContext(), "Application open successfully", Toast.LENGTH_LONG).show();
}
#Override
protected void onRestart(){
super.onRestart();
Log.e(TAG, "----onRestart Called");
}
#Override
protected void onStart(){
super.onStart();
Log.e(TAG, "----onSTART Called");
}
#Override
protected void onResume(){
super.onResume();
Log.e(TAG, "----onRESUME Called");
}
#Override
protected void onPause(){
super.onPause();
Log.e(TAG, "----onPAUSE Called");
}
#Override
protected void onStop(){
super.onStop();
Log.e(TAG, "----onSTOP Called");
}
#Override
protected void onDestroy(){
super.onDestroy();
Log.e(TAG, "----onDestroy Called");
}
}
Any help is really appreciated, if you need some more information on the code, I will update the post.
Thank you!
Android system can restart the service if u return START_STICKY inside onStartCommand().
It works perfectly on all lower version than Lollipop in Android.
No need of CountDownTimer.
Please read the question before marking this as a duplicate. I'm trying to access the LED/Flashlight WITHOUT using the Camera methods shown in other code on this site. Thank you.
I'm trying to use the flashlight/torch in Android. I have found and implemented code that works for doing this. The problem I have is that I'm using an image recognition API that uses the camera as an image scanner and they don't have a light on/off function. When I try to override their methods and use the Camera methods to turn the torch on/off, this works, however, the Camera methods now control the window and their Scanner no longer has priority on the screen.
So what I'm trying to determine is... Is there another way to turn on the flashlight/torch without using the Camera methods and preview functions. Anyone have an idea how to bypass the Camera to use the flashlight/torch? Any information would be greatly appreciated.
Here is the code that I currently use, which is working to turn the flashlight on/off, but like I said...this overrides the scanner, and I need the camera/scanner to operate at the same time to recognize my images.
public class Flashlight extends AutoScannerSession {
Camera cam;
private CameraManager mCameraManager;
private Context context;
private Scanner scanner;
private AutoScannerSession.Listener listener;
private boolean advancedListener = false;
public Flashlight(Activity parent, Scanner scanner, Listener listener, SurfaceView preview) {
super(parent, scanner, listener, preview);
cam = Camera.open();
cam.setErrorCallback(new Camera.ErrorCallback() {
#Override
public void onError(int error, Camera camera) {
Log.e("erro", error +"");
}
});
this.context = parent;
this.mCameraManager = new CameraManager(parent, this, preview);
this.scanner = scanner;
this.listener = listener;
if(listener instanceof AutoScannerSession.AdvancedListener) {
this.advancedListener = true;
}
}
#Override
public void start() {
super.start();
//flashOn();
}
public void flashOn() {
android.hardware.Camera.Parameters p = cam.getParameters();
p.setFlashMode(android.hardware.Camera.Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
//cam.startPreview();
}
public void flashOff() {
cam.stopPreview();
cam.release();
}
#Override
public void stop() {
super.stop();
flashOff();
}
No there is no alternative way to work with flash. But probably you can "share" the camera object with the Scanner.
At any rate, Camera.open() in Activity.onCreate() and turning on flashlight in Activity.onStart() do not look correct. To be a good citizen among other apps, your app should not obtain camera before onResume() and release it no later than onPause().
Code Snippet to turn on camera flash light.
Camera cam = Camera.open();
Parameters p = cam.getParameters();
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
Code snippet to turn off camera led light.
cam.stopPreview();
cam.release();
I have a Symphony H20 smartphone officially running Android 4.4.2, Kernel 3.4.67, MT6582. Setting Parameters.FLASH_MODE_TORCH as a camera parameter did not work. After trying a few hours I decided to decompile its pre-installed FlashLight app. There, I found that they write 1 in file /sys/class/torch/torch/torch_level to turn on the Camera LED and 0 to turn it off.
Then I tried the same thing and voilla! It worked.
But the same technique did not work in my Winmax W800 Plus with Android 4.4.2, Kernel 3.4.67, MT6572. It even does not have a file like /sys/class/torch/torch/torch_level at all.
i'm having trouble playing a sound in android.
My first attempt was all inside my onButtonClick function which worked really well for about 20 clicks. then the sound stopped. and i believe it used the entire sound pool of android because all my other apps stopped having sounds.
public void onButtonClick(View view)
{
MediaPlayer clickSound = MediaPlayer.create(this, R.raw.click);
clickSound.start();
//... other onButtonCode
}
i have since changed this up a little bit so that this is now a global variable
MediaPlayer clickSound;
and it is instantiated inside my onCreate() method. the onbuttonClick now has the clickSound.start()
but this doesn't work the way i thought it should. the sound is seemingly random. sometimes the click will be there. sometimes there will be no sound. or sometimes the sound is there for a little blip and ends before the sound is complete. On the good side it doesn't seem to completely fill up the sound pool so i can keep getting 'some' sounds while i am testing.
What am i missing to make the sound function properly?
I tried to add a clickButton.stop() but that made my sound not function at all, probably because it stops before it is noticeable.
You should release the ressource after use.
clickSound.release();
clickSound = null;
I would suggest following:
Initialize the Player in onResume:
clickSound = MediaPlayer.create(this, R.raw.click);
Release ressources in onPause:
clickSound.release();
clickSound = null;
Use button to play sound:
clickSound.start();
Use SoundPool instead.
soundPool = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
resId = soundPool.load(context, R.raw.click, 1);
for play :
private void playSpecSound(int resId)
{
if(soundPool != null)
{
if(0 == soundPool.play(resId, 1f, 1f, 0, 0, 1.0f))
{
Log.e(TAG, "Play specified sound failed !");
}
}
}
I am having problems with playing sound on android with the SoundPool, this works nicely with the MediaPlayer class. Why I can't use the MediaPlayer class is because it's not supporting the change of the sound pitch or speed.
The use case: Sound is played on background and it will be changed based on the user input.
The current problem: Does not play the sound correctly and freezes the application.
Question: What would be correct way to handle this situation, should the background sound played in separate thread and the communication of changing the sound volume should be done using Handler and messages ?
#Override
public void surfaceCreated(SurfaceHolder holder) {
soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
RAIN_SOUND_ID = soundPool.load(getContext(), R.raw.rain, 1);
new Thread(new Runnable() {
#Override
public void run() {
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
if (sampleId == RAIN_SOUND_ID) {
soundPool.play(RAIN_SOUND_ID, 1f, 1f, 10, -1, 1);
}
}
});
}
}).start();
}
The SoundPool class actually creates and manages it's own thread pool behind the scenes, for playing it's sounds. So you can simplify your code to remove your additional threading as a potential issue.