Thursday, December 15, 2011

Cancel the widget placement on pressing back key in AppWidgetConfigure Activity


As described in http://developer.android.com/guide/topics/appwidgets/index.html#Configuring, if you would like the user to configure settings when he or she adds a new App Widget, you can create an App Widget configuration Activity.

The configuration Activity should be declared in the Android manifest file in the following way:

<activity android:name=".ExampleAppWidgetConfigure" >
            <intent-filter >
                <action  android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
            </intent-filter>
</activity>

Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the android:configure attribute:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
          ...
          android:configure="com.example.android.ExampleAppWidgetConfigure" >
          ...
</appwidget-provider>

There is a special tip concerning exiting from Configuration Activity by pressing back key:

Tip: When your configuration Activity first opens, set the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before reaching the end, the App Widget host is notified that the configuration was cancelled and the App Widget will not be added.

And there is also link to the ExampleAppWidgetConfigure.java sample class in ApiDemos.

Let’s look at this example code:

public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // Set the result to CANCELED. This will cause the widget host to cancel
        // out of the widget placement if they press the back button.
        setResult(RESULT_CANCELED);

But actually this code doesn’t results in calling AppWidgetProvider.onDeleted. So widget neither was added to home screen completely nor was deleted also.

We could find the explanation of this behavior in Launcher.onActivityResult code:

} else if ((requestCode == REQUEST_PICK_APPWIDGET || requestCode == REQUEST_CREATE_APPWIDGET)
            && resultCode == RESULT_CANCELED && data != null) {
        // Clean up the appWidgetId if we canceled
        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
        if (appWidgetId != -1) {
            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
        }
    }

Now it is clear that we should extra data to Intent if we want to delete the widget properly:

Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_CANCELED, resultValue);


There were proposed some solutions like removing widget explicitly in onPause() event and some similar. But actually the right way to remove widget is to pass back a new Intent() that includes the EXTRA_APPWIDGET_ID. (This is so the homescreen can clean up discarded ids when canceled.) See details at: http://code.google.com/p/android/issues/detail?id=2539

The other interesting question is what happens when user presses “Home” key in Configuration Activity, widget can stay in the same state – not added nor deleted. It seems that it is up to developer to work up this case properly. 


No comments:

Post a Comment