I will explain my app first. My app consists of a service running in the background. The service is waiting for a certain app to be opened (spotify in my case).
Whenever Spotify opens it needs to show this popup with buttons and text. It has to basicly look like this: imgur.com/QHWZpu6
I've already tried DialogFragment but that doesn't work since there is no FragmentManager in the service class.
Do you guys have any suggestions? Thanks in advance!
Detect if App is Running/Launched
Take a look at ActivityManager
The method you are concerned with is ActivityManager.RunningAppProcessInfo(). It returns the package names of current running apps as a list. All you have to do is iterate through list and check if it matches app package, which in your case is spotify.
ActivityManager activityManager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appInfos = activityManager.getRunningAppProcesses();
for(int i = 0; i < appInfos.size(); i++)
{
if(appInfos.get(i).processName.equals("package name"))
{
//USE INTENT TO START YOUR ACTIVITY AS EXPLAINED BELOW
}
}
Start Activity from Service
To start activity from your service, use Intent as following:
Intent popUpIntent = new Intent(this, MyActivity.class);
popUpIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(popUpIntent);
Popup Activity / Show as Dialog
In order to display your Activity as a dialog, you just need to set your activity theme to "Theme.Dialog" in your manifest file
<activity
...
android:theme="#android:style/Theme.Dialog"
...
/>
Or you can dynamically set the theme in the activity by calling setTheme() inside Activity class.
setTheme(android.R.style.Theme_Dialog);
A service class is not supposed to interact with the UI thread. A simple interaction to get past this is to use the service thread to update something stored in SharedPreferences and set a shared preferences change listener in the UI thread for whichever activity you want to handle the UI display.
void onSharedPreferenceChanged (SharedPreferences sharedPreferences,
String key)
Based on that image, it seems you actually want to display a UI element when you're activity is not currently the active application, you might want to consider a notification for this instead
Related
Basically, I have an activity which contains the code for a Video conferencing app. And I need to keep that in the background. So that when the user presses a button, I create a FloatingViewService, and send from my activity, the data to that FloatingViewService. And I can for example (This works), start a new intent, and use it to navigate through my app, while my previous activity is still working, and sending the data to the FloatingViewService.
Now my problem is that I don't want to start a random activity, but I want to go back to the previous activity, before starting the call.
When I start my call, I do it like this:
Intent intent = new Intent(HomeActivity.this, InCallActivity.class);
intent.putExtra("url", "url");
intent.putExtra("test", false);
startActivity(intent);
And note! After the second activity is created, if I call finish, it will take me to my HomeActivity. Which is awesome.
BUT I don't want to finish, I simply just want to go to the activity from which my class is being called.
I tried with: moveTaskToBack(true); but it sends the app to the home screen.
Also I made this code:
ActivityManager m = (ActivityManager) getSystemService(ACTIVITY_SERVICE );
List<ActivityManager.RunningTaskInfo> runningTaskInfoList = m.getRunningTasks(10);
Iterator<ActivityManager.RunningTaskInfo> itr = runningTaskInfoList.iterator();
while(itr.hasNext()){
ActivityManager.RunningTaskInfo runningTaskInfo = (ActivityManager.RunningTaskInfo)itr.next();
int id = runningTaskInfo.id;
CharSequence desc= runningTaskInfo.description;
int numOfActivities = runningTaskInfo.numActivities;
String topActivity = runningTaskInfo.topActivity.getShortClassName();
Log.i("","top activity: " + topActivity);
}
Thinking that I can reinstate the activity from the backstack, using the FLAG_ACTIVITY_REORDER_TO_FRONT
BUT, I don't get my activity back, why is that?
All I get is:
12-06 13:17:54.213: D/HeartRateApplication(3168): top activity: com.vidyo.vidyocore.activities.WebViewActivity
12-06 13:17:54.213: D/HeartRateApplication(3168): top activity: com.google.android.launcher.GEL
But if I do finish, clearly my HomeActivity is there, because it takes me back to it. Why don't I get it in my list from the running activities?
And how can I fix this?
EDIT:
There was a comment that said that I should start the activity with a intent. So I feel maybe I was not clear enough.
I cannot start an intent to a default Activity.
There is a chance that this InCallActivity will be called from multiple activities. Hence I need to know what activity was before it, so I can call an intent to that activity, WITH like I said FLAG_ACTIVITY_REORDER_TO_FRONT
Hence the logic to use the runningTaskInfo but that doesn't not provide me with the whole backstack. Is there another way to get the backstack, so I can actually know whay activity to start?
Start the activity using Intent.FLAG_ACTIVITY_CLEAR_TOP
Also you can refer
this
String Activity name= getIntent().getStringExtra("mActivityName");
use this to track your activity flow and name.
Without using an Intent and passing an extra parameter, is it possible to determine which Activity launched the current Activity?
There are two approaches to do.
the common one
use startActivityForResult in your calling activity to start the activity. Here I use ActivityCompat for backward compatibility.
ActivityCompat.startActivityForResult(this, new Intent(this, MyActivity.class), 0, null);
Then in the callee activity, you can use the following code to detect the calling activity.
if (getCallingActivity() != null) {
Log.d(TAG, getCallingActivity().getClassName());
}
NOTE
In the calling activity, you don't have to implement onActivityResult if you don't need transfer data from callee activity.
the deprecated one
use the system's back stack to get the recent tasks. But it won't work after API 21, it's deprecated after API 21.
declare the necessary permission in the mainifest.
<uses-permission android:name="android.permission.GET_TASKS" />
Then in your callee activity
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RecentTaskInfo taskInfo : activityManager.getRecentTasks(1, 0)) {
Log.d(TAG, taskInfo.baseIntent.getComponent().getClassName());
}
Only thing that crosses my mind is a HashMap with "lastActivity" "Activity" key and value.
It would be static so you can update it on every Activity incantation.
Or to save it as a SharedPreferences but that is the same as HashMap ...
Hope it helped, best regards!
You Application class allows setting an ActivityLifecycleListener. Whenever a new activity touches onCreate() you can push the stuff like activities toString() or getClass().getSimpleName() on a stack of Strings, then use it to identify it.
When I mention task below, I am referring to a specific Android concept here:
http://developer.android.com/guide/components/tasks-and-back-stack.html#TaskLaunchModes
Hi there,
Let's say there is a button in a base activity. When this button is pressed, a third party file viewer activity is launched from base activity through intent, which displays a file to the user. We do not set any flag in this intent, so I assume the viewer activity is in the same task as the base activity.
So when this viewer activity is in the foreground, is there anyway to detect Home button press, since this triggers the status of the current task to change (probably from having one activity in the foreground to having all of them in the background?)?
Any thought/idea/comment is highly welcomed!
Thanks!
This code at least get the name of the current top activity:
ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
topActivityName = tasks.get(0).topActivity.getPackageName();
}
In my app, I want to programmatically bring the most recently used third party Activity to the front. After looking at other answers here, I've tried relaunching the activity using the baseIntent returned from a list of recent tasks, but that does not seem to bring the activity to the front over whatever else is going on.
My end goal is to create an app that replaces the incoming call screen with a small overlay so the user is not pulled completely out of whatever app they are using when they get a call. I've found you can't replace the default incoming call screen (if this is not true, please let me know as I'd rather do that instead) so as a workaround, I am trying to call the most recently used app to the front of the screen (to overlay the incoming call screen) and then display my overlay on top of that.
Here's the code I am using (The activity is launched from a broadcast receiver)
public class BringMRUAppToFront extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ActivityManager activityManager = (ActivityManager) getSystemService("activity");
List<RecentTaskInfo> recentTasks = activityManager.getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED);
if(recentTasks.size() > 2) {
RecentTaskInfo recentTask = recentTasks.get(2);
Intent testIntent = recentTask.baseIntent;
Log.i("MyApp", "Recent task - " + recentTask.baseIntent.getComponent().getPackageName());
testIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(testIntent);
}
finish();
}
}
Is there a reliable way to bring any third party activity to the front? The activity is guaranteed to be in memory (if one is not in memory, then I would just display the home screen), so there shouldn't be an issue there. I also don't believe it would be a security issue in this case as it would just be displaying an app that was visible right before the phone rang - though I do understand that opening this up in general in the SDK could pose a risk...still hoping it is possible.
EDIT: Modified the code slightly to reflect what I'm doing. The desired task will almost always be the 3rd task in the list - first is the current task and second is the task of the ringing phone. I am able to call the task to the front, but it is not always in the same state (going to the browser's page instead of the settings screen in the browser, for example). How does the recent tasks list do this?
Figured it out by looking at the Android source code - this is exactly what the Recent Tasks screen does, both pre- and post-Honeycomb:
RecentTaskInfo recentTask = recentTasks.get(1); // task 0 is current task
// maintains state more accurately - only available in API 11+ (3.0/Honeycomb+)
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
am.moveTaskToFront(recentTask.id, ActivityManager.MOVE_TASK_WITH_HOME);
} else { // API 10 and below (Gingerbread on down)
Intent restartTaskIntent = new Intent(recentTask.baseIntent);
if (restartTaskIntent != null) {
restartTaskIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
try {
startActivity(restartTaskIntent);
} catch (ActivityNotFoundException e) {
Log.w("MyApp", "Unable to launch recent task", e);
}
}
}
Permission android.permission.REORDER_TASKS is necessary for this to work correctly.
Start from Android L, getRecentTasks() returns application’s own tasks and possibly some other non-sensitive tasks (such as Home), so you can not do such job.
References: https://developer.android.com/preview/api-overview.html#Behaviors
Why dont you use a global static variable that is accessed by all activities and on its onPause just set that variable to that activity value
Eg
I am placing a static variable called ActivityName
public static String ActivityName = "";
and in the onPause of every activity just assign it the activities pacakage name
#Override
public void onPause() {
super.onPause();
// The static global variable
com.pacakagename.Utls.ActivityName = "com.pacakagename.Act1";
}
So when any of the activity pauses the value is assinged and you will come to know of the most recent paused activity and you can restart it using Class.forName(ActivityName)
Here is my problem -
I copied my .apk file onto phone memory card and launch my application clicking on it and it allows me to install my application.I install my application.Finally,I got system installation pop up containing two options "Open" and "Done".When i click "Open" my application got launched.Up to this point everything is working without any problem.
Now in my application I click on a button and some download is taking place as a result(Showing progress dialog).Now I press a Home button,so my application goes to background.
Now I again launch my application by going inside Menu and clicking on my application icon.
Expected result - Still I Should see Progress Dialog for downloading.
Actual result - A new instance/session of my application is getting started.
So how to avoid this so that only one and one instance/session of my application should run.
#Palejandro, here you are. Put the code below into your main activity onCreate() method:
// Possible work around for market launches. See
// http://code.google.com/p/android/issues/detail?id=2373
// for more details. Essentially, the market launches the main activity
// on top of other activities.
// We never want this to happen. Instead, we check if we are the root
// and if not, we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
Log.w(TAG, "Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}
I used this piece of code in my projects and it works fine!
I believe you need to put
<activity
android:launchMode="singleInstance"
</activity>
in the manifest file.
what do your OnPause, OnResume and OnCreate?
I will bet money you are not saving anything OnPause, and starting a new instance all the time via OnCreate.
You should read the notes on Activity Lifecycles.
If you haven't got this sorted yet, I would say your app is actually being killed when home is pressed, or perhaps you have a bug that doesn't latch onto whatever object is keeping state.
// put below code in your launcher activity before call super and setcontentview()
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(10);
boolean alreadyTask=false;
for(ActivityManager.RunningTaskInfo info : taskInfo){
ComponentName componentInfo = info.topActivity;
String value= componentInfo.getPackageName();
if(value.contains(getPackageName()) && !info.topActivity.getClassName().contains(getPackageName()+".LauncherActivity")){
alreadyTask=true;
Log.i(TAG, "second instance found!!!");
break;
}
}
if(alreadyTask){
finish();
}
I don't have a solution but the problem is that the intent used to start the app is different when you open it directly from install compared to opening it from your home screen. Since it will get started by two different intents it will open a new instance the second time round.
A quick work around is to avoid pressing "Open" when you have installed the application. Press "Done" and then find the application yourself.
See: http://code.google.com/p/android/issues/detail?id=2373