How to approximate PendingIntent getActivities in Api level 7 (Android 2.1)? - android

I wish to have an app that targets Android 2.1, API level 7, launch multiple activities at once when a user clicks on a C2DM notification that has come in. This is the method I currently use to launch my activity:
public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
This method only allows me to put one activity on the stack. What I really want to do is use this method:
public static PendingIntent getActivities (Context context, int requestCode, Intent[] intents, int flags)
This method reports that it is only available for API level 11, which is Android 3.0. I do not wish to break backward compatibility with 2.1. Can anyone suggest how I might be able to achieve this effect without taking a dependency on Android 3.0? I tried looking for the source to this new method, but it does not appear to be available yet.

What you do is have a separate activity that is the target of the alarm, and build the intent stack from there, as below. This could probably be generalised into something very like 'getactivities' quite easily - it's a pity it isn't in the compat libraries.
public class AlarmActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
intent = new Intent(this, ChildActivity.class);
startActivity(intent);
finish();
}
}

As MisterSquonk says in the comments, only one Activity can be active at any one time (even in 3.0), so launching "multiple activities at once" is not going to be possible. Even if it were, what will the user experience be like with multiple activities starting in quick succession, and no guarantee of which will be launched last, and so be the one left for the user to interact with.
I suspect that you actually want to wake up different parts of your app simultaneously without each one having its own UI. If so, then I would suggest having one or more Services which implement multiple BroadcastReceivers against a common Intent filter. When you fire a Broadcast of that event, then multiple things will get woken up at once.

Related

Intent.FLAG_ACTIVITY_REORDER_TO_FRONT not working in android 11

I need to bring the app from background to foreground when push notifications arrives. This code
works fine on versions prior to 11.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
...
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
...
}
But stops working in android 11. Any idea?
Thanks!!
Posting comment as answer:
AFAIK, Its not possible to start activities from the background since Android 10 unless your app meets one of the specific exceptions, see here. Are you sure your app was in the background? Also Intent.FLAG_ACTIVITY_REORDER_TO_FRONT should have nothing to do with actually starting the activity, it just moves to it the front of the stack if it is already running.

Android - launch app from broadcast receiver

I want the broadcast receiver to launch my app this way:
If the app is not in the foreground or background, launch it as if it is launched from launcher.
If the app is in the background, bring it to the foreground with the state it was last in.
If the app is in the foreground, do nothing.
Here is my code:
#Override
public void onReceive(Context context, Intent intent) {
Intent launch_intent = new Intent("android.intent.action.MAIN");
launch_intent.setComponent(new ComponentName("com.example.helloworld","com.example.helloworld.MainActivity"));
launch_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
launch_intent.addCategory(Intent.CATEGORY_LAUNCHER);
launch_intent.putExtra("some_data", "value");
context.startActivity(launch_intent);
}
MainActivity is my root activity. Like I said, if the app is already running, I just want it brought to the front without changing its state. If there is some activity on top of MainActivity, leave it as it is.
Most of the time the above code worked fine, but sometimes I noticed that the app was restarted (or the state was reset --- the root was back on top) when it was brought from the background.
What code should I be using? Any help is appreciated!
You don't need to write all that code. You can use a "launch Intent", as follows:
PackageManager pm = context.getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage("com.example.helloworld");
launchIntent.putExtra("some_data", "value");
context.startActivity(launchIntent);
However, your code should also work.
If you say this works most of the time, you might be seeing a nasty old Android bug in those cases. This occurs when you launch your app for the first time either directly from the installer, or via an IDE (Eclipse, Android Studio, etc.). You should always launch your app for the first time directly from the HOME screen or list of installed apps. For more information about this frustrating Android bug see https://stackoverflow.com/a/16447508/769265
Since you need behaviour like
1) If the app is not in the foreground or background, launch it as if it is launched from the launcher.
2) If the app is in the background, bring it to the foreground with the state it was last in.
3) If the app is in the foreground, do nothing.
Consider:
#Override
public void onReceive(Context context, Intent intent) {
Intent startIntent = context
.getPackageManager()
.getLaunchIntentForPackage(context.getPackageName());
startIntent.setFlags(
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
);
context.startActivity(startIntent);
}
#Override
public void onReceive(Context context, Intent intent) {
Intent launch_intent = new Intent(context, MainActivity.class);
launch_intent.setComponent(new ComponentName("com.example.helloworld","com.example.helloworld.MainActivity");
launch_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP |INTENT.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
launch_intent.putExtra("some_data", "value");
launch_intent.addCategory(Intent.CATEGORY_LAUNCHER);
context.startActivity(launch_intent);
}
It's this simple but unless you know the proper way when you try to get the extra data from your intent you will usually get a java null pointer exception.
Use the onNewIntent() method to receive the extra data. If you want to know how comment below.
Edit:
Try the following. But what I don't understand is the first code which I gave you should work on its own. It has always worked for me. Have you made sure that you have copied the first code I gave you and pasted it without making any changes?
Edit2:
If that doesn't work try setting the flag to clearTaskOnLaunch instead of INTENT.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Assuming you already know BroadcastReceiver, you just have to do the launching like you usually do on onReceive : Therefore it will look like this
#Override
public void onReceive(Context context, Intent intent) {
Intent launch_intent = new Intent("android.intent.action.MAIN");
launch_intent.putExtra("some_data", "value");
tiapp.startActivity(launch_intent);
}
If it is launched before, it will just resume that Activity, if not, it will start a new

Sending Intent to Home and Widget Add

I'm trying to figure out how to send an intent to the home screen to add a Widget to it if I can. Any ideas? Here is some code I've been fooling around with to at least prompt the Add Widget selection.
AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
selectWidget();
mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetHost = new AppWidgetHost(this, R.id.APPWIDGET_HOST_ID);
}
void selectWidget() {
int appWidgetId = this.mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(pickIntent, R.id.REQUEST_PICK_APPWIDGET);
}
Thank you to anybody who contributes.
You can send the ACTION_APPWIDGET_PICK intent to the system, but your app cannot process it, unless what you're coding is a Home screen replacement, i.e. a launcher.
Take a look at the documentation for App Widget Host, in particular the section about Host Binding. The code you're using in the selectWidget() method is the same used in the original Launcher app (under title Binding app widgets on Android 4.0 and lower). Then comes an implementation for onActivityResult, where the intent is processed. This method is what is missing in your code, but if you include it, you will end up doing all the work the Home screen app does (see addAppWidget(Intent data) next in that page).
If you continue reading the App Widget Host doc, you will see that the binding process changed on Android 4.1 and there is also a new intent for this task that requires a permission in the manifest. And to complicate things more, keep in mind #CommonsWare's comment: there are a lot of Home screen implementations, that probably do the binding process differently :(
To summarize: there's no way to get the list of app widgets and process what the user selected, neither is a way to ask the launcher app to do this for us, unfortunately. Perhaps in a future Android version, as this comment in the latest Launcher source code reveals:
/**
We will likely flesh this out later, to handle allow external apps to place widgets, but for now,
we just want to expose the action around for checking elsewhere. */

Is it safe to reuse an intent?

The Android docs define an Intent as "a bundle of information containing an abstract description of an operation to perform". This suggests that you should be able to reuse a single Intent object multiple times if needed, but I haven't seen any examples showing this is the case/ is safe to do. Is there any reason to NOT do the following:
private final Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
...
protected void onCreate(Bundle savedInstanceState) {
enabledBluetoothIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
...
}
and then call startActivityForResult(enableDiscoverableIntent, REQUEST_ENABLE_BT_DISCOVERY) in multiple places in the code? What happens if the same intent is started twice?
It is completely safe when you want to use it to do the exact same thing, since an Intent is no more than a bunch of data and instructions. If you want to use the same Intent object for different purposes (for example you have a bunch of tabs and try to set the tabs reusing the same intent but changing the activity they'll launch) you have to be more careful, and I'd recommend re-creating a new Intent object for each.

Android - When launch the same activity from widget with different extras, how to prevent the same instance show up after returned from HOME button?

I have a widget that contains 4 buttons to show 4 stock prices, each of them will launch into the same activity Quote.class to show stock details. In onUpdate(), it will set up the pendingIntent with extras with stock symbol. After I hit button A, it goes to Quote activity that shows stock A. Then I hit the BACK button to the homescreen, Quote activity calls onDestroy() and when I hit button B, stock B will show properly. However, when i hit HOME button after it shows stock A, the Quote activity only calls onStop without calling onDestroy(), then as i hit button B, it will call onStart() and it shows the same instance that shows stock A.
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.etappwidget);
setQuoteIntent(context, views, R.id.view1, "BAC", 1);
setQuoteIntent(context, views, R.id.view2, "C", 2);
setQuoteIntent(context, views, R.id.view3, "GOOG", 3);
setQuoteIntent(context, views, R.id.view4, "AAPL", 4);
private static void setQuoteIntent(Context context, RemoteViews views, int viewId, String symbol, int requestCode) {
Intent i = new Intent(context, Quote.class);
i.putExtra("SYMBOL", symbol);
i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
PendingIntent pi = PendingIntent.getActivity(context, requestCode, i, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(viewId, pi);
}
Originally I thought adding a flag in the Intent should solve this problem. But I have tried
i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK or FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_NO_HISTORY), none of them makes any difference.
So is there any ways to make it work? How can i remove the history stack from HOME button? How can I call onCreate in Quote activity and get new extras when i hit button B? Any help is appreciated. Thanks
It is normal for onDestroy to possibly not get called if you do simple task switching (like holding the HOME button). If you need to do clean-up, it needs to go in onPause.
I believe the problem is that you have a PendingIntent that only differs by extra. PendingIntents are cached, so if you use two with the same action and data, they'll overwrite each other. You can circumvent that by giving each some random data. Try passing the symbol in the data rather than through the extra (which is preferred anyway).
You can try this:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Your activity will not be seen in the history stack
clickIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Since: API Level 1 If set, the new activity is not kept in the
history stack. As soon as the user navigates away from it, the
activity is finished. This may also be set with the noHistory
attribute.
This solved the same issue of mine while implementing widget activities.
When you press home, most probably the activity will not be destroyed. It is put to pause state in such case. So, I guess your code to initiate the stock view would stationed in onCreate rather than onResume. So, moving those to onResume should solve the problem.
If you are using a different Action in your Intent and use the SingleTop or similar flag and override onNewIntent to detect the correct action that should do the trick. You need to be prepared to handle the intent in onCreate and onNewIntent.

Categories

Resources