My initial goal is to add the Google Search widget to the linear layout of the activity. I need to include it just like it appears and works in the Launcher (this is why I need to be able to add the widget).
I would like to add widgets to my activity whithout having to launch the widget picker activity. I tried to:
1. directly specify an integer id (I always get inflate errors)
2. get the id like this:
ComponentName cn = new ComponentName(getBaseContext(), "com.android.quicksearchbox.SearchWidgetProvider");
int[] ids = AppWidgetManager.getInstance(getApplicationContext()).getAppWidgetIds (cn);
(the array is always empty)
None of these works.
After this I have this code, to use the ID (it works if I get the ID from the widget picker activity):
AppWidgetProviderInfo withWidgetInfo = AppWidgetManager.getInstance(getApplicationContext()).getAppWidgetInfo(appWidgetId);
AppWidgetHostView hostView = myWidgetHost.createView(getBaseContext(), appWidgetId, withWidgetInfo);
hostView.setAppWidget(appWidgetId, withWidgetInfo);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ll.addView(hostView);
How should I do it? Thank you!
Try this:
// APPWIDGET_HOST_ID is any number you like
appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetHost = new AppWidgetHost(this, APPWIDGET_HOST_ID);
AppWidgetProviderInfo newAppWidgetProviderInfo = new AppWidgetProviderInfo();
// Get an id
int appWidgetId = appWidgetHost.allocateAppWidgetId();
// Get the list of installed widgets
List<AppWidgetProviderInfo> appWidgetInfos = new ArrayList<AppWidgetProviderInfo>();
appWidgetInfos = appWidgetManager.getInstalledProviders();
for(int j = 0; j < appWidgetInfos.size(); j++)
{
if (appWidgetInfos.get(j).provider.getPackageName().equals("com.android.quicksearchbox") && appWidgetInfos.get(j).provider.getClassName().equals("com.android.quicksearchbox.SearchWidgetProvider"))
{
// Get the full info of the required widget
newAppWidgetProviderInfo = appWidgetInfos.get(j);
break;
}
}
// Create Widget
AppWidgetHostView hostView = appWidgetHost.createView(this, appWidgetId, newAppWidgetProviderInfo);
hostView.setAppWidget(appWidgetId, newAppWidgetProviderInfo);
// Add it to your layout
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ll.addView(hostView);
EDIT:
To bind widget IDs, i.e. make widgets update and respond to user interaction, refer the solution here: Widgets don't respond when re-added through code
Well, I managed to make the code that works (except it should and cannot work that easily - details are provide bellow).
The code that should work is:
//create ComponentName for accesing the widget provider
ComponentName cn = new ComponentName("com.android.quicksearchbox", "com.android.quicksearchbox.SearchWidgetProvider");
//ComponentName cn = new ComponentName("com.android.music", "com.android.music.MediaAppWidgetProvider");
//get appWidgetManager instance
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getBaseContext());
//get list of the providers - .getAppWidgetIds (cn) does seem to be unrelated to widget hosting and more related to widget development
final List<AppWidgetProviderInfo> infos = appWidgetManager.getInstalledProviders();
//get AppWidgetProviderInfo
AppWidgetProviderInfo appWidgetInfo = null;
//just in case you want to see all package and class names of installed widget providers, this code is useful
for (final AppWidgetProviderInfo info : infos) {
Log.v("AD3", info.provider.getPackageName() + " / "
+ info.provider.getClassName());
}
//iterate through all infos, trying to find the desired one
for (final AppWidgetProviderInfo info : infos) {
if (info.provider.getClassName().equals(cn.getClassName()) && info.provider.getPackageName().equals(cn.getPackageName())) {
//we found it
appWidgetInfo = info;
break;
}
}
if (appWidgetInfo == null)
return; //stop here
//allocate the hosted widget id
int appWidgetId = myWidgetHost.allocateAppWidgetId();
//bind the id and the componentname - here's the problem!!!
appWidgetManager.bindAppWidgetId(appWidgetId, cn);
//creat the host view
AppWidgetHostView hostView = myWidgetHost.createView(getBaseContext(), appWidgetId, appWidgetInfo);
//set the desired widget
hostView.setAppWidget(appWidgetId, appWidgetInfo);
//add the new host view to your activity's GUI
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ll.addView(hostView);
Well, the problem is "appWidgetManager.bindAppWidgetId(appWidgetId, cn); " - this requires the permission BIND_APPWIDGET - in the manifest. - even if we put, it still won't work. I read it may be reserved for system applications
However, even after adding the permission and putting the apk in the system/app folder, it still does not work (it does not make it a system app).
Regarding this problem I found this answer here:
This is deliberately not available to applications. If you want to add a widget, you need to launch the selector UI for the user to pick the widget which will then take care of the bind. Widgets can expose a lot of private data of all types, so it is not safe to allow an application to arbitrarily bind to them without the user implicitly approving (through the selection UI).
Dianne ... Android framework engineer
However, I am uncertain but, maybe this means what we could achieve the desired functionality if we could sign the apk with the image developer's key? However, this is off the question's topic. But if you happen to be able to explain to me how to efficiently host AppWidgets, please do and have your answer accepted by me (launcher applications in the market can do it, so it must be possible).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With