I am trying to startService only while in foreground, but to determine foreground I use Activity.onStart, this however is called sometimes when app is in background as per that piece of code that throws java.lang.IllegalStateException: Not allowed to start service Intent when starting the service.
-- concretly, when starting activity with screen off.
Does anyone know what the actual check is? How can I "if" this, i.e. I need to && onStart with some processIsInForeground() to get true onStart
So far I have
val appProcesses = activityManager.runningAppProcesses
if (appProcesses == null) return false
val thisProcess = appProcesses.firstOrNull { it.processName == packageName }
if (thisProcess == null) return false
val isProcessForeground == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
But this only works like 90% of the time, some times importance is IMPORTANCE_SERVICE, sometimes IMPORTANCE_TOP_SLEEPING
Also, docs say that api is mostly just for debug, etc.
Related
I have been struggling with an issue where I want to access the package name of apps
running in foreground and not being the same app as mine. But as far as I am concerned
it is not possible as long as I have to give a local Context parametrized into the method
which returns exactly that.
Therefore I wanted to ask if there is a way of doing exactly this but not only on my App itself but globally?
I tried doing this from another StackOverflow thread:
fun getCurrentForegroundRunningApp(context: Context): String {
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val appProcesses = am.runningAppProcesses
for (appProcessInfo in appProcesses) {
Log.i("For all:: ",""+appProcessInfo.processName)
if (appProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return appProcessInfo.processName
} else {
return "There is no app in the foreground"
}
}
return "No App in the foreground"
}
I expected for example that it returns how I am running com.etc.somepackage that isn't what
the app package my app is called is. It only returns such value on my app but not on any other.
I created a chat application that uses Twilio Sdk. Everything works fine but after a Video Call ends, I get this notification which doesn't go away whatever I try to do. After this notification appears, if I try to initiate Video Call, it doesn't work then. Maybe its using some of my resources like microphone which does not allow the app to start Video Calling because the Android system shows that microphone is still being used. Also this is appearing on my Redmi 9C. I have already searched everywhere on the net but no such solution found. It also states its a bug in some devices but there must be something that can be done to resolve this. Help would be appreciated thank you.
This is the code that is used to disconnect from a room:
private fun killAllVideoProcess() {
if (localVideoTrack != null) {
if (localParticipant != null) {
localParticipant!!.unpublishTrack(localVideoTrack!!)
}
localVideoTrack!!.release()
localVideoTrack = null
}
if (room != null && room!!.state != Room.State.DISCONNECTED) {
room!!.disconnect()
disconnectedFromOnDestroy = true
}
if (localAudioTrack != null) {
localAudioTrack!!.release()
localAudioTrack = null
}
if (localVideoTrack != null) {
localVideoTrack!!.release()
localVideoTrack = null
}
}//killAllVideoProcess ends
I'm trying to correctly handle screen rotation during WebRTC call on Android.
But after first rotation local video translation stopping.
After creating (or recreating) activty I am creating SurfaceViewRenderers for local & remote views:
ourView.init(eglBase.eglBaseContext, null)
ourView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
ourView.setZOrderMediaOverlay(true)
ourView.setEnableHardwareScaler(true)
ourView.setMirror(true)
theirView.init(eglBase.eglBaseContext, null)
theirView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
theirView.setEnableHardwareScaler(false)
theirView.setMirror(true)
localVideoSyncer.setTarget(ourView)
remoteVideoSyncer.setTarget(theirView)
After that, if this is a first time when connection must be created, I am initializing peer connection:
iceConnected = false
val dataChannelParameters = CallUtils.createChannelParameters()
peerConnectionParameters = CallUtils.createConnectionParameters(videoWidth, videoHeight, dataChannelParameters)
if(appRTCClient == null) {
appRTCClient = CallUtils.createAppRTCClient(roomId, this, info?.ice ?: emptyList())
}
roomConnectionParameters = CallUtils.createRoomConnectionParameters(info?.address, roomId)
if(peerConnectionClient == null) {
peerConnectionClient = PeerConnectionClient(
applicationContext, eglBase, peerConnectionParameters, this)
}
val options = PeerConnectionFactory.Options()
peerConnectionClient!!.createPeerConnectionFactory(options)
if (appRTCClient == null) {
NetworkLogger.log(TAG,"AppRTC client is not allocated for a call.")
return
}
if(callStartedTimeMs == 0L)
callStartedTimeMs = System.currentTimeMillis()
appRTCClient!!.connectToRoom(roomConnectionParameters!!)
if(audioManager == null)
audioManager = AppRTCAudioManager(applicationContext)
If activity is recreated, PeerConnectionClient is no longer can send video to remote target. I tried to reassign localRender & videoCapturer, but that has no effect. Is it possible to reuse existing connection after activity recreated?
I think the best solution here is to place appRTCClient and related objects outside of activity and make them independent from activity's lifecycle. You use applicationContext thats why you can store it in some singletone which relies on application's lifecycle. Another way is to use fragment inside your activity for displaying chat windows and manually handle rotatation inside onConfigurationChanged method, so you will have to replace portrait fragment with landscape one.
I am writing an Android service to monitor the user to check if that user left the activities or applications (and their child activities) launched by the service. I tried to use Activitymanager.getRunningTasks() to get the package name and task ID of the foreground activity and check if it is the same package that my service launched. This method works if all the child activities are stay in the same task.
However, if some activities in external applications is launched as a new task, then the above method is not working.
Is there something like "task stacks" or "application stacks" for me to trace if the foreground activity is launched by me or my child activities?
The code I tried so far, periodicCheck() is called periodically:
int myTaskId = -1;
String myPackageName = "application.launched.by.me";
void periodicCheck() {
android.app.ActivityManager activityManager = (android.app.ActivityManager) SystemManagerService.this.getSystemService(Context.ACTIVITY_SERVICE);
List<android.app.ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(10);
String currentApplicationPackageName = taskInfo.get(0).baseActivity.getPackageName();
int currentApplicationTaskId = taskInfo.get(0).id;
if (currentApplicationPackageName.equals(myPackageName) || myTaskId == currentApplicationTaskId) {
// user is staying in our target application
// update the task ID
myTaskId = currentApplicationTaskId;
} else {
// user has left our target application, do something
}
}
I developed an application that contains a homescreen with an article list.
If you click on it, you access the detail in another screen.
I implemented the ActionBarSherlock, so I used the "up" button pattern for this activity.
Then I added a widget to this application. When you click on the widget, you access directly the detail activity.
The "up" button has been implemented following the Google recommandations (http://developer.android.com/training/implementing-navigation/ancestral.html).
My problem is that on API Level 15 and below, it works perfectly. It calls the following code :
#Override
public boolean shouldUpRecreateTask(Activity activity, Intent targetIntent) {
String action = activity.getIntent().getAction();
return action != null && !action.equals(Intent.ACTION_MAIN);
}
But on JellyBean, the code used is :
public boolean shouldUpRecreateTask(Intent targetIntent) {
try {
PackageManager pm = getPackageManager();
ComponentName cn = targetIntent.getComponent();
if (cn == null) {
cn = targetIntent.resolveActivity(pm);
}
ActivityInfo info = pm.getActivityInfo(cn, 0);
if (info.taskAffinity == null) {
return false;
}
return !ActivityManagerNative.getDefault().targetTaskAffinityMatchesActivity(mToken, info.taskAffinity);
} catch (RemoteException e) {
return false;
} catch (NameNotFoundException e) {
return false;
}
}
The first part of the method retrieves information on the activity that should be loaded if stack must be recreated.
But I still don't understand what does the line :
!ActivityManagerNative.getDefault().targetTaskAffinityMatchesActivity(mToken, info.taskAffinity);
Can anyone help me on this line, I really need to find out how to obtain true by initializing everything well ?
Its a boolean method it has to return something. If it needs to return a true boolean variable for it work, you have to do so!
From the official Documentation:
Returns true if the app should recreate the task when navigating 'up'
from this activity by using targetIntent.
If this method returns false the app can trivially call navigateUpTo(Intent)
using the same parameters to correctly perform up navigation.
If this method returns false, the app should synthesize a new task stack by using
TaskStackBuilder or another similar mechanism to perform up navigation.
The affinity indicates which task an activity prefers to belong to. By default, all the activities from the same application have an affinity for each other. So, by default, all activities in the same application prefer to be in the same task. However, you can modify the default affinity for an activity. Activities defined in different applications can share an affinity, or activities defined in the same application can be assigned different task affinities.