In my project I am trying to bring my application to front after app is finished (User pressed back button). But it only gives me the last opened app to front. So if I am using a different app in the mean time it will open this app and not my app. Maybe some one can help me - I tried a lot of different combinations with Flags, but it didn't work. Additionally I didn't found a solution to get my app back if the display is locked - Maybe someone has a good solution for that or can give me advice.
Thanks
public class IncomingBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity myActivity = (MyActivity) context;
myActivity.doWork();
}
public class MyActivity extends Activity {
private boolean appInBackground = false;
...
#Override
public void onStop() {
appInBackground = true;
super.onStop();
}
#Override
public void finish() {
if (exitPressed) {
super.finish();
} else {
appInBackground = true;
moveTaskToBack(false);
}
}
public void doWork() {
// bring app to foreground
if (appInBackground) {
Intent intent1 = new Intent(getBaseContext(), MyActivity.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent1);
}
....
}
}
Android Manifest launchMode: android:launchMode="singleTask"
UPDATE:
I used my app to indicate incoming SIP calls, I had a look at the demo application for WalkieTalkieActivity (https://android.googlesource.com/platform/development/+/master/samples/SipDemo)
// main Activity
#Override
public void onCreate(Bundle savedInstanceState) {
...
callReceiver = new IncomingBroadcastReceiver ();
this.registerReceiver(callReceiver, new IntentFilter(
"com.example.INCOMING"));
...
// me = SipProfile
Intent i = new Intent();
i.setAction("com.example.INCOMING");
PendingIntent pi = PendingIntent.getBroadcast(getBaseContext(), 0,
i, Intent.FILL_IN_DATA);
manager.open(me, pi, null);
}
EXAMPLE:
My app is in foreground and I press back button to take it to back. Then I open another app for example hangouts, than I press the home button to go back to main screen. If the broadcast receiver gets an incoming call "INCOMING" than my app should appear, but it opens hangouts.
My app is in foreground and I press back button
When you press back button, the current activity instance is lost.hence the value of appInBackground set in
#Override
public void onStop() {
appInBackground = true;
super.onStop();
}
is lost too.
so next time when you receive the broadcast and arrive at public void doWork(), appInBackground is null.
Now I have found a solution: I should take the pendingIntent in my doWork() method and send it. Now my app is taking to front, even if it wasn't the last opened app. Thanks for the hints, now I have to work on bringing my app to front if screenlock is enabled. Any ideas?
public void doWork() {
// bring app to foreground
if (appInBackground) {
Intent intent1 = new Intent();
intent1.setClass(getBaseContext(),MyActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
pendingIntent.send();
}
...
}
Related
I am building an app to test all the hardware buttons on device. For Home button, I am starting a service and relaunching the same activity from that service(updating the UI that home button test is performed). The problem is, all the previous progress of tests is erased and this activity starts from scratch when it is relaunched. For ex: I performed back key, menu, volume up key and home in the given order. When activity is relaunched after home test, it considers the back key, menu, and volume up key as not performed.
When I launch this as an independent application, it works fine(app relaunches with previous progress intact) but when I launch it from a deep link URL then this issue arises.
Below is my code of my Service class:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
timer=new Timer();
TimerTask timerTask=new TimerTask() {
#Override
public void run() {
if(getRecentApp().equals(getLauncherPackage())){
if(VolumeKeyTest.isHomeKeyPressed) {
if(!isAppRelaunched) {
bringApplicationToFront();
}
//VolumeKeyTest.isHomeKeyPressed=false;
if(timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
}
}
}
};
timer.schedule(timerTask,0,500);
//return START_STICKY_COMPATIBILITY;
return super.onStartCommand(intent, flags, startId);
}
private void bringApplicationToFront() {
Intent notificationIntent = new Intent(getApplicationContext(),VolumeKeyTest.mClass);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
timer = new Timer();
try{
pendingIntent.send();
isAppRelaunched = true;
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
add this line to activity in manifest file
android:launchMode="singleTop"
Add this method to the same activity
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//do the task here to be refreshed
}
Whenever new intent is called it will open the same actvity which is previously opened. If not then it will open new activity.
Read this more clarification https://inthecheesefactory.com/blog/understand-android-activity-launchmode/en
I solved it using the link
https://inthecheesefactory.com/blog/understand-android-activity-launchmode/en
I added this to my <activity> tag in manifest
android:launchMode="singleInstance"
I have a PopUp activity that starts when the AlarmManager receives an alarm.
AlarmReceiver extends WakefulBroadcastReceiver:
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, AlarmService.class);
service.putExtras(intent);
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, service);
}
AlarmService extends IntentService:
#Override
protected void onHandleIntent(Intent intent) {
Intent i = new Intent();
i.setClass(this, PopUpActivity.class);
startActivity(i);
AlarmReceiver.completeWakefulIntent(intent);
}
PopUpActivity:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);
getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
setContentView(R.layout.layout_dialog);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ClientConstants.WAKE_LOCK_NOTIFICATION);
// Acquire the lock
wl.acquire();
if (canVibrate){
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(new long[]{ 0, 200, 500 },0);
}
if (canRing){
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(this, getAlarmUri());
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.prepare();
mediaPlayer.start();
}
} catch (IOException e) {
}
}
findViewById(R.id.dialog_ok_button).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
stopRinging();
finish();
}
});
// Release the lock
wl.release();
}
private void stopRinging(){
if (canRing && mediaPlayer.isPlaying())
mediaPlayer.stop();
if (canVibrate){
vibrator.cancel();
}
}
PopUpActivity is started from an alarm manager. If PopUpActivity is started when the application is not the active application, and if user presses "OK button", activity disappears. Nothing is wrong right here till now. The problem is, if user opens recent apps screen and selects the activity a new PopUpActivity is started again. How can i get rid off this problem?
When you declare your PopupActivity in your manifest, make sure you include android:noHistory="true". This will mean that as soon as you open "recents", the popup activity will be forgotten, and you will just return to where you were before when you re-open the app.
When user presses Ok button, Activity.finish() method is being called. This results in the Activity being destroyed. Hence when user selects the app from recent app section, the Activity is created again.
In case you don't want to destroy the Activity but want to put it in background, replace Activity.finish() method with Activity.moveTaskToBack(boolean).
findViewById(R.id.dialog_ok_button).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
stopRinging();
moveTaskToBack(true);
}
});
You need to handle scenarios wherein Activity is restarted after being killed due to memory shortage and configuration changes.
You can set FLAG_ACTIVITY_SINGLE_TOP in the Activity launch Intent flags, to ensure the new instance is not created if it is already running at the top of the history stack.
In your manifest, under the section for your Activity, try this:
<activity>
android:launchMode="singleTask"
</activity>
In case you want your Activity not to show up in your recent apps list, try
<activity>
android:excludeFromRecents="true"
</activity>
Hope this helps.
When you press OK button, you finish() the activity and selecting it again from history will obviously re-create it.
What you should do is hide this alarm activity from history/recents using android:excludeFromRecents="true"
and use launchMode = "singleInstance" with this so that android can never make another two instances of this activity at same time.
you can avoid from this problem simply by adding flag to the intent that starts the activity indicating not to be shown in the recent tasks:
Intent i = new Intent();
i.setClass(this, PopUpActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(i);
setting the Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS will make your PopupActivity invisible on the recent tasks.
What I want to do is quite simple: my application offers the user to watch a maximum of 10 min of video, then it stops the video and gets back to my application (previous activity). The video is shown in an external player with that code:
Intent intentVideo = new Intent();
intentVideo.setAction(Intent.ACTION_VIEW);
intentVideo.setData(Uri.parse(url)));
startActivity(intentVideo);
Then a background Service check periodically if time is elapsed or not.
How can my service kill the video activity (where I can't add code or listeners, or whatever, because it is provided by an external app) and make my app go back to its previous activity when time is elapsed?
Thanks
One way to solve this problem is to define a BroadcastReceiver inside the Activity. When the Service needs to notify the Activity that the time is up, send a broadcast and receive it in the BroadcastReceiver. Then, inside the onReceive() call finish() on the Activity to kill it. Hope this helps.
Okay here's my final code if it can help, thanks to Egor.
Note: Two solution are possible to force stopping the player activity:
using startActivityForResult(intent, rq) / finishActivity(rq)
using FLAG_ACTIVITY_CLEAR_TOP
Be careful using finishActivity(), some external apps won't close because of their behavior. For me it worked well when I open videos using VLC player, but not working when I open videos with Dailymotion app.
ActivityThatLaunchesPlayer.java
public class ActivityThatLaunchesPlayer extends Activity
{
private BroadcastReceiver brdreceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
System.out.println("broadcast signal received");
//either
finishActivity(57); //57 is my arbitrary requestcode
//or either :
Intent intentback = new Intent(getApplicationContext(), ActivityThatLaunchesPlayer.class);
intentback.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intentback);
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//set the brdcstreceiver to listen to the slot
getApplicationContext().registerReceiver(brdreceiver, new IntentFilter("com.example.portail10.timeElapsed"));
//here we launch the player (android opens a new appropriate activity)
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setData(Uri.parse(uri));
startActivityForResult(intent, 57); //again arbitrary rqstcode
//here we start the service that watch the time elapsed watching the video
intentServ = new Intent(this, TimeWatcher.class);
startService(intentServ);
}
}
TimeWatcher.java
public class TimeWatcher extends Service
{
//... some code is missing, but the main idea is here
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
//send the broadcast when time's up
Intent intentbrd = new Intent();
intentbrd.setAction("com.example.portail10.timeElapsed");
sendBroadcast(intentbrd);
System.out.println("Brdcast sent");
stopSelf();
}
}, 0, 600000); //in ms = 10min
return START_NOT_STICKY;
}
I have a broadcast receiver which will launch an Activity onReceive.
When launched, this activity will perform a long task and call finish() at the end.
I do not want to trigger another launch of Activity when the previous Activity is still performing the long task. How can I launch only a singletask activity? I have set this in the manifest.
android:launchMode="singleTask"
In my onReceive method,
public void onReceive(Context context, Intent intent) {
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activity);
}
Don't seems to work.
The Activity class actually is a MediaRecorder which will record a video clip (say 10 sec). Thus I do not want to trigger another Activity while this recording is still incomplete.
You just need to have some way for your activity to communicate to your receiver to let it know whether or not it is already running. If you have that then you can make an if statement in the receiver that will keep it from launching multiples.
One option is a static boolean in your activity that indicates whether or not you are currently running. Then you can check that boolean from the receiver, and if it is true, then don't call startActivity().
your activity would need something like this:
public YourActivity extends Activity{
public static isRunning = false;
public void onStart(){
...
isRunning = true;
}
public void onStop(){
...
isRunning = false;
}
}
now in your receiver you can make a simple if statement that will check the value of isRunning:
public void onReceive(Context context, Intent intent) {
if(YourActivity.isRunning == false){
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activity);
}
}
Please add these flags.
public void onReceive(Context context, Intent intent) {
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP |Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
context.startActivity(activity);
}
Good day, I have an activity which i navigate to from an icon on an appwidget using pending Intents. Everything is being done in a service class. Now, the activity has a refresh button which when pressed, it sends an intent that calls the onStart() method on the service to update itself and perform some web operations. How do i go about reflecting the changes that could have occurred from the service in the activity without temporarily existing the activity.
Service to Activity:
if(intent.getExtras()!= null){
appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
//if i get this action from my detailedinfo class add a boolean to it
if(intent.getAction() == refresh_action){
// boolean variable to hold condition
my_action = true;
}
Intent forecast = new Intent(this,detailedInfo.class );
forecast.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
forecast.putExtra("cityname", city);
PendingIntent forecastIntent = PendingIntent.getActivity(this, 0, forecast, 0);
/*onclick to go to detailedInfo class*/
remoteView.setOnClickPendingIntent(R.id.city_image_id, forecastIntent);
if(my_action == true){
//Log.d(TAG, "my_action is true, performing pending intent");
try {
forecastIntent.send(this, 0, forecast);
} catch (CanceledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And in the Activity class:
Intent service = new Intent(this, cityService.class);
service.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
service.setAction(refresh_action);
Uri data = Uri.withAppendedPath(Uri.parse(CityWidgetProvider.URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId));
service.setData(data);
startService(service);
I tried adding a setAction() method to the intent that calls the service and then use the same pendingIntent(even though i think is a long shot) but they seems to be ignored. Please how do i go about this and what could i have been doing wrong.? As usual any help is highly appreciated. Thank you.
I'm not 100% clear on what you're trying to do, but the easiest thing to do would be to register a BroadcastReceiver in your Activity onResume (remove it in onPause). When the service is done with whatever it needs to do, broadcast that info.
In the Activity
public static final String ACTION_STRING = "THE_BIG_ACTION";
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do whatever you want here
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(ACTION_STRING));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
In the service, when you're done, just call...
sendBroadcast(new Intent(YourActivityClass.ACTION_STRING));
If you want to include some data, just put it in the intent like you would when starting an Activity.
If your Activity is off screen when the service completes, and the user goes back to it, you'll have missed the notification. That's a different issue to resolve.