I have an app that automatically starts a few seconds delayed after boot. BTW: This is nothing evil! The user must enable it by himself! When I now tap on the app's icon I would like to have the same instance being opened that was already started at boot. I don't want the app to restart. But this is what happens right now.
Background: I'm writing some debug info to a TextView. When the app starts at boot, it is immediately put to background with moveTaskToBack(true), because it should not cover the screen of course. The user should see the IDLE screen. So the app (and in turn this output) can only become visible when the app is opened manually.
Here is the AndroidManifest.xml:
<application android:icon="#drawable/fritzbox"
android:label="#string/app_name"
android:allowTaskReparenting="true"
android:persistent="true">
<uses-library android:name = "com.google.android.maps" />
<receiver android:name=".BootUpReceiver">
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
<category android:name = "android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name =".WiFiOnDemandActivity"
android:label="#string/app_name"
android:allowTaskReparenting="true"
android:launchMode="singleInstance">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
As you can see I've already tried android:launchMode, android:allowTaskReparenting and android:persistent. The broadcast receiver that receives the BOOT_COMPLETED broadcast creates a PendingIntent that is scheduled with the AlarmManager. So the app is started 15s (START_DELAY) after boot. Here is the code:
public class BootUpReceiver extends BroadcastReceiver implements Defines
{
private AlarmManager mAlarmManager = null;
private Intent mIntent = null;
private PendingIntent mPendingIntent = null;
#Override
public void onReceive( final Context context, final Intent intent)
{
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE );
mIntent = new Intent ( context, WiFiOnDemandActivity.class );
mIntent.setAction(intent.getAction());
mIntent.addFlags ( Intent.FLAG_ACTIVITY_NEW_TASK );
mPendingIntent = PendingIntent.getActivity( context, 0, mIntent, 0);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + START_DELAY, mPendingIntent );
}
}
Strangely enough sometimes it seems to work as expected (no restart) but sometimes it doesn't!
Thanks!
Bernd
Do show your code, but this cannot be guaranteed. The system may kill your process at any time if memory is low, so you might get a new process when you start via the launcher. What makes you think you need the exact same instance?
Related
I'm developing an app, which sends notifications in a proper time in a future. If I call AlarmManager.init () in main activity - it gives me Toast after 5 seconds on Samsung Galaxy Tab 3 and LeEco Le 2, as it should. But if I call AlarmManager.init () and kill my app (swipe it off) - I still get Toast on Samsung Galaxy Tab 3, but I dont get it on LeEco Le 2. What is my problem?
AlarmManager:
public class AlarmManager {
static android.app.AlarmManager alarmManager;
static Context context;
public static void init (Context c) {
context = c;
alarmManager = (android.app.AlarmManager) context.getSystemService(ALARM_SERVICE);
Intent intent = new Intent("com.fome.planner");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
5 * 1000, alarmIntent);
}
}
Receiver:
public class MyReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.e("type", intent.getAction());
StringBuilder msgStr = new StringBuilder("current time: ");
Format formatter = new SimpleDateFormat("hh:mm:ss a");
msgStr.append(formatter.format(new Date()));
Toast.makeText(context, msgStr, Toast.LENGTH_SHORT).show();
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name="android.support.multidex.MultiDexApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.NoActionBar">
<activity android:name=".DayActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_places_key" />
<activity android:name=".TaskCreationActivity" />
<activity android:name=".CalendarActivity" />
<activity android:name=".ListActivity" />
<receiver
android:name=".MyReceiver"
android:process=":remote"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.fome.planner"/>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
The app is probably killed when you swipe it off on your LeEco Le2 while Samsung puts your app to the background. Check the application page to see if it is still running after swipe or if it is in force stopped state.
I am trying to resume my activity from a notification, but it is recreating the activity and not resuming.
As all posts regarding this issue, mention creating a PendingIntent and setting this with the appropriate flags (as shown in code below), and adding the singleTop|singleInstance to the AndroidManifest.
Notification Code:
NotificationManager mNotifyMan = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMan.cancelAll();
Notification.Builder mNB = new Notification.Builder(this);
mNB.setOngoing(true);
Intent intent = new Intent(parentContext, main.class);
intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
PendingIntent pendingIntent = PendingIntent.getActivity(parentContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mNB.setContentIntent(pendingIntent);
mNB.setSmallIcon(R.drawable.ic_notify_icon);
mNB.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_noti_large));
mNB.setContentTitle(Title);
mNB.setContentText(Message);
mNB.setColor(0);
mNotifyMan.notify(777, mNB.build());
I understand one must pass an intent with the current context.
When resuming an activity via the onPause() on onResume(), it resumes and restores the last activity state, i.e. a thread counter running has incremented values.
Problem:
When resuming from the notification (i.e. clicking on the notification), the activity is recreated. I have attempted to resolve this by
when onPause() is executed, sending the current activity state via base class to the notification, thus recreating the notification with the current state.
Here is my AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cynetstudios.wifimanager">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.wifi" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:launchMode="singleInstance">
<activity android:name="com.cynetstudios.frequencyselector.main" android:configChanges="orientation|screenSize|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.cynetstudios.frequencyselector.serviceWifiFreqManager" android:exported="false"/>
</application>
</manifest>
I might be missing something trivial, any advice?
You can set your Activity's launchMode SingleTask, SingleTop or SingleInstance depending on how you want your activity to act.
Later you can handle your activity's onNewIntent method if your activity is open when user clicks your active notification.
Also you need to define activity's launchMode in that atcitvity's part. I edited your xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cynetstudios.wifimanager">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.wifi" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="com.cynetstudios.frequencyselector.main"
android:configChanges="orientation|screenSize|keyboardHidden"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.cynetstudios.frequencyselector.serviceWifiFreqManager" android:exported="false"/>
</application>
</manifest>
I hope this'll help you.
launchMode should be used in Activity section (not application)
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClass(this, main.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startActivity(intent);
You can try this Intent. Such an intent is used by system app launcher, which will just show(no recreate) your activity if it is not killed.
Try
Intent.FLAG_ACTIVITY_CLEAR_TOP
with
Intent.FLAG_ACTIVITY_NEW_TASK
Set them as flags for the intent
Try this it may help you:
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
and as #Alexander says put android:launchMode="singleTop" into activity tag
I have researching for hour and hour and found many similar question but have no a working solution for my question.
I'm understand if I close the app by force close that is normal that I not receive data from gcm. But I was unable to receive the notification with gcm until I start the app. So the application is running either foreground or background then I only be able to receive the data from gcm but when I close the app by sliding away it (which is not done by force close) the notification didn't show up which mean gcm wasn't receive any data at all. . So it mean I need to stay active but if I do so then there is no point for using gcm anymore which design for pushing notification.
Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.khooteckwei.google" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.example.gcmtesting.google.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcmtesting.google.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.gcmtesting.google" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
</application>
</manifest>
here is the wakefulBroadcastReceiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
The notification working fine when the app is active so I didn't include the function that use to display notification.Is there any problem with this 2 pages?
I think your problem is in your GcmBroadcastReceiver receiver, you can look at this link , I think it's will help you with GCM http://www.intertech.com/Blog/push-notifications-tutorial-for-android-using-google-cloud-messaging-gcm/
I think notifications doesn't work because your receiver doesn't check do your app running or not , if it is you need to handle notification or if not show android notification
I have read several answers about this question, but the posted solution doesn't work for me. Probably there is something wrong or missed in my code.
I need that my app, with no activity, starts automatically after the boot completed.
If I include an activty, just to start for the first time the app (exiting the stopped state), everything works.
Thank you in advance for your help.
Here is my code.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="zag.salva" >
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name=".Salva_autostart"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".Salva_servizio"
android:enabled="true" >
<intent-filter>
<action android:name=".Salva_servizio" />
</intent-filter>
</service>
</application>
Salva_autostart.java
public class Salva_autostart extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent intento = new Intent(context, Salva_servizio.class);
intento.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.startService(intento);
}
}
Salva_servizio.java
public class Salva_servizio extends Service
{
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// Task execution
Salva_invio2 invio = new Salva_invio2();
invio.esegui(this);
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
You shouldn’t add FLAG_INCLUDE_STOPPED_PACKAGES to your receiver's intent that start your service. You have to add it to the intent that you use for sendBroadcast. Meaning, you need to add it to the intent in the application that invokes the Broadcast.
That is why this flag is irrelevant in your code.
If you will sendBroadcast to this receiver ("Salva_autostart") just once, from outside your application - then your application will not be in "force stop" state any more and on next boot your receiver will be triggered.
Also you should add (addFlags) and not set (setFlags).
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
This is how you should trigger your receiver from another application:
Intent intent = new Intent("com.xxx.my_filter_intent");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
this.sendBroadcast(intent);
On your manifest add the above filter intent to your receiver (you can add it in new <intent-filter> or in the same that you already have for the BOOT_COMPLETED action.
<receiver
android:name=".Salva_autostart"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="com.xxx.my_filter_intent" />
</intent-filter>
</receiver>
Read more here:
http://developer.android.com/about/versions/android-3.1.html#launchcontrols
Note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.
I'm trying to rig together a service that simply issues a notification on "boot" and then another one once the service is running. I'm using the following for my manifest:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="my.project"
android:versionCode="1"
android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17"
/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
>
<service
android:name=".Manager"
/>
<receiver
android:name=".Bootstrap"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Unfortunately when I reboot my device, nothing displays and it seems like the service is never started.
Here is the implementation for my BroadcastReceiver subclass:
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Test", "Bootstrap run!");
int notificationId = 1;
NotificationCompat.Builder startNotification = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Glance")
.setContentText("Starting the Glance service.")
;
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, startNotification.build());
//
// Run the service.
//
Intent startServiceIntent = new Intent(context, Manager.class);
context.startService(startServiceIntent);
}
Any suggestions on what I might be doing wrong or missing here that's causing things not to work?
Thanks!
If you are testing this on Android 3.1, please add an activity to your application, then run your activity. Starting with Android 3.1, manifest-registered BroadcastReceivers are blocked until something manually runs one of your components, which typically means a user has launched one of your activities. See this nearly-two-year-old blog post for more details.