Issues with a SurfaceView when reopening app after locking and unlocking phone - java

In my game, I have a thread. This thread is paused in onPause() in the activity and restarted in surfaceCreated in the main game class.
#Override
public void surfaceCreated(SurfaceHolder holder) {
if(gt == null) {
gt = new GameThread(getHolder(), this);
gt.setRunning(true);
gt.start();
}
}
The onPause(called from game):
public void onPause(){
... other stuff
if(gt != null){
try {
gt.setRunning(false);
gt.join();
gt = null;
}catch(Exception e){
e.printStackTrace();
}
}
}
But for some reason, when the screen is locked and unlocked, the thread does not start again. When I open the list of recent apps and reopen the app from there, the thread restarts.
Why is this happening, and how can I solve it?

You should start your thread in onStart(), not in surfaceCreated, because the surface is not recreated in this case (your activity is not destroyed), so the method surfaceCreated is not called when you unlock your phone. However, onStart() is.

Related

Android foreground service holds microphone access even after being killed

I'm using a foreground service on Android that plays audio. I also use microphone input through NDK from Android Oboe library on a fragment, unrelated to the service. However, after I close the app, the microphone is inacessible to other apps, even if the service is killed (the service notification goes away).
Here's how I'm starting the service:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//Start in Foreground
ContextCompat.startForegroundService(this, intent);
if (serviceConnection != null) {
//Then bind service
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
} else {
startService(intent);
if (serviceConnection != null) {
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
The service is just public class MainService extends Service
and I added this on AndroidManifest
<service android:name=".services.MainService" android:stopWithTask="true"/>
so it stops when I close the app.
However, the oboe code is not in the service. I suspect that C++ keeps a thread open on the background. Somehow, this thread lives even after the app closes. Is it possible?
I added this:
override fun onDestroy() {
Log.d(TAG, "-----fxfragment destroyed!")
NativeInterface.destroyAudioEngine()
super.onDestroy()
}
to delete the audio engine on the C++ side. It works on some phones, the microphone is acessible. But on some, it does not.
Creating engine in onResume and destroying in onPause() so the stream retains exclusive
mode only while in focus. This allows other apps to reclaim exclusive stream mode. Therefore, I would recommend you to add onResume() and onPause()
#Override
protected void onResume() {
super.onResume();
PlaybackEngine.create(this);
setupLatencyUpdater();
// Return the spinner states to their default value
mChannelCountSpinner.setSelection(CHANNEL_COUNT_DEFAULT_OPTION_INDEX);
mPlaybackDeviceSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
mBufferSizeSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
mAudioApiSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
}
and in the onPause()
#Override
protected void onPause() {
if (mLatencyUpdater != null) mLatencyUpdater.cancel();
PlaybackEngine.delete();
super.onPause();
}
You can also go through this github link for further details
this is bug in library as mention here library issues link

My app freezes after fullscreen application on front

I am struggling with persistent problem with Android app that has MQTT ServiceConnection running on background. When ever I switch to an other application that has fullscreen surface (game, youtube on fullscreen, etc) the application completely freezes when trying to bring it on front again. It even refuses to relaunch if closed from drawer. The app won't reopen unless completely killed. The weird thing is that if I run the application via debugger it works perfectly. It makes the problem difficult to get handle on. I have put on prints on beginning of each life cycle method, even before call to super class method. None of them get printed when the app hangs, which hints that it hangs some where on the system level.
Now if I call stopService at onStop method, it works fine but defeats the purpose of having persistent service on the background. I have called unbindService also on onStop, but it does not help. With all the other application everything works fine, even you tube as long as it is not used in fullscreen.
The dependency to the MQTT library is
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
and this is my onStop() method
#Override
protected void onStop() {
FirebaseUserActions.getInstance().end(getIndexApiAction0());
if(mBoundToService) {
try {
unbindService(serviceConnection);
mBoundToService = false;
}
catch (Exception e)
{
e.printStackTrace();
}
}
super.onStop();
}
And the onStart() method would be this:
#Override
protected void onStart() {
Log.d(TAG, "onStart has been called");
super.onStart();
if(!mBoundToService) {
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
FirebaseUserActions.getInstance().start(getIndexApiAction());
}
But this never gets called. From the logs I can see that MQTT service is receiving messages and produces no errors. Messages continue to be received even as the application is hanged so the background service is alive and running.
The inlined Service connection class is like this:
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder)
{
mqttService = ((MQTTService.MyBinder) binder).getService();
mBoundToService = true;
Log.d(TAG,"MQTT service has been bound");
Handler handler = getHandler();
//NOTIFY THE LOGIN ACTIVITY THAT THE DATA HAS BEEN ACQUIRED
Message msg = handler.obtainMessage(Utils.HANDLE_MQTT_SERVICE_CONNECTED);
Bundle bundle = new Bundle();
bundle.putString(Utils.KEY_MQTT_SERVICE_BOUND,"Everything is complete");
msg.setData(bundle);
handler.sendMessage(msg);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBoundToService = false;
Log.d(TAG, "MQTT service has been UNbound");
}
};
The MQTT service is started like this from onCreate():
mqttIntent = new Intent(getApplicationContext(), MQTTService.class);
if(!mBoundToService){
Log.d(TAG,"Starting MQTT Intent");
startService(mqttIntent);
Log.d(TAG,"Binding MQTT Service");
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
Am I missing something that I should be doing at the onStop() to be able to resume the application after having fullscreen application on front?

Game Loop Is Not Destroying

Background
I have created a game loop to run the UI, but when I push the back button from the game screen (SingleGameActivity) I get to the level-selector menu called (StartLvlActivity). If I try to reenter the game or push the back button from StartLvlActivity I get a keyDispatchingTimedOut error (ANR).
When I wrote Log messages, the game activity (SingleGameActivity) was only paused, not stopped when I pushed the back button. And the game loop was never destroyed when I closed the activity.
08-03 09:56:12.130: I/Process(346): Sending signal. PID: 5763 SIG: 3
08-03 09:56:12.130: I/dalvikvm(5763): threadid=3: reacting to signal 3
08-03 09:56:12.333: I/dalvikvm(5763): Wrote stack traces to '/data/anr/traces.txt'
08-03 09:56:12.341: E/ActivityManager(346): ANR in com.coderogden.pongtennis (com.coderogden.pongtennis/.activities.StartLvlActivity)
08-03 09:56:12.341: E/ActivityManager(346): Reason: keyDispatchingTimedOut
Questions
1. Why isn't the game loop destroyed when I push the back button from the game menu? I mean, why isn't surfaceDestroyed called when onPaused is called (onStop is never called and I don't know why....).
How do I access "/data/anr/traces.txt"
How do I handle the errors?
If you can answer any of these questions I would appreciate it very much!
EDIT
This is the surface view class from where I start and destroy the thread (or apperently I'm just starting it as it won't shut down when I press "back"-button).
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
Log.d(TAG, " surface created");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(TAG, " surface destroyed");
}
EDIT 2 (with solution!)
The bug was fixed by changing this piece of code:
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
to this:
thread.setRunning(false);
WHY?
Is it because I need to stop the thread before destroying it?

Weird issue with media player and async playing aacp/shoutcast stream on android

I'm trying to build a custom player for a radio station, and they want to move from mpeg to aac to lower the bitrate (mostly for mobile users) however when i started the project i was testing it against the mpeg stream, When i change it to the new aac stream my player seems to lock for a period of time, then the UI thread is killed by android while the player is attempting to load the stream in the background. I do get some initial errors about it being unable to play, but maybe 30 seconds after the app is killed i get an orphaned async player re-spawning in the background with it's sticky notification and the stream starts playing?
the logcat output shows these lines around when it crashes
I/dalvikvm﹕ threadid=3: reacting to signal
I/dalvikvm﹕ Wrote stack traces to '/data/anr/traces.txt'A/libc﹕ Fatal signal 6 (SIGABRT) at 0x000008eb (code=0), thread 32258
I see the sticky for the orphaned async task and it's playing audio when i click it (to regain audio focus) but the main app/ui thread is obviously completely reset
The code that spawns the async task is as follows:
private class PlayAsync extends AsyncTask<String, Void, Boolean> {
private String url_to_play = "";
#Override
protected void onPreExecute() {
super.onPreExecute();
textView_info.setText("Buffering...");
}
#Override
protected Boolean doInBackground(String... params) {
url_to_play = params[0];
Bundle b = new Bundle();
b.putString("url", url_to_play);
Intent i = new Intent(MainActivity.this, MusicService.class);
i.putExtras(b);
try {
stopService(new Intent(MainActivity.this, MusicService.class));
} catch (Exception ex) {
//
}
startService(i);
return true;
}
#Override
protected void onPostExecute(Boolean result) {
isMuted = isMuted();
if (isMuted) {
textView_info.setText("Playing Muted!");
} else
textView_info.setText("Playing");
isBuffering = false;
}
#Override
protected void onProgressUpdate(Void... values) {
}
protected void onError(MusicService mp, int what, int extra) {
// The MediaPlayer has moved to the Error state, must be reset!
button_stop.performClick();
}
}

Thread crash on Android 4.0 when exiting an Activity

When testing several games with a standard game thread in Android 4.0 it works well until the Activity is shut down (pressing the home button etc), leaving the activity the application crashes with a nullPointer.
This even happens in the sample LunarLander that Google has programmed.
The problem is that Canvas becomes null when leaving the activity and that makes the application crash.
The error message from the LogCat is just below.
02-27 18:07:58.974: V/MainThread(2667): CANVAS android.view.Surface$CompatibleCanvas#4102bcf0
02-27 18:07:59.164: V/MainThread(2667): CANVAS null
02-27 18:07:59.164: W/dalvikvm(2667): threadid=14: thread exiting with uncaught exception (group=0x409c01f8)
02-27 18:07:59.174: E/AndroidRuntime(2667): FATAL EXCEPTION: Thread-108
02-27 18:07:59.174: E/AndroidRuntime(2667): java.lang.NullPointerException
02-27 18:07:59.174: E/AndroidRuntime(2667): at com.joakimengstrom.pong.MainThread.run(MainThread.java:49)
This is the code when starting a thread, with the Log.v you see above.
while(this.running){
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
...
And below is when creating the thread and shutting it down when the surface is destroyed.
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new MainThread(getHolder());
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
How do I exit the thread in a safe way without making canvas null?
In Android 4.0, SurfaceHolder.lockCanvas can return null when the surface is destroyed. So here:
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
Just surround your synchronized (surfaceHolder) block with if (canvas != null). This should not cause any issues with the behaviour of your application as it occurs when drawing is not needed.

Categories

Resources