Widget to create Shortcut of Installed Apps - android

How to create shortcut for pre-installed apps from my widget?

Do you want some static shortcuts? Just pre-installed apps?
This is how I created what look like shortcuts on the home screen:
RemoteViewsWidget views = new RemoteViewsWidget(context, R.layout.your_layout);
Where RemoteViewsWidget is your subclass of RemoteViews. You'll want the context to use for actions done in the RemoteViewsWidget class.
In a method in the RemoteViewsWidget class, I set the image and text for the "shortcut":
setImageViewUri(imageResId, uri);
setTextViewText(textResId, displayName);
Where imageResId is the resource in your layout you want to be your thumnail and the uri points to the image (I used a locally saved file for the image source). Similar for the textResId and displayName.
setOnClickPendingIntent(layoutViewId, PendingIntent.getActivity(
context, requestCode, intent, flags));
Here, layoutViewId is the parent layout that your image view and text view live in. This layout is what triggers the intent when it is selected. The pending intent is what is executed when the layout is selected - just fill in your context, intent of the activity you want launched and flags, if necessary.
To find what you need from the apps to launch them, you probably want to use PackageManager:
List<ResolveInfo> appInfos = context.getPackageManager().queryIntentActivities(
new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER), 0);
to get a list of the resolve info for all apps in your launcher. You can get all you need from that list to make the intent for the setOnClickPendingIntent above. If you only want a subset of these apps, you can apply a different or more categories, different actions, etc. Or you can just use known packages or activities.
After you've created your remote views, you need to update the widget, either in a utility method or in your widget provider subclass:
views.updateWidget(); // update resources with image, text and intent as above
AppWidgetManager.getInstance(context.getApplicationContext()).updateAppWidget(
widgetId, views);

Related

Different types of Android Intents

I have recently started a new Android project and I'm working off the previous developer's code. I'm relatively new to Android and I've come across something that I'm unsure of.
What is the difference between this:
Intent intent = new Intent("com.example.project.MENU");
and this:
Intent intent = new Intent(this, DisplayMenu.class);
I understand what the 2nd code snippet does, I just can't get my head around as to what the first one is doing? Is it referencing the file in the package? Thanks
The first one is an implicit intent, while the second is an explicit intent.
The first one fired an Intent for the action com.example.project.MENU. If you look inside you project AndroidManifest.xml you can see some <intent-filter> balise. This baslise register activity, service or broadcast receiver to different actions.
This mecanism can be used to allow third party app to launch some of your activities.
You can see more on this tutorial http://www.vogella.com/tutorials/AndroidIntent/article.html#intenttypes
Basically an Intent carries some information that are used by the system in order to determine which component should be called for executing the action.
These information are:
Component name: the name of the component that should be launched. (If present the Intent is Explicit)
Action: it specifies the generic action that should be executed (es. ACTION_VIEW, ACTION_SEND). It determines how the rest of the intent is strucutred.
Data: represents the URI that refers to the object that should be associated with the action. For example with the action ACTION_EDIT, the Data should contain the URI of the document that you want modify.
Category: Additional infromation (for example if you want that your app is shown in the launcher you can use CATEGORY_LAUNCHER)
Extras: keys-values pairs that carries additional information
Flags: it is like a metadata that specify how the intent should be managed by the system.
The Intent class provides a lot of different constructors.
The first one you asked for is public Intent (String action)
So, this sets the Action, and lets null all other fields.
The second one public Intent (Context packageContext, Class<?> cls) creates an intent for a specific component by its Component name. All other fields are null. This is a Explicit Intent, since you declare exactly which component should receive it.
The first one is used when you need to call Intent from System
such as Open Camera, Gallery, or Share something to other Application
for example
// this one call Camera to Capture Image
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// this one call gallery to let you select image
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
and That MediaStore.something here is just a Path to the system
for example
MediaStore.ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"
Intent.ACTION_PICK = "android.intent.action.PICK"
The first type of intent is mostly used if you want to open another application from your application while the second type of intent is used to open another activity in your application.

Some 3rd party widgets stop updating after application upgrade

My application hosts user installed widgets, same as a launcher application.
Once I bind the widget, everything works fine. Widgets are created, updated automatically, I can click to navigate inner views.
Everything keeps working fine, until I update my application from Play store (or manually with a signed APK).
After the update, the widgets still show but they won't update anymore. Some widgets function when I click on them but the view is stuck and never gets updated until I re-create the widget (get a new ID and bind it).
I tried forcing an update using
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.setComponent(appWidgetInfo.provider);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]
{appWidgetId});
context.sendBroadcast(intent);
but that doesn't help...
I wanted to try a forced update on click but I couldn't find any way to get the widget's RemoteViews (as this is not my widget, I just host it).
RemoteViews views =
new RemoteViews(context.getPackageName(),R.layout.mywidget_layout);
Intent updateIntent = new Intent();
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
updateIntent.putExtra(myWidgetProvider.WIDGET_IDS_KEY, ids);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.view_container, pendingIntent);
Also implemented an AppWidgetProvider to listen to widgets' ID changes (APPWIDGET_HOST_RESTORED) but it doesn't get called on my application update.
My next step would be to re-create all widgets after application update, but I really prefer not to do so.
Would appreciate any help!
Solved.
The last thing I wanted to do, was probably the first thing I should have tried.
I moved on to re-creating the widgets and I found that I don't have to fully re-create them, just re-call bindAppWidgetIdIfAllowed() with the same Widget ID I already have.
The method will return true if everything is still OK and if not, the widget may not be installed anymore or you need to trigger its configuration screen.
Certain Android functionality will break if the widget is installed on the SD Card. Try moving it to the device storage and re-test.
make sure you use unique keys with putExtra(MyWidgetProvider.WIDGET_ID_KEY, ids);
Do not use putExtra(AppWidgetManager.EXTRA_WIDGET_IDS, ids);

How to create a shortcut of an app on a SPECIFIC launcher app?

Background
I already know how to put a shortcut to an app globally:
Intent shortcutIntent=new Intent();
shortcutIntent.setComponent(new ComponentName(packageName,fullPathToActivity));
final Intent putShortCutIntent=new Intent();
putShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,shortcutIntent);
//... <=preparing putShortcutIntent with some customizations (title, icon,...)
putShortcutIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
context.sendBroadcast(putShortcutIntent);
This works well.
What I do wish to do is to be able to put the shortcut only to a specific launcher app (in fact it's the default launcher app, but that's not the problem).
The problem
For some reason, instead of putting the shortcut on the launcher app i've chosen (in this case "nova launcher") , I end up getting the shortcut created on the touchwiz launcher alone.
What I've tried
the obvious solutions were:
putShortcutIntent.setClassName(launcherPackageName,broadcastReceiverClassName);
or
putShortcutIntent.setPackage(launcherPackageName);
none worked, even though i've seen the values fine during debug mode (the parameters were legit).
The weird thing is that if I use this, it puts the shortcut only on the touchwiz launcher...
The question
Why does it occur?
How come I can't choose where to send the broadcast to?
is there a better way to achieve this?
EDIT: here's how I get the default broadcastReceiver that can handle the shortcut creation intent:
final ResolveInfo defaultActivityForLauncherIntent=... //here i return the correct app that is the default launcher
Intent intentForAddingShortcutOnDesktop=new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
//<= here I prepare the intent of creating a shortcut
final List<ResolveInfo> broadcastReceiversResolveInfos=context.getPackageManager().queryBroadcastReceivers(intentForAddingShortcutOnDesktop,0);
for(final ResolveInfo resolveInfo : broadcastReceiversResolveInfos)
if(resolveInfo.activityInfo.packageName.equals(defaultActivityForLauncherIntent.activityInfo.packageName))
{
intentForAddingShortcutOnDesktop.setComponent(new ComponentName(//
resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
break;
}
context.sendBroadcast(intentForAddingShortcutOnDesktop);
it seems part of the confusion was that the play store was set to create new shortcuts.
This, and the fact i forgot to query the broadcastReceivers instead of activities...

Prompt for default activity without actually opening activity

I need to set the default app for a specific mime type. I know how to clear the default but I need to then prompt the user without actually opening the app.
PackageManager p = mContext.getPackageManager();
ComponentName cN = new ComponentName(mContext, FakeDownloadActivity.class);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Intent selector = new Intent(Intent.ACTION_DEFAULT);
selector.addCategory(Intent.CATEGORY_DEFAULT);
selector.setType(mimeType);
mContext.startActivity(selector);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
The code above launches the activity rather than ONLY selecting the default activity. It works be enabling a fake activity then disabling it. This causes the Select Default App dialog to show the next time it is called. I simply want to ONLY select the default activity.
What you are looking for is an ACTION_PICK_ACTIVITY intent.
First, you create an intent that defines the apps that should be eligible to choose, for instance:
Intent mainIntent = new Intent(Intent.ACTION_DEFAULT, null);
mainIntent.addCategory(Intent.CATEGORY_DEFAULT);
Then, you create the ACTION_PICK_ACTIVITY intent, and as an Extra, you pass the main intent you created before
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
Now, you just start an activity for result with this intent:
startActivityForResult(pickIntent, 0);
And a dialog will be created where the used can pick an application, but when clicked, the activity is not launched, instead, it will stay in your activity, and the function onActivityResult will be called with the results. So you need to create that function:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//In data, you have all the information about the selected application
if (data != null) {
//You can launch the application that we just picked with startActivity(data);
//or explore the variable to get all the information than you want
}
}
Take a look at the Intent class. There you have information about the package name, and the class that would be launched.
From now, what you need is to set that package and class as the default to the intent, or whatever else you need. The bad side, is that you only can save that information for your own internal purposes, for example to decide what app to launch next time that the users performs some action. What you cannot do is to modify the system settings to set a default activity for a given intent. Actually, the package manager has the addPreferredActivity method, that was supposed to do this, but it is deprecated since API level 8, giving this reasons:
This is a protected API that should not have been available to third
party applications. It is the platform's responsibility for assigning
preferred activities and this cannot be directly modified. Add a new
preferred activity mapping to the system. This will be used to
automatically select the given activity component when
Context.startActivity() finds multiple matching activities and also
matches the given filter.

Android - Communications between a widget and its app

I have a widget that shows various images with text below, and the same UI set up in the app itself. I want the widget to not only be able to open the app, but to open the app based on which picture is showing in the widget and then show that same image in the app. However, I am having a tough time getting this to work.
Thanks.
Let's say there are several images in the ui, you can set different Intent for each image, and these intents each will target a different activity.
This post: http://rxwen.blogspot.com/2012/10/communication-between-android-widget.html may give you some hints.
Add this code in widget.java file to launch your application. instead of MainActivity.class you can call any activity
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.mywidget_provider);
Intent openApp = new Intent(context,MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context,0,openApp,0);
views.setOnClickPendingIntent(R.id.btnOpenApp,pIntent);
appWidgetManager.updateAppWidget(appWidgetId,views);
}

Categories

Resources