I currently have two applications.
App A has a list of existing applications that you can click on and open. Including which is App B. Now I want to only run App B for a set amount of time ~30 minutes.
Is there a way to automatically close App B and reopen App A? I want to fully close App B. Kind of like when you press the soft button on your android and close out the app by swiping left/right.
I have tried using KillBAckgroundProcess and killProcess, but it does not fully simulate the "swiping left/right" of the app. I have looked at other issues on stack overflow, but none have the answer of how to do it this specific way.
Example Code:
//process
for (ActivityManager.RunningAppProcessInfo process : processes) {
if(process.processName.equals("com.example.adam2392.helloworld")) {
processToKill = process.processName;
processId = process.pid;
}
}
//packages
for (ApplicationInfo packageInfo : packages) {
if (packageInfo.packageName.equals("com.example.adam2392.helloworld")) {
packageToKill = packageInfo.packageName;
}
}
am.killBackgroundProcesses(packageToKill);
android.os.Process.killProcess(processId);
I believe what would work better for your situation is to set an alarm in App B's onStart() or onCreate() method that goes off after 30 minutes and runs whatever code you need it to run to kill processes and then terminate App B. I've never done this myself, but this link has a nice tutorial about using Alarms in Android to schedule an app to do something. For your situation, you most likely will want to use
AlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 60 * 1000, PendingIntent)
as the trigger for your alarm because there's probably no reason that App B has to begin its shutdown process at EXACTLY 30 min.
As far as closing the App, I believe this should work for you:
public void killApp() {
Intent goHomeIntent = new Intent(Intent.ACTION_MAIN);
goHomeIntent.addCategory(Intent.CATEGORY_HOME);
goHomeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(goHomeIntent);
finish();
}
This may not force quite the app like you're wanting, but usually you want to just let Android terminate the app at its own discretion after it has been closed.
Related
My application (Xamarin.Android) runs as foreground service. The service hence has a permanent notification which I update. The app receives data from a bluetooth-enabled medical device. When comms arrive at my app, I update the notification with a counter (patient events in my case).
If I tap on the notification, my app launches so all good there, however, for certain incoming bluetooth packets, I need to actually start (or foreground) my activity, this needs to happen WITHOUT the user tapping on the notification. NB: I am only expecting this to work when device is unlocked, screen on, and with my app not in the foreground.
My code used to work just fine, so I suspect its googles changes to Android 10 and 11 that have stopped this working, but can it still be done?
My current code shown below
Many Thanks
Karen
/// <summary>
/// Assuming that the phone is not locked, and the screen is on, this brings the application to the foreground. It is used, for instance
/// where a patient event is inititiated while the user is viewing another app. The app is brought to the foreground by simply launching (or re-launching)
/// Main Activity
/// </summary>
public void BringToForeground()
{
var context = (Activity)MainApplication.ActivityContext;
KeyguardManager keyguardManager = (KeyguardManager)context.GetSystemService(Context.KeyguardService);
DisplayManager displayManager = (DisplayManager)context.GetSystemService(Context.DisplayService);
var displayOn = false;
foreach (var display in displayManager.GetDisplays())
{
if (display.State == DisplayState.On)
displayOn = true;
}
if (!displayOn || keyguardManager.IsKeyguardLocked)
return;
//Check if we are already foregrounded, if so, return, nothing more to do
var proteusAppProcess = new ActivityManager.RunningAppProcessInfo();
ActivityManager.GetMyMemoryState(proteusAppProcess);
if (proteusAppProcess.Importance == Importance.Foreground)
return;
//Not foregrounded so re-launch intent - since this APP is SingleTop, this will replace any existing activity
Intent resultIntent = new Intent(StaticDefs.Com_Spacelabs_EclipsePatientApp_Android_SwitchScreenIntent);
resultIntent.PutExtra(PageId.PageIdStringIdent, (int)PageId.RequestedPageId.PatientEventListScreen);
resultIntent.SetFlags(ActivityFlags.NoHistory | ActivityFlags.NewTask | ActivityFlags.SingleTop);
context.StartActivity(resultIntent);
}
Right, I think I can answer my own question - its due to the changes from Android 10 re who can launch foreground activities programatically.
To make the above code work, I needed to ask for the SYSTEM_ALERT_WINDOW permission and then manually visit (or programmatically open) the Android settings page for my app and enable the 'Appear On Top' option.
After doing that, my activity starts like it used to.
Unfortunately, given that this is a medical app, likely used by elderly folks, expecting folks to manually re-config the app is not realistic, so I will put up with notification tap to launch activity. It seems that the SYSTEM_ALERT_WINDOW permission is required even though my app runs as a foreground service - foreground services being a way around the Android 9 background execution limits!
Karen
In an AppWidgetProvider class, I have a simple CountDownTimer running.
object : CountDownTimer(30000, 1000) {
override fun onTick(millisUntilFinished: Long) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val views = RemoteViews(context.packageName,R.layout.view_group)
views.setTextViewText(R.id.m_text_view,"seconds remaining: " + millisUntilFinished / 1000)
appWidgetManager.updateAppWidget(appWidgetIds[0], views)
}
override fun onFinish() {
// Do nothing
}
}.start()
This updates the corresponding widget (appWidgetIds[0]) as expected, but this is only the case while the app is open. When I swipe off the app in the recents menu, I.e. closing it, the widget stops updating.
I have tried using a separate service too, but same result. Presumably because the service is not a foreground service, and I don't want to have a persistent notification so I can't use a foreground service.
When I swipe off the app in the recents menu, I.e. closing it, the widget stops updating.
That generally terminates your process, at which point your CountDownTimer no longer exists.
I have tried using a separate service too, but same result
That would not necessarily prevent your process from being terminated, though it might help get you a process back faster. However, on Android 8.0+, your service would be stopped after a minute.
Doing work every 30 seconds in the background is fairly evil from a battery consumption standpoint, which is why it is impractical on modern versions of Android.
Found the answer.
In the on the onStartCommand method of the service, return START_STICKY flag. This will tell the OS, if for any reason the service closes, run it again when you have enough resources.
source
more info
On restart, you can get all widget ids as follows:
ComponentName thisWidget = new ComponentName(context,MyWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
source
EDIT
Just so you know, in versions of android greater than API 23, even the START_STICKY flag isn't enough to get the OS to restart the service.
I've decided to skip this feature because it won't work in future versions of android.
I have an Android Service (implementation of Servcie interface) which is running on a separate process compared to my real app. Unfortunately when I leave my real App (in which I clicked the Button to start my Service) and swipe it out from Task Manager, my Service gets killed as well.
I know there are a lot of questions like this here, but somehow none are targeting the Problem in my concrete constellation or they are vaguely answered.
So in my manifest I have something like:
<application ...>
<activity .../>
<service Android:name="MyService"
Android:label="MyLabel"
Android:export="false"
Android:process=":MyRemoteProcessName" />
</application>
I first have played around with an IntentService, but also switched to an own implementation of the Service Interface (eliminating the IntentService to be the point of failure) which looks something like:
public class MyService extends Service {
private ScheduledExecutorService scheduledWorker = Executors.newSingleThreadScheduledExecutor();
#Override
public void onStart() {
// Init components
startForeground(this, MyNotification);
}
#Override
public int onStartCommand(Intent i, int startId) {
// Execute Work on Threadpool here
scheduledWorker.execute(new ScheduledStopRequest(this, startId), 5, TimeUnit.Minutes);
return START_REDILIVER_INTENT;
}
// Overwritten onDestroy-Method
#Override
public void onLowMemory() {
Log.e(LOG_TAG, "On Low Memory called!");
}
#Override
public IBind onBind() {
// Dont't want to let anyone bind here
return null;
}
// Simply tries to stop the service after e.g. 5 Minutes after a call
private static class MyRunnable implements Runnable {
// Constructor with params used in run method..
#Override
public void run() {
mReferenceToMyService.stopSelfResult(startId);
}
}
}
I'm starting my Service in an onClick-Listener on a special button, with an explicit Intent, which kinda looks like the following:
#Override
public void onClick(View v) {
Intent i = new Intent(this, MyService.class);
startService(i);
}
My Intention is to keep the Service running when the user leaves the app, so that the Service can finish downloading and storing some important data. When the user comes back to my app again, he can view the data (That's why I'm executing it in a separate process). So is this possible?
My assumption right now is, that Android somehow notices my Service is just being used by my App (due to missing IntentFilters in Manifest or explicit call rather than by filter?!) and thus kills it immediately when my App is closed (even when running as ForegroundService as you can see above).
Does it seem possible to you and might some changes in the call of the service fix this problem or am I getting the concept of a service wrong?
(One last note: onLowMemory-Method doesn't get called -> No log entries.)
So, according to your hints (and so new keywords for me to look for) and after some additional research by myself, I think I have solved my problem. During my research I have found an very interisting blog post on this topic, maybe also for you, which is why I would like to share it with you: http://workshop.alea.net/post/2016/06/android-service-kill/ .
After verifying and going through the steps in this article everything seems to work fine (so startForeground seems to solve the problem). I want to point out here, that I have only tested it, with my service instance still running in separate process, so manifest entries as is above.
The actual thing which really confused me at the beginning was my android studio debug session being killed everytime, just after swiping out my app from recent apps (menu). This made me think my service being killed by the system as well. But according to the article (I have added some logs to the callback methods provided) when
Opening my app
starting service
swiping out app
starting app again and finally
calling service again,
I only received callbacks to the methods as if my service would still be running. Having an explicit look at DDMS (tool) also prooved my 2nd process, and thus my service, being still alive. Having verified this, I then cleared all my app data and repeated the steps above (excluding step no. 5). Having had a look in the database afterwards, prooved the data having been downloaded by the service.
For the curious of you:
The process of swiping out my app from recent apps (and thus having the onTaskRemoved callback method being called) lead to another problem. It somehow increases the startId parameter of onStartCommand by 1 so that my DelayedStopRequest malfunctiones and doesn't stop my service anymore.
This means: Repeating above steps 1 - 3 makes me receive startId = 1 in onStartCommand. By calling stopSelfResult(1) later on (which was the latest startId) it returnes false and the service keeps running. Continuing to follow step 4 + 5 then, makes onStartCommand being called with startId = 3 (but should actually be 2! which is skipped somehow). Calling stopSelfResult(3) with parameter 3 later on is then going to stop the service again (also visible in screenshots).
I hope my answer is correct so far (, understandable) and also helpful for you. Thank you for all of your answers which provided beneficial input and also pointed me to the solution. The android version I have been working with is:
4.1.2 - Jelly Bean | API Level : 16
I also added screenshots of the log entries from DDMS (imgur is rejecting my uploads so you'll temporarily have a link to my dropbox):
screenshots from logs from DDMS
Unfortunately running service in a separate process does not help you. I think there is no way you can prevent your service from being closed if user removes its task. You can however restart your service overriding onTaskRemoved. See this answer.
If you want to run this service class indefinitely after closing the app also.. you should use Alaram Manager class ..
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(this, LocationListnerServiec.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, MyAlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
60000, pIntent);
}
Use this method for keep checking the service class is on or off.. By using this method Your service class will keep working after destroying of you application.
When my app starts, I load all the string data coming from the server in a hashmap and all the screens read from this hashmap in order to display button names, texts and screen titles.
I count on this object (and a lot of other similar objects)'s lives to be maintained for my app to remain functional.
I have found that, if I resume the app after a few hours it is still functional.
But if I open 10 more apps, leave them all open and resume the app after a few hours, it tries to read from one of these objects, but they are now gone!
In these cases, I find it best to kill the app and restart it, and tried doing so in the onDestroy of the main activity but this backfired because 5 seconds after I switch to another activity, onDestroy of the previous activity is called and the app gets killed using this code:
android.os.Process.killProcess(android.os.Process.myPid());
So I only want to kill the app when its been idle for hours AND the resources have been nullified.
This way when the user tries to resume it, it will die and start again, thus loading all the resources in the memory again.
I looked for an onDestroy method in Application class but there isnt one. Thre is an onTrimMemory method.
QUESTION IS:
How do I use Application.onTrimMemory() callback to kill my application IF resources that it needs have been destroyed?
EDIT: Actually, reading the onTrimMemory documentation, Im left with the impression that its me that should release memory by destroying objects, and if I dont do so, then how come after resuming the app, these objects are now null? I dont get it.
EDIT2:
I managed to partly solve my problem:
I downloaded a "Fill Ram" app from Google made for developers who want to see how their app behaves at low memory situations
I gradually started filling ram and saw how onTrimMemory methods were called with values or respectively 20, 40, 60 and 80
after each time I saw it being called in the logs I quickly resumed my app and then at around 60 or 80, the resources I needed were null
I inserted a null pointer check in onResume and if those resources were null, I did the following:
if (application.data == null || application.data.size() == 0) {
// Restart app so data is reloaded
Log.e("kill app", "kill app");
Intent mStartActivity = new Intent(this,MainActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
}
as pointed out here:
how to programmatically "restart" android app?
The problem remains semi-resolved, because I suppose at some other place in my app some other resource might go missing, so I am considering doing this in onTrimMemory 60 or 80?
I need some more help in understanding this.
Also, should I use
System.exit(0);
or
android.os.Process.killProcess(android.os.Process.myPid());
I did something else in addition:
in my base activity that all other activities extend, I added the following:
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level > TRIM_MEMORY_MODERATE) {
// Restart app so data is reloaded
android.os.Process.killProcess(android.os.Process.myPid());
}
}
There are lots of reasons why detecting if application is on foreground.
for example - as a trigger to GCM/C2DM push notification - lot's of apps would have good reason implementing different behavior when app is foreground and background.
Other reason could be - shotting down services consuming precious resources, such as querying servers in background task for instance.
Just to be clear: the definition (as I see it) for background app is:
application which none of it activities are invoked the onStart() method, and did not invoke yet the onStop() method.
that's because activity is visible to the user in it life cycle only at that time.
From the other hand -
seems like Google don't want application to react to the home button (it's not part of the API)
reacting to the onBackPressed() on the "root / main" activity as indicator for leaving Activity certainly not good idea (because lots of users using the home button, and not the back button)
there is no method in the API allowing determine if app is foreground (according to my definition..)
if I didn't miss something in the API, and it's really the case - Why there is no why to determine easily if the application is foreground or not????!!!!
what I know I can do to determine if the application is foreground is described in this thread - How to detect when an Android app goes to the background and come back to the foreground
but as #Emil saying - it's requiring special permission, or requiring some tricky logic's which very fast becoming problematic to maintain, and it smells like bad approach (although that's what I'm doing for now, because I don't have better idea...)
my questions basically are:
Is there no such API method from good reason?
Is taking into account if application is foreground or not is a bad approach?
Is there any other way to know if application is foreground or not?
is taking into account if application is foreground or not is a bad approach?
Taking foreground versus background into account is reasonable.
is there any other way to know if application is foreground or not?
You can roughly divide the scenarios for this into two groups:
Cases where you want to take an action immediately upon a change in the foreground/background status
Cases where some other event occurs (AlarmManager alarm, incoming system broadcast, etc.), and at that point you want to take different actions based upon whether or not you are in the foreground
In the former case, onUserLeaveHint() is your most reliable simple option. I cannot guarantee that it will cover all cases, but it should handle the HOME scenario, for example. You are also welcome to maintain a reference count of started activities in a static data member and try to use it instead.
In the latter case, an ordered broadcast can be useful.
With the new Android Architecture Components there is an easy way to know if your app is in the foreground or the background.
Just like with the activity scope lifecycle owner there is a general process lifecycle owner which you can subscribe to and get lifecycle updates.
For example:
Add this code in order to register as a lifecycle observer
ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleListener)
And this code in order to receive the relevant callbacks
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onApplicationOnStartEvent() {
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onApplicationOnStopEvent() {
}
Don't forget to remove the observer once you don't need it
ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleListener);
More information and examples can be found in this excellent article:
https://proandroiddev.com/detecting-when-an-android-app-backgrounds-in-2018-4b5a94977d5c
I had the same issue. I want to display push notification when my activity is not in foreground mode. Please go through following code and you will get your answer.
Context ctx = context.getApplicationContext();
ActivityManager am = (ActivityManager) context
.getSystemService(ACTIVITY_SERVICE);
// get the info from the currently running task
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
PackageManager pm = this.getPackageManager();
try {
/**
* take fore ground activity name
*/
ComponentName componentInfo = taskInfo.get(0).topActivity;
if (printLog == true) {
Log.d("Home", "CURRENT Activity ::"
+ taskInfo.get(0).topActivity.getClassName());
Log.d("Home", "Number Of Activities : "
+ taskInfo.get(0).numRunning);
Log.d("Home",
"Componenet Info : " + componentInfo.getPackageName());
Log.d("Home",
"Componenet Info : " + componentInfo.getClassName());
}
/**
* All activities name of a package to compare with fore ground
* activity. if match found, no notification displayed.
*/
PackageInfo info = pm.getPackageInfo(
"<PackageName>",
PackageManager.GET_ACTIVITIES);
ActivityInfo[] list = info.activities;
for (int i = 0; i < list.length; i++) {
Log.d("TAG","Activity : "+list[i].name);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
To use this, you have to take permission in your manifest file.
uses-permission android:name="android.permission.GET_TASKS"
Pardon me if I can't get your question.
If it is necessery for you to know if the app is on backround or foreground from a service that is running on the background(doesnt make sense otherwise), then you can just use binding, that is - bind to it on all your activities onResume, and unbind on all activities onPause. then in your service you can manage not only your application visibility to the user, but also which of the activities are open at any time. it is also leak-proof and more stable then a static variable (which can be cleaned up if necessery) as you are using android's API and relying on the correctness of the android OS code itself.