App Widget Host

来源:互联网 发布:互联网数据分析师 编辑:程序博客网 时间:2024/05/17 23:35

The Android Home screen available on most Android devices allows the user to embed app widgets for quick access to content. If you're building a Home replacement or a similar app, you can also allow the user to embed app widgets by implementing an AppWidgetHost. This is not something that most apps will ever need to do, but if you are creating your own host, it's important to understand the contractual obligations a host implicitly agrees to.

This document focuses on the responsibilities involved in implementing a custom AppWidgetHost. For an example of how to implement an AppWidgetHost, see the source code for the Android Home screen Launcher.

Here is an overview of key classes and concepts involved in implementing a custom AppWidgetHost:

  • App Widget Host— The AppWidgetHost provides the interaction with the AppWidget service for apps, like the home screen, that want to embed app widgets in their UI. An AppWidgetHost must have an ID that is unique within the host's own package. This ID remains persistent across all uses of the host. The ID is typically a hard-coded value that you assign in your application.
  • App Widget ID— Each app widget instance is assigned a unique ID at the time of binding (seebindAppWidgetIdIfAllowed(), discussed in more detail in Binding app widgets). The unique ID is obtained by the host using allocateAppWidgetId(). This ID is persistent across the lifetime of the widget, that is, until it is deleted from the host. Any host-specific state (such as the size and location of the widget) should be persisted by the hosting package and associated with the app widget ID.
  • App Widget Host View— AppWidgetHostView can be thought of as a frame that the widget is wrapped in whenever it needs to be displayed. An app widget is assigned to an AppWidgetHostView every time the widget is inflated by the host.
  • Options Bundle— The AppWidgetHost uses the options bundle to communicate information to theAppWidgetProvider about how the widget is being displayed (for example, size range, and whether the widget is on a lockscreen or the home screen). This information allows the AppWidgetProvider to tailor the widget's contents and appearance based on how and where it is displayed. You useupdateAppWidgetOptions() and updateAppWidgetSize() to modify an app widget's bundle. Both of these methods trigger a callback to the AppWidgetProvider.

Binding App Widgets


When a user adds an app widget to a host, a process called binding occurs. Binding refers to associating a particular app widget ID to a specific host and to a specific AppWidgetProvider. There are different ways of achieving this, depending on what version of Android your app is running on.

Binding app widgets on Android 4.0 and lower

On devices running Android version 4.0 and lower, users add app widgets via a system activity that allows users to select a widget. This implicitly does a permission check—that is, by adding the app widget, the user is implicitly granting permission to your app to add app widgets to the host. Here is an example that illustrates this approach, taken from the original Launcher. In this snippet, an event handler invokesstartActivityForResult() with the request code REQUEST_PICK_APPWIDGET in response to a user action:

private static final int REQUEST_CREATE_APPWIDGET = 5;private static final int REQUEST_PICK_APPWIDGET = 9;...public void onClick(DialogInterface dialog, int which) {    switch (which) {    ...        case AddAdapter.ITEM_APPWIDGET: {            ...            int appWidgetId =                     Launcher.this.mAppWidgetHost.allocateAppWidgetId();            Intent pickIntent =                     new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);            pickIntent.putExtra                    (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);            ...            startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);            break;    }    ...}

When the system activity finishes, it returns a result with the user's chosen app widget to your activity. In the following example, the activity responds by calling addAppWidget() to add the app widget:

public final class Launcher extends Activity         implements View.OnClickListener, OnLongClickListener {    ...    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        mWaitingForResult = false;        if (resultCode == RESULT_OK && mAddItemCellInfo != null) {            switch (requestCode) {                ...                case REQUEST_PICK_APPWIDGET:                    addAppWidget(data);                    break;                case REQUEST_CREATE_APPWIDGET:                    completeAddAppWidget(data, mAddItemCellInfo, !mDesktopLocked);                    break;                }        }         ...    }}

The method addAppWidget() checks to see if the app widget needs to be configured before it's added:

void addAppWidget(Intent data) {    int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);    String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET);    AppWidgetProviderInfo appWidget =             mAppWidgetManager.getAppWidgetInfo(appWidgetId);    if (appWidget.configure != null) {        // Launch over to configure widget, if needed.        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);        intent.setComponent(appWidget.configure);        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);        startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);    } else {        // Otherwise, finish adding the widget.    }}

For more discussion of configuration, see Creating an App Widget Configuration Activity.

Once the app widget is ready, the next step is to do the actual work of adding it to the workspace. The original Launcher uses a method called completeAddAppWidget() to do this.

Binding app widgets on Android 4.1 and higher

Android 4.1 adds APIs for a more streamlined binding process. These APIs also make it possible for a host to provide a custom UI for binding. To use this improved process, your app must declare the BIND_APPWIDGETpermission in its manifest:

<uses-permission android:name="android.permission.BIND_APPWIDGET" />

But this is just the first step. At runtime the user must explicitly grant permission to your app to allow it to add app widgets to the host. To test whether your app has permission to add the widget, you use thebindAppWidgetIdIfAllowed() method. If bindAppWidgetIdIfAllowed() returns false, your app must display a dialog prompting the user to grant permission ("allow" or "always allow," to cover all future app widget additions). This snippet gives an example of how to display the dialog:

Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);// This is the options bundle discussed aboveintent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);startActivityForResult(intent, REQUEST_BIND_APPWIDGET);

The host also has to check whether the user added an app widget that needs configuration. For more discussion of this topic, see Creating an App Widget Configuration Activity.

Host Responsibilities


Widget developers can specify a number of configuration settings for widgets using the AppWidgetProviderInfo metadata. These configuration options, discussed in more detail below, can be retrieved by the host from the AppWidgetProviderInfo object associated with a widget provider.

Regardless of the version of Android you are targeting, all hosts have the following responsibilities:

  • When adding a widget, you must allocate the widget ID as described above. You must also make sure that when a widget is removed from the host, you call deleteAppWidgetId() to deallocate the widget ID.
  • When adding a widget, be sure to launch its configuration activity if it exists, as described in Updating the App Widget from the Configuration Activity. This is a necessary step for many app widgets before they can be properly displayed.
  • Every app widget specifies a minimum width and height in dps, as defined in the AppWidgetProviderInfo metadata (usingandroid:minWidth and android:minHeight). Make sure that the widget is laid out with at least this many dps. For example, many hosts align icons and widgets in a grid. In this scenario, by default the host should add the app widget using the minimum number of cells that satisfy the minWidth andminHeight constraints.

In addition to the requirements listed above, specific platform versions introduce features that place new responsibilities on the host. These are described in the following sections.

Android 3.0

Android 3.0 (API Level 11) introduces the ability for a widget to specify autoAdvanceViewId(). This view ID should point to an instance of an Advanceable, such as StackView or AdapterViewFlipper. This indicates that the host should call advance() on this view at an interval deemed appropriate by the host (taking into account whether it makes sense to advance the widget—for example, the host probably wouldn't want to advance a widget if it were on another page, or if the screen were turned off).

Android 3.1

Android 3.1 (API Level 12) introduces the ability to resize widgets. A widget can specify that it is resizable using the android:resizeMode attribute in the AppWidgetProviderInfo metadata, and indicate whether it supports horizontal and/or vertical resizing. Introduced in Android 4.0 (API Level 14), the widget can also specify aandroid:minResizeWidth and/or android:minResizeHeight.

It is the host’s responsibility to make it possible for the widget to be resized horizontally and/or vertically, as specified by the widget. A widget that specifies that it is resizable can be resized arbitrarily large, but should not be resized smaller than the values specified by android:minResizeWidth and android:minResizeHeight. For a sample implementation, see AppWidgetResizeFrame in Launcher2.

Android 4.0

Android 4.0 (API Level 15) introduces a change in padding policy that puts the responsibility on the host to manage padding. As of 4.0, app widgets no longer include their own padding. Instead, the system adds padding for each widget, based the characteristics of the current screen. This leads to a more uniform, consistent presentation of widgets in a grid. To assist applications that host app widgets, the platform provides the methodgetDefaultPaddingForWidget(). Applications can call this method to get the system-defined padding and account for it when computing the number of cells to allocate to the widget.

Android 4.1

Android 4.1 (API Level 16) adds an API that allows the widget provider to get more detailed information about the environment in which its widget instances are being hosted. Specifically, the host hints to the widget provider about the size at which the widget is being displayed. It is the host’s responsibility to provide this size information.

The host provides this information via updateAppWidgetSize(). The size is specified as a minimum and maximum width/height in dps. The reason that a range is specified (as opposed to a fixed size) is because the width and height of a widget may change with orientation. You don’t want the host to have to update all of its widgets on rotation, as this could cause serious system slowdown. These values should be updated once upon the widget being placed, any time the widget is resized, and any time the launcher inflates the widget for the first time in a given boot (as the values aren’t persisted across boot).

Android 4.2

Android 4.2 (API Level 17) adds the ability for the options bundle to be specified at bind time. This is the ideal way to specify app widget options, including size, as it gives the AppWidgetProvider immediate access to the options data on the first update. This can be achieved by using the method bindAppWidgetIdIfAllowed(). For more discussion of this topic, see Binding app widgets.

Android 4.2 also introduces lockscreen widgets. When hosting widgets on the lockscreen, the host must specify this information within the app widget options bundle (the AppWidgetProvider can use this information to style the widget appropriately). To designate a widget as a lockscreen widget, use updateAppWidgetOptions() and include the field OPTION_APPWIDGET_HOST_CATEGORY with the value WIDGET_CATEGORY_KEYGUARD. This option defaults to WIDGET_CATEGORY_HOME_SCREEN, so it is not explicitly required to set this for a home screen host.

Make sure that your host adds only app widgets that are appropriate for your app—for example, if your host is a home screen, ensure that the android:widgetCategory attribute in the AppWidgetProviderInfo metadata includes the flag WIDGET_CATEGORY_HOME_SCREEN. Similarly, for the lockscreen, ensure that field includes the flagWIDGET_CATEGORY_KEYGUARD. For more discussion of this topic, see Enabling App Widgets on the Lockscreen.


在该文献

  1. 结合应用小工具
    1. 在Android 4.0和更低的结合应用小工具
    2. 在Android 4.1及更高的结合应用小工具
  2. 主持人职责
    1. Android 3.0的
    2. Android版3.1
    3. Android 4.0的
    4. 搭载Android 4.1
    5. Android 4.2版

大多数Android设备上可用的Android主屏幕允许用户嵌入应用小工具,以便快速访问的内容。如果你正在构建一个家庭更换或类似的应用程序,也可以允许用户通过实现嵌入应用程序部件 AppWidgetHost。这不是大多数应用程序都不会需要做的事情,但如果你正在创建您自己的主机,它了解合同义务的主机隐含同意是非常重要的。

本文件的重点参与实施定制的责任 AppWidgetHost。对于如何实现一个例子 AppWidgetHost,请参阅Android主屏幕的源代码 发射器。

这里是参与实施定制关键类和概念的概述 AppWidgetHost

  • 应用的Widget主机 -该AppWidgetHost提供与AppWidget服务的应用程序,如主屏幕,希望嵌入应用小部件在其UI交互。一个AppWidgetHost必须有一个ID,它是主机自己的包中是唯一的。此ID在跨越主机的所有使用持久性。该ID通常是在应用程序中指定一个硬编码值。
  • 应用程序窗口小部件ID -每个应用程序控件实例是在结合时分配一个唯一的ID(见bindAppWidgetIdIfAllowed() ,详细讨论绑定应用小部件)。唯一ID是由使 ​​用主机获得allocateAppWidgetId() 。该ID是横跨插件,即的寿命持久,直到它从主机中删除。任何特定的主机的状态(例如大小和小部件的位置)应当由主机包被持久并与该应用微件ID相关联。
  • 应用窗口小部件主机视图 - AppWidgetHostView可以被认为是一帧,该插件是包裹在每当需要将其显示出来。一个应用程序widget被分配给一个AppWidgetHostView每个小部件由主机充气时间。
  • 选项包 -该AppWidgetHost使用选项束将信息传达给所述AppWidgetProvider如何正在显示微件(例如,尺寸范围,以及是否该窗口小部件上的锁定屏幕或主屏幕)。该信息允许 AppWidgetProvider的基础上如何以及在哪里显示定制Widget的内容和外观。您可以使用 updateAppWidgetOptions() 和updateAppWidgetSize() 来修改应用程序widget的包。这两种方法触发一个回调至 AppWidgetProvider

结合应用小工具


当用户添加一个应用程序窗口小部件到主机,这个过程被称为 绑定发生。绑定是指一个特定的应用程序部件编号为特定主机和特定的关联 AppWidgetProvider。有实现这一目标,取决于什么版本的Android您的应用程序上运行的不同方式。

在Android 4.0和更低的结合应用小工具

在运行Android 4.0版和更低的设备,用户通过系统的活动,允许用户选择一个小部件添加应用程序部件。这含蓄地做了权限检查,也就是说,通过将应用程序窗口小部件,用户被隐性授予权限,以您的应用程序小部件添加到主机。这里是示出该方法中,从原始拍摄的示例 发射器。在这个片段中,一个事件处理程序调用startActivityForResult() 的请求代码REQUEST_PICK_APPWIDGET响应用户操作:

private  static  final  int REQUEST_CREATE_APPWIDGET =  5 ; private  static  final  int REQUEST_PICK_APPWIDGET =  9 ; ... public  void onClick ( DialogInterface dialog ,  int which )  {     switch  ( which )  {     ...         case  AddAdapter . ITEM_APPWIDGET :  {             ...             int appWidgetId =                      Launcher . this . mAppWidgetHost . allocateAppWidgetId ();             Intent pickIntent =                      new  Intent ( AppWidgetManager . ACTION_APPWIDGET_PICK );             pickIntent . putExtra                     ( AppWidgetManager . EXTRA_APPWIDGET_ID , appWidgetId );             ...             startActivityForResult ( pickIntent , REQUEST_PICK_APPWIDGET );             break ;     }     ... }

当系统活动结束时,它返回与用户选择的应用小工具,你的活动的结果。在下面的例子中,活性通过调用响应addAppWidget()添加的应用插件:

public  final  class  Launcher  extends  Activity          implements  View . OnClickListener ,  OnLongClickListener  {     ...     @Override     protected  void onActivityResult ( int requestCode ,  int resultCode ,  Intent data )  {         mWaitingForResult =  false ;         if  ( resultCode == RESULT_OK && mAddItemCellInfo !=  null )  {             switch  ( requestCode )  {                 ...                 case REQUEST_PICK_APPWIDGET :                     addAppWidget ( data );                     break ;                 case REQUEST_CREATE_APPWIDGET :                     completeAddAppWidget ( data , mAddItemCellInfo ,  ! mDesktopLocked );                     break ;                 }         }          ...     } }

该方法addAppWidget()检查是否该应用插件需要它的加入之前进行配置:

                              在启动配置小工具,如果                         否则,完成添加小部件。    } }

有关配置的更多讨论,请参见创建应用程序窗口小部件配置活动。

一旦应用小工具已准备就绪,下一步就是做它添加到工作区的实际工作。在 最初的启动使用一种称为方法completeAddAppWidget() 来做到这一点。

在Android 4.1及更高的结合应用小工具

搭载Android 4.1增加了API,用于一个更精简的绑定过程。这些API也有可能使一台主机绑定提供自定义UI。要使用此改进方法,您的应用程序必须声明 BIND_APPWIDGET在其清单权限:

<使用许可权 的android:名称= “android.permission.BIND_APPWIDGET”  />

但是,这仅仅是第一步。在运行时,用户必须明确授予权限,您的应用程序,使其能够应用小部件添加到主机。要测试你的应用程序是否有权限新增的小工具,可以使用 bindAppWidgetIdIfAllowed() 方法。如果bindAppWidgetIdIfAllowed() 返回假的,你的应用程序必须显示一个对话框,提示用户授予权限(“允许”或“总是允许”,以涵盖所有未来的应用小工具添加)。这段代码提供了如何显示对话框的例子:

Intent intent =  new  Intent ( AppWidgetManager . ACTION_APPWIDGET_BIND ); intent . putExtra ( AppWidgetManager . EXTRA_APPWIDGET_ID , appWidgetId ); intent . putExtra ( AppWidgetManager . EXTRA_APPWIDGET_PROVIDER , info . componentName ); //这是讨论的选项包above intent . putExtra ( AppWidgetManager . EXTRA_APPWIDGET_OPTIONS , options ); startActivityForResult ( intent , REQUEST_BIND_APPWIDGET );

主机也必须检查用户是否补充说,需要配置一个应用程序部件。有关此主题的更多讨论,请参阅 创建应用程序窗口小部件配置活动。

主持人职责


插件开发者可以指定用于使用小窗口的数目的配置设置AppWidgetProviderInfo元数据。这些配置选项,在下面更详细讨论的,可以通过从主机检索AppWidgetProviderInfo 与小窗口提供者相关联的对象。

无论你的目标了Android版本,所有主机具有以下职责:

  • 当添加窗口小部件,则必须按照上述分配部件ID。您还必须确保当一个小部件从主机中删除,你可以调用deleteAppWidgetId() 来释放小部件ID。
  • 当添加窗口小部件,可以肯定如果存在推出配置活动,如描述从配置活动更新应用的Widget。这是许多应用小部件的必要步骤可以正确显示前。
  • 每一个应用程序窗口小部件指定的dps的最小宽度和高度,如定义AppWidgetProviderInfo元数据(使用安卓了minWidth安卓了minHeight)。确保小部件至少有这么多的dps布局。例如,许多主机对齐栅格图标和窗口小部件。在这种情况下,在默认情况下,主机应使用满足细胞的最小数量添加的应用插件了minWidth了minHeight约束。

除了上面列出的要求,具体版本的平台引入放置在主机上新的责任功能。这些将在以下各节中描述。

Android 3.0的

Android 3.0的(API等级11)介绍了一个小部件,以指定的能力autoAdvanceViewId() 。这种观点ID应指向一个实例 中推进,如StackView 或AdapterViewFlipper。这表示主机应该调用预先()这一观点在间隔认为适当的宿主(考虑到是否有意义推进插件,例如,主机可能不希望如果提前一个小部件是另一个页上,或如果屏幕被关闭)。

Android版3.1

Android的3.1(API等级12)引入了调整部件的能力。一个小部件可以指定它使用调整大小 的android:resizeMode 在属性AppWidgetProviderInfo 元数据,并说明它是否支持水平和/或垂直大小调整。在Android 4.0的(API级别14)介绍,小部件也可以指定一个 机器人:minResizeWidth 和/或机器人:minResizeHeight

它是主机的责任,这使该插件被水平和/或垂直地调整,由插件规定的。这说明它是可以调整大小可以调整任意大,但不应改变大小比规定值小的小部件的Android版 ​​本:minResizeWidth 和机器人:minResizeHeight。有关示例实现,请参阅 AppWidgetResizeFrame的launcher2

Android 4.0的

搭载Android 4.0(API等级15)引入该把责任在主机上管理填充填充政策的改变。作为4.0,应用小部件不再包括自己的填充。相反,系统添加填充每个部件,基于当前屏幕的特性。这导致一个更均匀,在网格部件的一致呈现。为了帮助该主机的应用程序窗口小部件,该平台提供的方法应用 getDefaultPaddingForWidget() 。计算细胞的数量分配给widget时应用程序可以调用此方法来获取系统定义的填充和解释它。

搭载Android 4.1

搭载Android 4.1(API等级16)增加了一个API,允许小部件供应商,以获取有关在其控件实例被托管环境的更多详细信息。具体地,主机暗示至约在正被显示的窗口小部件的尺寸小窗口提供者。这是主机的责任提供这种规模的信息。

主机通过提供此信息 updateAppWidgetSize() 。的大小指定为在DPS的最小和最大宽度/高度。一个范围(而不是一个固定的大小)的原因是因为一个小窗口的宽度和高度可以与取向发生变化。你不希望主机必须更新其所有的旋转部件,因为这可能会导致严重的系统运行缓慢。这些值应从前的插件来更新被放置,所述插件被调整大小的任何时间,任何时间发射膨胀用于在给定引导在第一时间(作为值不跨越启动持续)的部件。

Android 4.2版

对于选择在捆绑绑定时指定的Android 4.2(API等级17)增加的能力。这是指定的应用程序插件选项,包括大小的理想方法,因为它给了AppWidgetProvider直接访问数据的选项在第一次更新。这可以通过使用该方法来实现bindAppWidgetIdIfAllowed() 。有关此主题的更多讨论,请参阅绑定应用程序部件。

Android 4.2版还引入了锁屏小部件。当主机在锁定屏幕上的小部件,主机必须指定应用程序窗口小部件选项包内该信息(AppWidgetProvider可以使用这些信息来适当方式进行样式设置)。要指定一个widget作为锁屏插件,使用updateAppWidgetOptions() ,包括现场 OPTION_APPWIDGET_HOST_CATEGORY 与价值WIDGET_CATEGORY_KEYGUARD。此选项默认为 WIDGET_CATEGORY_HOME_SCREEN,所以也没有明确要求,设置本作的主屏幕主机。

请确保您的主机只增加了应用小工具,适合你的应用程序,例如,如果你的主机是主屏幕,确保 机器人:widgetCategory 在属性 AppWidgetProviderInfo元数据包括标志WIDGET_CATEGORY_HOME_SCREEN。同样,对于锁屏,确保字段包括标志 WIDGET_CATEGORY_KEYGUARD。有关此主题的更多讨论,请参阅 在锁屏启用应用程序的窗口小部件。


0 0
原创粉丝点击