Luuncher onCreate stupViews 初始化com.android.launcher3
.Workspace 控件,构造方法中实现setOnTouchListener(new WorkspaceTouchListener(mLauncher, this));
在 WorkspaceTouchListener的onLongPress中
弹出OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);,长按桌面弹出小部件选择,选择小部件
/** Returns WidgetsFullSheet that was opened, or null if nothing was opened. /
@Nullable
public static WidgetsFullSheet openWidgets(Launcher launcher) {
if (launcher.getPackageManager().isSafeMode()) {
// 在安全模式下無法使用小工具
Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
return null;
} else {
return WidgetsFullSheet.show(launcher, true / animated */);
}
}
WidgetsFullSheet 控件中加载小部件到 WidgetsRecyclerView中
/** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
@VisibleForTesting
public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
return launcher.findViewById(R.id.primary_widgets_list_view);
}
在BaseWidgetSheet的onLongClick中开发创建Widget, beginDraggingWidget方法具体创建,走到startDrag方法
private boolean beginDraggingWidget(WidgetCell v) {
// Get the widget preview as the drag representation
WidgetImageView image = v.getWidgetView();
// If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
// we abort the drag.
if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
return false;
}
PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview());
dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());
if (image.getDrawable() != null) {
int[] loc = new int[2];
getPopupContainer().getLocationInDragLayer(image, loc);
dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
} else {
View preview = v.getAppWidgetHostViewPreview();
int[] loc = new int[2];
getPopupContainer().getLocationInDragLayer(preview, loc);
Rect r = new Rect(0, 0, preview.getWidth(), preview.getHeight());
dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
new Point(loc[0], loc[1]), this, new DragOptions());
}
close(true);
return true;
}
首先调用AppWidgetHostView.setAppWidget(int appWidgetId, AppWidgetProviderInfo info)
,设置AppWidget的显示View和padding,appWidgetId默认-1
拖动Widget ,DragController.DragListener的实现WidgetHostViewLoader.onDragStart
(),
/** * Start preloading the widget. */
private boolean preloadWidget() {
final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
if (pInfo.isCustomWidget()) {
return false;
}
final Bundle options = mInfo.getDefaultSizeOptions(mLauncher);
// If there is a configuration activity, do not follow thru bound and inflate.
if (mInfo.getHandler().needsConfigure()) {
mInfo.bindOptions = options;
return false;
}
mBindWidgetRunnable = new Runnable() {
@Override
public void run() {
mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
if (LOGD) {
Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId);
}
if (new WidgetManagerHelper(mLauncher).bindAppWidgetIdIfAllowed(
mWidgetLoadingId, pInfo, options)) {
// Widget id bound. Inflate the widget.
mHandler.post(mInflateWidgetRunnable);
}
}
};
mInflateWidgetRunnable = new Runnable() {
@Override
public void run() {
if (LOGD) {
Log.d(TAG, "Inflating widget, id: " + mWidgetLoadingId);
}
if (mWidgetLoadingId == -1) {
return;
}
AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
(Context) mLauncher, mWidgetLoadingId, pInfo);
mInfo.boundWidget = hostView;
// We used up the widget Id in binding the above view.
mWidgetLoadingId = -1;
hostView.setVisibility(View.INVISIBLE);
int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo);
// We want the first widget layout to be the correct size. This will be important
// for width size reporting to the AppWidgetManager.
DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
unScaledSize[1]);
lp.x = lp.y = 0;
lp.customPosition = true;
hostView.setLayoutParams(lp);
if (LOGD) {
Log.d(TAG, "Adding host view to drag layer");
}
mLauncher.getDragLayer().addView(hostView);
mView.setTag(mInfo);
}
};
if (LOGD) {
Log.d(TAG, "About to bind/inflate widget");
}
mHandler.post(mBindWidgetRunnable);
return true;
}
第一步,getAppWidgetHost().allocateAppWidgetId获取服务器分配的 appWidgetId
第二部,AppWidgetManager#bindAppWidgetIdIfAllowed(int, UserHandle, ComponentName, Bundle)
为给Widget设置appWidgetId。如果成功,应用程序的AppWidgetProvider将收到ACTION_APPWIDGET_UPDATE更新广播。
绑定AppWidgetID成功后,初始化Widget界面,最终调用mLauncher.getDragLayer().addView(hostView);
添加布局到Draglayer 底层布局中。