Dynamically enabling or disabling a widget does not work

We would like to enable or disable widgets via code. When we say "disable" we mean that a widget which is registered in an application should not show up in the list of widgets available to the user when they try to add a widget to their home screen. This question has been asked, unfortunately, many times without answer.

There was one response by Dianne Hackborn to a separate widget question which suggested that it was possible to use the package manager to disable widgets:

PackageManager pm = context.getPackageManager(); 
pm.setComponentEnabledSetting(new ComponentName("com.example.android.apis", ".appwidget.ExampleBroadcastReceiver"), 
    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, // or DISABLED 
    PackageManager.DONT_KILL_APP); 

This, however, does not work. The widget component will still appear in the list of widgets. It may be that the AppWidgetService (located in the Android source's Base.git at srcbaseservicesjavacomandroid server), which loads the list of available widgets, caches this list of available widgets. If that were the case, though, then the above code which enables or disables the widget component would work after a device reset because there would be no cache; it does not.

I have also tried looking into overriding some methods of the AppWidgetProvider, such as filtering out any events. I don't think this will go anywhere, because the AppWidgetService, which populates the list, uses the Package Manager to find all components which catch the ACTION_APPWIDGET_UPDATE action on startup and when a package is added (ie a new app is installed). The only time that a provider is removed from this list is on a ACTION_PACKAGE_REMOVED broadcast. So given that the providers will always be there, regardless of the enabled/disabled state of the component, I have looked into the actual list activity which is shown from the Launcher app when the user long- clicks the desktop and adds a widget: AppWidgetPickActivity in Settings.GIT in com.android.settings. This, unfortunately, populates the list directly from the AppWidgetService, without any filtering for the component's enabled status: void putInstalledAppWidgets(List items) { List installed = mAppWidgetManager.getInstalledProviders(); putAppWidgetItems(installed, null, items); }

I would love to see if anyone has overcome this hurdle. Perhaps I am going about it the wrong way. All I want is to be able to remove a widget from the list of widgets available to the user when they try to add a widget to their home screen.


It may be that the AppWidgetService (located in the Android source's Base.git at srcbaseservicesjavacomandroid server), which loads the list of available widgets, caches this list of available widgets.

It does, near as I can tell. It stores the list in mInstalledProviders ; this list is added to via readStateFromFileLocked() , which appears to be called from the system startup logic.

If that were the case, though, then the above code which enables or disables the widget component would work after a device reset because there would be no cache; it does not.

You assume a RAM cache. The cache is an XML file.

This, unfortunately, populates the list directly from the AppWidgetService, without any filtering for the component's enabled status

And this would appear to be a bug in Android. More generally, the whole caching thing I would think is the bug -- I see no way to recover if that cache gets out of sync.

I would recommend you post your writeup as an issue on the public Android issue tracker, if you have not done so already.


It worked for me! I had to use DONT_KILL_APP or it would kill my app immediately. Also, I had to comment out the condition to check if it was already in the same state.

Here's the helper method I created:

public void setMyCustomWidgetEnabled( boolean bEnable )
    {
        Log.d( LOG_TAG_NAME, "Entering setMyCustomWidgetEnabled( " + bEnable + " )..." );

        PackageManager rPackageManager = getPackageManager();
        if( rPackageManager != null )
        {
            ComponentName rComponentName = new ComponentName( getBaseContext(), MyCustomWidget.class );

            int nComponentEnabledState = rPackageManager.getComponentEnabledSetting( rComponentName );

            if( bEnable )
            {
                //if( nComponentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED )
                {
                    // Change the State to Enabled
                    rPackageManager.setComponentEnabledSetting( rComponentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP );

                    Log.d( LOG_TAG_NAME, "-> Changed My Custom Widget' to ENABLED!" );
                }
            }
            else
            {
                //if( nComponentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED )
                {
                    // Change the State to Disabled
                    rPackageManager.setComponentEnabledSetting( rComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP );

                    Log.d( LOG_TAG_NAME, "-> Changed 'My Custom Widget' to DISABLED!" );
                }
            }
        }

        Log.d( LOG_TAG_NAME, "Leaving setMyCustomWidgetEnabled( " + bEnable + " )..." );
}

The feature

pm.setComponentEnabledSetting()

works in ICS. When the widget is disabled, it's removed from the list of available widgets. Small consolation for the moment, but it's at least been corrected.

链接地址: http://www.djcxy.com/p/8928.html

上一篇: 防止Android上的屏幕旋转

下一篇: 动态启用或禁用小部件不起作用