App Widgets are miniature application views that can be embedded in other applications (such as the Home screen) and receive periodic updates. These views are referred to as Widgets in the user interface, and you can publish one with an App Widget Provider. An application component that is able to hold other App Widgets is called an App Widget host (like, Home Screen).

Dimensions in Cells

For n number of Cells (Columns or Rows), the Available Size (dp) is approximately (70*n)-30. So, an app widget of dimensions minWidth 250 x minHeight 60, will be "stretched" to occupy 4x2 cells on screen.
1 = up to  40dp
2 = up to 110dp
3 = up to 180dp
4 = up to 250dp


AppWidget Configuration: Problem & Solution

1. AppWidgetProvider.onReceive(APPWIDGET_ENABLED)/onEnabled() gets called right in the beginning, even before Widget HOST dependent SIZE message (Motorola: com.motorola.blur.home.ACTION_SET_WIDGET_SIZE; Samsung: is delivered.
    As AppWidgetConfigure needs WidgetID, AppWidgetConfigure.onCreate() is also called after onEnabled().
    That is, onEnabled() is already called even if Configuration later gets cancelled by pressing "Back" button.

2. If a Configuration Activity is declared, the AppWidgetProvider.onReceive(APPWIDGET_UPDATE)/onUpdate() method will not be called when the App Widget is created. It is the responsibility of the configuration Activity to request an update from the AppWidgetManager when the App Widget is first created. However, onUpdate() will be called for subsequent updates - it is only skipped the first time.
    ==> But in reality, onUpdate() is called even when Configuration Activity is declared.

3. The AppWidget Configuration documentation says "Setting the result to RESULT_CANCELED will cause the widget host to cancel out of the widget placement if they press the back button".
    ==> But in reality, when Configuration is cancelled by navigating "Back", the Widget is not Deleted!! That is, AppWidgetConfigure.onDestroy() is called, but AppWidgetProvider.onReceive(APPWIDGET_DELETED) is not called for corresponding Widget. This leaves unconfigured widget hidden (ghost) somewhere and hence, AppWidgetProvider.onReceive(APPWIDGET_DISABLED)/onDisabled doesn't get called even if onEnabled() already called before creating Configuration activity.
4. These and some more appear to be long-pending issues not resolved by Google/Android team:
    Unconfigured home screen widgets are left in limbo
    Widget onUpdate is called once before displaying configuration activity
Add AppWidget::
    onReceive action=android.appwidget.action.APPWIDGET_ENABLED
    onReceive action=android.appwidget.action.APPWIDGET_UPDATE
    updateAppWidget(): appWidgetId=131
    onReceive action=com.motorola.blur.home.ACTION_SET_WIDGET_SIZE
     YmdhmsAppWidgetConfigure: onCreate()
     YmdhmsAppWidgetConfigure: onCreate() finished. mAppWidgetId=131
---- config shown
Option A: Press Back button and NOTHING happens. Widget is "lost" without being deleted.
Option B: Accept Configuration (Don't press Back button)::
    updateAppWidget(): appWidgetId=131
    onReceive action=com.motorola.blur.home.ACTION_WIDGET_ADDED
    onReceive action=android.appwidget.action.APPWIDGET_UPDATE
    updateAppWidget(): appWidgetId=131
---- config accepted
Delete AppWidget:: (Note: This can't be done for Option A, where Widget is lost after pressing Back button)
    onReceive action=android.appwidget.action.APPWIDGET_DELETED
    onReceive action=android.appwidget.action.APPWIDGET_DISABLED
---- deleted


Best option is to NOT use Widget Info "android:configure". Instead, let the widget be created & shown with default configuration and provide a choice to later reconfigure the settings. (In any case, even if  "android:configure" is used, there is no default/recommended process to re-configure a widget after it's created).

Assign "id" to the AppWidget layout. Use setOnClickPendingIntent() on it to set explicit intent for (manually) starting the Configuration Activity.
    Bundle extras = new Bundle();
    extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    // Bind the Click intent for the on the (whole) widget
    final Intent clickIntent = new Intent(context, YmdhmsAppWidgetProvider.class)
        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // in case activity is started outside of the context of an existing activity
    final PendingIntent clickPendingIntent = PendingIntent.getActivity(context, appWidgetId, // use unique request code instead of 0, to create unique PendingIntents
            clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    views.setOnClickPendingIntent(, clickPendingIntent);

No comments:

Post a Comment