Launch application after PackageInstaller finished (self) updating - android

After the PackageInstaller successfully (self) updates the application, the application closes and doesn't launch again.
Possible duplicate: Android PackageInstaller, re-open the app after it updates itself
The situation is pretty similar, ill show some code snippets first.
AndroidManifest.xml
<receiver android:name=".UpdateReceiver" >
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
My PackageInstaller session runs in an AsyncTask:
PackageInstaller packageInstaller = ctx.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams parameters = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
parameters.setAppPackageName(StaticData.TerminalPackageName);
progressChanged(10);
try {
int sessionId = packageInstaller.createSession(parameters);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
ProgressApproximatorHandler progress = startProgressApproximator(10, 100, 5);
OutputStream installerStream = session.openWrite("INSTALL_TERMINAL", 0, mApplicationLength);
installerStream.write(firmwareData, 0, mApplicationLength);
// This call ensures every byte on the stream is committed to disk.
session.fsync(installerStream);
installerStream.close();
Intent intent = new Intent(ctx, UpdateReceiver.class);
intent.setAction(Intents.APK_INSTALL_FINISHED_INTENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext.get(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Sealing the session.
session.commit(pendingIntent.getIntentSender());
session.close();
progress.stop();
} catch (IOException e) {
Logger.error(mLogTag, e, "Failed to create an installer session.");
return false;
}
At the end of this snippet, you can see the setup of an Intent to send. I've tried many variations and none of them worked. For example:
Intent intent = new Intent(Intents.APK_INSTALL_FINISHED_INTENT);
and
Intent intent = new Intent("android.intent.action.MY_PACKAGE_REPLACED");
My receiver never receives the intent.
public class UpdateReceiver extends BroadcastReceiver {
private static final String TAG = "UPDATE";
#Override
public void onReceive(Context context, Intent intent) {
Logger.info(TAG, "Intent action: " + intent.getAction());
Logger.info(TAG, "updated");
}
}
EDIT: Somehow I managed to restart the app autimatically but it gets killed after a 1-3 seconds. I found the following error in the logcat of the system.
W/ActivityManager: Unable to send startActivity intent
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.MY_PACKAGE_REPLACED from pid=-1, uid=10071
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18195)
at com.android.server.am.ActivityManagerService.broadcastIntentInPackage(ActivityManagerService.java:18777)
at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:308)
at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:205)
at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:7409)
at android.content.IntentSender.sendIntent(IntentSender.java:190)
at android.content.IntentSender.sendIntent(IntentSender.java:154)
at com.android.server.pm.PackageInstallerService$PackageInstallObserverAdapter.onPackageInstalled(PackageInstallerService.java:1069)
at android.app.PackageInstallObserver$1.onPackageInstalled(PackageInstallObserver.java:34)
at com.android.server.pm.PackageInstallerSession.dispatchSessionFinished(PackageInstallerSession.java:1137)
at com.android.server.pm.PackageInstallerSession.-wrap2(PackageInstallerSession.java)
at com.android.server.pm.PackageInstallerSession$4.onPackageInstalled(PackageInstallerSession.java:648)
at com.android.server.pm.PackageManagerService.handlePackagePostInstall(PackageManagerService.java:1809)
at com.android.server.pm.PackageManagerService.-wrap25(PackageManagerService.java)
at com.android.server.pm.PackageManagerService$PackageHandler.doHandleMessage(PackageManagerService.java:1438)
at com.android.server.pm.PackageManagerService$PackageHandler.handleMessage(PackageManagerService.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.android.server.ServiceThread.run(ServiceThread.java:46)
I am not sure if this is the reason for it.
EDIT2: Now I receive the intent, thus the app is running. The problem now is that its in the back stack.
I have a launcher app that could re-launch the main (updated) app but that doesn't sound clean code to me.
EDIT3:
I tried David's answer but I receive the following error:
E/ActivityManager: Failure starting process com.example.myapp
java.lang.SecurityException: Package com.example.myapp is currently frozen!
at com.android.server.pm.PackageManagerService.checkPackageStartable(PackageManagerService.java:3197)
at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3789)
at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3749)
at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3630)
at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:1255)
at com.android.server.am.BroadcastQueue$BroadcastHandler.handleMessage(BroadcastQueue.java:172)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.android.server.ServiceThread.run(ServiceThread.java:46)
Note this is thrown by the android system, and not by my app.

The MY_PACKAGE_REPLACED Intent is broadcast by Android after your app is updated.
To restart your app after the update, you could pass a launch Intent to the PackageInstaller, like this:
Intent intent = getPackageManager().getLaunchIntentForPackage("my.package.name");
PendingIntent pendingIntent = PendingIntent.getActivity(
mContext.get(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(pendingIntent.getIntentSender());
This should cause your app to be restarted after the update is completed.

While David Wasser's answer was probably the right one. I am closing my case because I'm having very strange and undefined behaviour, and I am pretty sure that's because I am using a custom ROM

Related

Android - How to receive shortcut create result

Looking at the code sample here - I find the following comment puzzling:
// ... We assume here that the
// app has implemented a method called createShortcutResultIntent() that
// returns a broadcast intent.
what does it mean the app has implemented ... where is this implementation done?
is it a broadcast receiver? registered to which intent filter?
is this an abstract method? of which class?
and then I see this code sample - which handles a completely different flow (I think) and I'm lost again
You can obtain feedback via catching the broadcast event which you setup while use requestPinShortcut function.
At first you need a usual broadcast receiver (in the code below it has name ShortcutReceiver). You can even use existing broadcast receiver and simple add new action which it should catch.
Lets the action will be "general.intent.action.SHORTCUT_ADDED" and it will be stored in ShortcutReceiver.kInstalledAction constant. In this case in the manifest you should have:
<receiver android:name=".ShortcutReceiver" >
<intent-filter>
<action android:name="general.intent.action.SHORTCUT_ADDED"/>
</intent-filter>
</receiver>
After this you can use following code in the activity for create a pinned shortcut (in other places change this on object of Context class):
ShortcutManager manager = this.getSystemService(ShortcutManager.class);
Intent targetIntent = new Intent(ShortcutReceiver.kInstalledAction);
targetIntent.setPackage(this.getPackageName());
PendingIntent intent = PendingIntent.getBroadcast(this, 0, targetIntent, 0);
manager.requestPinShortcut(info, intent.getIntentSender());
In this code info is correct object of ShortcutInfo class.
You can handle the event while catch the broadcast:
public class ShortcutReceiver extends BroadcastReceiver {
public static final String kInstalledAction = "general.intent.action.SHORTCUT_ADDED";
#Override
public void onReceive(Context context, Intent intent) {
if (kInstalledAction.equals(intent.getAction())) {
// Handle the event after the shortcut has been added
Toast.makeText(context, "The shortcut has been added", Toast.LENGTH_LONG).show();
}
}
}
Please take into account that from my experience the broadcast event happens after the shortcut has been added but sometimes there can be some delays (at about some minutes). But may be there is some dependency on the launcher.
Update
As described in other answers on Android 8 catching of implicit intent via broadcast in general doesn't work.
So I simple changed the intent to explicit via set package name of the current app. So only our broadcast receiver can catch the intent.
First things first. Implicit intents on Android 8.0 Oreo:
Because Android 8.0 (API level 26) introduces new limitations for broadcast receivers, you should remove any broadcast receivers that are registered for implicit broadcast intents. Leaving them in place does not break your app at build-time or runtime, but they have no effect when your app runs on Android 8.0.
Explicit broadcast intents—those that only your app can respond to—continue to work the same on Android 8.0.
There are exceptions to this new restriction. For a list of implicit broadcasts that still work in apps targeting Android 8.0, see Implicit Broadcast Exceptions.
https://developer.android.com/about/versions/oreo/android-8.0-changes
Note: there are some exceptions: https://developer.android.com/guide/components/broadcast-exceptions (very few)
Instead, we will use the so-called context-registered receiver, it will last as long as our app lives, or until we unregister it.
Also, ShortcutManager requires API 25 that's why we will use it's compat version in order not to duplicate the code for old and new versions. (ShortcutManagerCompat was added in version 26.1.0)
Code to create a pinned shortcut on the Home screen:
public static void addShortcut(Context context, String id) {
if(context == null || note == null)
return;
//there may be various Home screen apps, better check it
if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)){
Intent shortcutIntent = new Intent(context, MainActivity.class);
shortcutIntent.setAction(Constants.ACTION_SHORTCUT); // !!! intent's action must be set on oreo
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, note.get_id().toString())
.setIntent(shortcutIntent)
.setShortLabel("MyShortcut") //recommend max 10 chars
.setLongLabel("Long shortcut name")//recommend max 25 chars
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut))
.build();
//callback if user allowed to place the shortcut
Intent pinnedShortcutCallbackIntent = new Intent(ACTION_SHORTCUT_ADDED_CALLBACK);
PendingIntent successCallback = PendingIntent.getBroadcast(context, REQ_CODE_SHORTCUT_ADDED_CALLBACK,
pinnedShortcutCallbackIntent, 0);
ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, successCallback.getIntentSender());
}
And here is the code to receive the broadcast in your Activity, for example. Note that this "callback" will be called only if your app is running, receiver is registered and the user allowed the shortcut:
private ShortcutAddedReceiver shortcutAddedReceiver;
private void registerShortcutAddedReceiver(){
if(shortcutAddedReceiver == null){
shortcutAddedReceiver = new ShortcutAddedReceiver();
}
IntentFilter shortcutAddedFilter = new IntentFilter(ShortcutHelper.ACTION_SHORTCUT_ADDED_CALLBACK);
registerReceiver(shortcutAddedReceiver, shortcutAddedFilter);
}
private void unregisterShortcutAddedReceiver(){
if(shortcutAddedReceiver != null){
unregisterReceiver(shortcutAddedReceiver);
shortcutAddedReceiver = null;
}
}
#Override
public void onStart() {
super.onStart();
registerShortcutAddedReceiver();
}
#Override
public void onStop() {
super.onStop();
unregisterShortcutAddedReceiver();
}
private class ShortcutAddedReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Snackbar.make(view, "Shortcut added", Snackbar.LENGTH_LONG).show();
}
}
Hope this helps!

Alarm manager is not triggering if app is killed

I am trying to create a scheduling application. I am using Alarm manager. It is working fine when app is alive. If I removed the app from recent applications Alarm is not triggering. Please let me any idea to resolve my issue. Herewith I attached my code.
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(SettingsPage.this, AlarmManagerForSettings.class);
i.putExtra("requestCode", "100");
i.putExtra("AlarmTag",id);
PendingIntent pi = PendingIntent.getBroadcast(SettingsPage.this, (int)id, i, 0);
am.cancel(pi); // cancel any existing alarms RTC_WAKEUP
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, time, AlarmManager.INTERVAL_DAY, pi);
ComponentName receiver = new ComponentName(SettingsPage.this, AlarmManagerForSettings.class);
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
Broadcast Receiver:-
public class AlarmManagerForSettings extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String requestCode = "";
String alarmTag = "";
if (bundle != null) {
requestCode = bundle.get("requestCode").toString();
alarmTag = bundle.get("AlarmTag").toString();
}
//Rest of code I wrote here
}
}
Manifest:-
<receiver
android:name=".AlarmManagerForSettings"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Some of the mobile Broadcast Receiver is not running..if Broadcast is not running follow below steps:
In Xiaomi devices, you just have to add your app to Autostart list, to do so, follow these simple steps given below:
1.Open Security app on your phone.
2.Tap on Permissions, it'll show you two options: Autostart and Permissions
3.Tap on Autostart, it'll show you list of apps with on or off toggle buttons.
4.Turn on toggle of your app, you're done!
How to get MIUI Security app auto start permission programmatically?
Write your alarm manager code in sticky server class and start this service as per yours functionality. Check after killing of app is updating.

BroadcastReceiver doesn't start activity when app closed

So, I've been trying to achieve that for at least five hours today and I've tried literally ANY solution found anywhere.
I'm programming a little clock app, using AlarmManager to make the app ring. It works fine when my app is open or minimized. I'm trying to make it work when the app is closed, and that's the problem. So, there is the piece of code that sets the AlarmManager :
AlarmManager am = (AlarmManager) ctxt.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ctxt, AlarmService.class);
PendingIntent pen = PendingIntent.getBroadcast(ctxt, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, nextRing.getTime(), pen);
(Here, ctxt is the context, I've tried both getApplicationContext() and getBaseContext() and nextRing.getTime() is a long that represents the date)
Then, I have my AlarmService class (wich used to be a service, which explain the name, but is now a BroadcastReceiver and I just don't want to rename it now)
public class AlarmService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
/*Intent cust = new Intent(context, CustomIntent.class);
context.startService(cust);*/
Bundle extras = intent.getExtras();
Intent newIntent = new Intent(context, AlarmActivity.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.putExtra("AlarmName", extras.getString("AlarmName"));
context.startActivity(newIntent);
}
}
So this is the try with only the BroadcastReceiver, wich doesn't work obviously, so I tried to add a IntentService (commented out code at the top) which has the following code
public class CustomIntent extends IntentService {
public CustomIntent() {
super("CustomIntent");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newIntent = new Intent(getBaseContext(), AlarmActivity.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(newIntent);
}
}
... and that's not working either ! Finally, here's the manifest I use :
<application>
[Here goes stuff that have nothing to do with my bug]
<receiver android:name=".custom_classes.AlarmService"/>
<service
android:name="com.group9.abclock.custom_classes.CustomIntent"
android:enabled="true" >
<intent-filter>
<action android:name="com.group9.abclock.custom_classes.CustomIntent" />
</intent-filter>
</service>
</application>
Sorry for the (very) long post but I tough I should explain anything I tried. Thanks in advance if you can help !
If your application is closed, you can't trigger a BroadcastReceiver because it's not registered, and you can't use Context methods because there is no Context.
If you want to execute tasks while the application is closed, you have to create another project with a Service, and start it with your application.
A Service runs in background until someone kill it, and once it's started, the main application is not needed anymore. So the ring functionality have to be implemented in this service.
Just remember that the AlarmManager.setExact, is not that exact from API 23, due to Doze Mode.

Android Notification Action is not fired (PendingIntent)

I am trying to add an Notification action item in my app which is a music player. When a stream is started a notification should be triggered and an stop button for the stream should be displayed in the notfication. The notification working fine so far, I am having trouble with the stop action item. Here is how it is declared in the service starting the stream:
Intent stopIntent = new Intent(this, MusicPlayerNew.class);
stopIntent.putExtra("STOP", "STOP");
PendingIntent stopPendingIntent = PendingIntent.getActivity(this, 0,
stopIntent, PendingIntent.FLAG_UPDATE_CURRENT, null);
mBuilder.addAction(R.drawable.ic_stat_stop, "Stop", stopPendingIntent);
Now in the onResume()-method of my activity I check with getIntent().getStringExtra() for the "STOP" extra, but the intent I retrieved via getIntent() has no extras set :(
I also tried to check to send an broadcast (i have a broadcast receiver working to communicate from the service to the activity)
Intent stopIntent2 = new Intent(MusicPlayerNew.STOP_MEDIAPLAYER);
PendingIntent stopPendingIntent2 = PendingIntent.getBroadcast(this, 0,
stopIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.addAction(R.drawable.ic_stat_stop, "Stop", stopPendingIntent2);
Now this works if the activity is currently in the foreground. If the activity is in the background the stop button does nothing :(
EDIT:
I have the BroadcastReceiver in my Activity as a private class
private class DataUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
..
}}
In the onResume() register my app for this receiver:
intentFilter = new IntentFilter(STOP_MEDIAPLAYER);
registerReceiver(dataUpdateReceiver, intentFilter);
onPause()
unregisterReceiver(dataUpdateReceiver);
Now if I remove the unregistering from the onPause()-method the broadcast is received even if the app/activity is not in the foreground anymore. But is this the right way to do it? I got this register/unregister-stuff from a tutorial on the web i think..
This is very late answer but it may help someone:
You should choose the right kind of Pending intent based on the intent you want to run. Here are some Examples:
For Activity use below:
Intent i = new Intent(this, YourActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
For Service use below:
Intent i = new Intent(this, YourService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
For Broadcast Receiver use below:
Intent i = new Intent(this, YourReciver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
You may need to change the request code and Flags if required
I find solution in this thread on google code https://code.google.com/p/android/issues/detail?id=61850
To fix it you must add PendingIntent.FLAG_CANCEL_CURRENT flag to your PendingIntent.
PendingIntent stopPendingIntent2 = PendingIntent.getBroadcast(this, 0,
stopIntent2, PendingIntent.FLAG_CANCEL_CURRENT);
I ran into this problem today. In my case it was using cached intent extras from a previous instance of the intent as all the parameters for the pendingIntent constructors was same. I found two solutions for this...
Using FLAG_CANCEL_CURRENT as mentioned by Nik.
Passing an unique requestCode to the pendingIntent as follows
PendingIntent pi = PendingIntent.getService(this, UNIQUE_ID, pi, 0);
In my case, the second method solved the problem as I need to keep the previous notifications alive. May be this will help someone with similar issue.
I ran into this problem today and it was caused by the activity not being registered or added to AndroidManifest.xml. I thought I had it in there but it wasn't. Also, no errors were being logged by trying to invoke the action with its intent.
I figured this out by creating an intent and then calling startAcitivty(intent) without using a notification. It then gave me an error stating the activity was likely missing from the manifest.
If none of the other answers solve your problem then hopefully this will. Usually tricky problems are the result of something simple and silly.
Do not use explicit Intent
In my case, I created a dynamically context registered BroadcastReceiver within my Service class for listening the notification actions.
class MyService:Service(){
private val receiver: BroadcastReceiver = NotificationActionReceiver()
...
inner class NotificationActionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
...
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
...
registerReceiver(receiver,IntentFilter("SOME_ACTION"))
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
...
unregisterReceiver(receiver)
super.onDestroy()
}
PendingIntent with explicit Intent
val nextIntent = Intent(this, NotificationActionReceiver::class.java) //Explicit Intent
val nextPendingIntent: PendingIntent= PendingIntent.getBroadcast(this,0x11,nextIntent, PendingIntent.FLAG_CANCEL_CURRENT)
However with this setup, the BroadcastReceiver never triggered.
In order to make it work I need to replace my explicit intent with the implicit one
So all I did was,
val nextIntent = Intent("SOME_ACTION") //Implicit Intent
val nextPendingIntent: PendingIntent= PendingIntent.getBroadcast(this,0x11,nextIntent, PendingIntent.FLAG_CANCEL_CURRENT)
NOTE: Since the BroadcastReceiver is dynamically context registered, you don't have to worry about restrictions on implicit intents
More than using broadcast receiver, you should use a service and declare a new action in your service this way:
public final String ACTION_STOP = "yourpackagename.ACTION_STOP";
And then create your intents like this:
Intent stopIntent = new Intent(this, YourService.class).setAction(YourService.ACTION_STOP);
PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, 0);
Of course, stop playback in your service's function startCommand, if the intent's action equals ACTION_STOP.
This should do the trick ;)
You do not receive the broadcast when it is in the background because you are unregistering in onPause. Move the unregisterReceiver code to onDestroy function. This will be called only when the activity is destroyed. Or you can unregister once the expected event has occurred.
There are multiple questions here:
Part 1: Why is your intent not receiving the "STOP" extra?
Though it is not seen in the code you have provided, I wanted to confirm if you are using the flag FLAG_ACTIVITY_SINGLE_TOP for the notification intent ? If so, the intent you receive in your activity would be the intent that started the activity and hence the "STOP" extra will not be available. You will need to extend the onNewIntent() is this case (where the new intent is sent). More info here.
If you have not used FLAG_ACTIVITY_SINGLE_TOP, then it means that a new activity is created when notification is tapped, in which case the Intent must have the "STOP" parameter. If you can provide me all relevant code, I can help you better.
Part 2: Using Broadcast Receiver
This is not straight forward, as you already discovered. You would need to unregister in onDestroy and if your activity is closed by the user, the onDestroy may be called and your broadcast receiver may not active at the time the notification is tapped by the user. If you dont unregister at all, it may seem to be working, but this is a memory leak, GC may clean up anytime which could lead to a crash in your program, ie., you MUST unregister. If you need to go with broadcast receiver approach, you need to have a service to do this and service comes with its own pitfalls -> restart by system, battery drain etc. I would strongly recommend you go with your first approach.
I had a very similar issue but a very different solution. Pending intent is also not fired if you have declared <service android:enabled="false"></service> in your manifest.xml file.
Replace from android:enabled="false" to android:enabled="true"
This might not be a direct issue of the problem. But if you create the service in android studio using default template it automatically adds these properties to the service.
For me, the solution was to set the flags of the intent :
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK);

How do you start an Activity with AlarmManager in Android?

I've poured through a dozen tutorials and forum answers about this problem, but still haven't been able to get some working code together. I'll try to keep the question straightforward:
How do you use AlarmManager (in the Android API) to start an Activity at a given time? Any solution to this problem will do.
My latest attempt to achieve this is below.
(Imports omitted. I expect MyActivity to start 3 seconds after the program is opened, which it doesn't. There are no error messages to speak of.)
public class AndroidTest2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = this;//.getApplicationContext();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); // CORRECT
Intent intent = new Intent(context, myReceiver.class); // CORRECT
PendingIntent pending = PendingIntent.getBroadcast( context, 0, intent, 0 ); // CORRECT
manager.set( AlarmManager.RTC, System.currentTimeMillis() + 3000, pending ); // CORRECT
setContentView(R.layout.main);
}
}
public class myReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent i=new Intent(context, myActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
public class myActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("", "Elusive success");
setContentView(R.layout.main);
}
}
Any advice would be appreciated.
Please note: I've got myReceiver in the manifest already
In case someone else stumbles upon this - here's some working code (Tested on 2.3.3 emulator):
public final void setAlarm(int seconds) {
// create the pending intent
Intent intent = new Intent(MainActivity.this, AlarmReceiver.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0,
intent, 0);
// get the alarm manager, and scedule an alarm that calls the receiver
((AlarmManager) getSystemService(ALARM_SERVICE)).set(
AlarmManager.RTC, System.currentTimeMillis() + seconds
* 1000, pendingIntent);
Toast.makeText(MainActivity.this, "Timer set to " + seconds + " seconds.",
Toast.LENGTH_SHORT).show();
}
public static class AlarmReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d("-", "Receiver3");
}
}
AndroidManifest.xml:
<receiver android:name="com.example.test.MainActivity$AlarmReceiver" >
</receiver>
Issues with BenLambell's code :
EITHER:
Move the receiver to it's own .java file or
make the inner class static - so it can be accessed from outside
Receiver is not declared correctly in the manifest:
if it's an inner class in MainActivity use:
<receiver android:name="package.name.MainActivity$AlarmReceiver" ></receiver>
if it's in a separate file:
<receiver android:name="package.name.AlarmReceiver" ></receiver>
If your intention is to display a dialog in the receiver's onReceive (like me): that's not allowed - only activities can start dialogs. This can be achieved with a dialog activity.
You can directly call an activity with the AlarmManager:
Intent intent = new Intent(MainActivity.this, TriggeredActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) getSystemService(ALARM_SERVICE)).set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + seconds * 1000, pendingIntent);
How do you use AlarmManager (in the Android API) to start an Activity at a given time?
Supply a PendingIntent to the set() call that identifies the activity to start up. Or, do what you're doing, which should work just fine.
This sample project is a bit elaborate, because it's 19 tutorials deep into one of my books, but if you look at classes like EditPreferences, OnBootReceiver, and OnAlarmReceiver, you will see the same basic recipe that you're using above. In this case, I could have just used a getActivity() PendingIntent, but the tutorial after this one gives the user a choice of launching an activity or displaying a Notification, so a BroadcastReceiver makes more sense.
Look for warnings in addition to errors in LogCat. Most likely, your receiver or activity is not in your manifest.
Note that popping up an activity out of the middle of nowhere is generally not a good idea. Quoting myself from the book in question:
Displaying the lunchtime alarm via a full-screen activity certainly works,
and if the user is looking at the screen, it will get their attention. However,
it is also rather disruptive if they happen to be using the phone right that
instant. For example, if they are typing a text message while driving, your
alarm activity popping up out of nowhere might distract them enough to
cause an accident. So, in the interest of public safety, we should give the user an option to
have a more subtle way to remind them to have lunch.
add this in your android mainifest file and it will hopefully work
<activity android:name=".MyReceiver" />
<receiver android:name=".MyReceiver"> </receiver>
In my experience you can achieve this without broadcast receiver, just use PendingIntent.getActivity() instead of getbroadcast()
private void setReminder(){
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar startTime = Calendar.getInstance();
startTime.add(Calendar.MINUTE, 1);
Intent intent = new Intent(ReminderActivity.this, ReminderActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(ReminderActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC, startTime.getTimeInMillis(), pendingIntent);
}
I've tested this code on android O but I'm not sure about other android versions please inform me if this doesn't work on any other android version.
Main Problem : if you close completely you're app and expect to start you're activity after 3 seconds, you wrong. because when you close you're app , you're app cant receive broadcast, for solve this problem use services instead of broadcasts.
Point: when you're service would ran ,you cant start your activity if your app wouldn't in foreground.
Solution: I think when your service started you can again set Alarmmanager to start your activity with PendingIntent for just now.
Remember :
When you create your intent for pass it to pendingIntent add the FLAG_ACTIVITY_NEW_TASK to it.
For this PendingIntent use PendingIntent.getActivity() method and for the first PendingIntent use PendingIntent.getService() method.
I hope this help you.
I had this problem too long ago to know which answer is correct, but thank you to everyone for their responses. I'm self-answering so the question isn't still open.
According to Java convention class name begin with Capital letter.So change your
"myReceiver" to "MyReceiver" and "myActivity" to "MyActivity".
Then add your receiver in the manifest file like the below.
<application
------------
<receiver android:name="MyReceiver"></receiver>
---------------------
</application>
you are not sending any broadcast for the receiver to receiver and further more it lokks like u want a splash screen or something like that for that purpose u can start a new thread wait for some sec then start ur activity in that and for that time period u can do what ever u want on the UI thread ...

Categories

Resources