Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - adding AppWidgets to an Activity

Tags:

android

widget

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!

like image 483
stormofwar Avatar asked Apr 03 '12 18:04

stormofwar


2 Answers

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

like image 167
Kamran Ahmed Avatar answered Oct 05 '22 22:10

Kamran Ahmed


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).

like image 43
stormofwar Avatar answered Oct 05 '22 23:10

stormofwar