mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 16:26:47 +00:00
- show instruction toast on clicking the widget - Add animation when widget drops on the workspace. Added WidgetHostViewLoader to handle short press and assign widget host view to enable animation b/19897708 Change-Id: Iec36d72cb21bf09343d0beeb31a09bf8b0cb5e0d
198 lines
7.6 KiB
Java
198 lines
7.6 KiB
Java
package com.android.launcher3.widget;
|
|
|
|
import android.appwidget.AppWidgetHostView;
|
|
import android.appwidget.AppWidgetManager;
|
|
import android.content.Context;
|
|
import android.graphics.Rect;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
|
|
import com.android.launcher3.AppWidgetResizeFrame;
|
|
import com.android.launcher3.DragLayer;
|
|
import com.android.launcher3.Launcher;
|
|
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
|
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
|
|
|
public class WidgetHostViewLoader {
|
|
|
|
private static final boolean DEBUG = false;
|
|
private static final String TAG = "WidgetHostViewLoader";
|
|
|
|
/* constants used for widget loading state. */
|
|
private static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
|
|
private static final int WIDGET_PRELOAD_PENDING = 0;
|
|
private static final int WIDGET_BOUND = 1;
|
|
private static final int WIDGET_INFLATED = 2;
|
|
|
|
int mState = WIDGET_NO_CLEANUP_REQUIRED;
|
|
|
|
/* Runnables to handle inflation and binding. */
|
|
private Runnable mInflateWidgetRunnable = null;
|
|
private Runnable mBindWidgetRunnable = null;
|
|
|
|
/* Id of the widget being handled. */
|
|
int mWidgetLoadingId = -1;
|
|
PendingAddWidgetInfo mCreateWidgetInfo = null;
|
|
|
|
// TODO: technically, this class should not have to know the existence of the launcher.
|
|
private Launcher mLauncher;
|
|
private Handler mHandler;
|
|
|
|
public WidgetHostViewLoader(Launcher launcher) {
|
|
mLauncher = launcher;
|
|
mHandler = new Handler();
|
|
}
|
|
|
|
/**
|
|
* Start loading the widget.
|
|
*/
|
|
public void load(View v) {
|
|
if (mCreateWidgetInfo != null) {
|
|
// Just in case the cleanup process wasn't properly executed.
|
|
finish(false);
|
|
}
|
|
boolean status = false;
|
|
if (v.getTag() instanceof PendingAddWidgetInfo) {
|
|
mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
|
|
status = preloadWidget(v, mCreateWidgetInfo);
|
|
}
|
|
if (DEBUG) {
|
|
Log.d(TAG, String.format("load started on [state=%d, status=%s]", mState, status));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Clean up according to what the last known state was.
|
|
* @param widgetIdUsed {@code true} if the widgetId was consumed which can happen only
|
|
* when view is fully inflated
|
|
*/
|
|
public void finish(boolean widgetIdUsed) {
|
|
if (DEBUG) {
|
|
Log.d(TAG, String.format("cancel on state [%d] widgetId=[%d]",
|
|
mState, mWidgetLoadingId));
|
|
}
|
|
|
|
// If the widget was not added, we may need to do further cleanup.
|
|
PendingAddWidgetInfo info = mCreateWidgetInfo;
|
|
mCreateWidgetInfo = null;
|
|
|
|
if (mState == WIDGET_PRELOAD_PENDING) {
|
|
// We never did any preloading, so just remove pending callbacks to do so
|
|
mHandler.removeCallbacks(mBindWidgetRunnable);
|
|
mHandler.removeCallbacks(mInflateWidgetRunnable);
|
|
} else if (mState == WIDGET_BOUND) {
|
|
// Delete the widget id which was allocated
|
|
if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
|
|
mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
|
|
}
|
|
|
|
// We never got around to inflating the widget, so remove the callback to do so.
|
|
mHandler.removeCallbacks(mInflateWidgetRunnable);
|
|
} else if (mState == WIDGET_INFLATED && !widgetIdUsed) {
|
|
// Delete the widget id which was allocated
|
|
if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
|
|
mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
|
|
}
|
|
|
|
// The widget was inflated and added to the DragLayer -- remove it.
|
|
AppWidgetHostView widget = info.boundWidget;
|
|
mLauncher.getDragLayer().removeView(widget);
|
|
}
|
|
setState(WIDGET_NO_CLEANUP_REQUIRED);
|
|
mWidgetLoadingId = -1;
|
|
}
|
|
|
|
private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) {
|
|
final LauncherAppWidgetProviderInfo pInfo = info.info;
|
|
|
|
final Bundle options = pInfo.isCustomWidget ? null :
|
|
getDefaultOptionsForWidget(mLauncher, info);
|
|
|
|
// If there is a configuration activity, do not follow thru bound and inflate.
|
|
if (pInfo.configure != null) {
|
|
info.bindOptions = options;
|
|
return false;
|
|
}
|
|
setState(WIDGET_PRELOAD_PENDING);
|
|
mBindWidgetRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (pInfo.isCustomWidget) {
|
|
setState(WIDGET_BOUND);
|
|
return;
|
|
}
|
|
|
|
mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
|
|
if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
|
|
mWidgetLoadingId, pInfo, options)) {
|
|
setState(WIDGET_BOUND);
|
|
}
|
|
}
|
|
};
|
|
mHandler.post(mBindWidgetRunnable);
|
|
|
|
mInflateWidgetRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (mState != WIDGET_BOUND) {
|
|
return;
|
|
}
|
|
AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
|
|
(Context) mLauncher, mWidgetLoadingId, pInfo);
|
|
info.boundWidget = hostView;
|
|
setState(WIDGET_INFLATED);
|
|
hostView.setVisibility(View.INVISIBLE);
|
|
int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
|
|
|
|
// 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);
|
|
mLauncher.getDragLayer().addView(hostView);
|
|
v.setTag(info);
|
|
}
|
|
};
|
|
mHandler.post(mInflateWidgetRunnable);
|
|
return true;
|
|
}
|
|
|
|
public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
|
|
Bundle options = null;
|
|
Rect rect = new Rect();
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
|
|
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
|
|
info.componentName, null);
|
|
|
|
float density = launcher.getResources().getDisplayMetrics().density;
|
|
int xPaddingDips = (int) ((padding.left + padding.right) / density);
|
|
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
|
|
|
|
options = new Bundle();
|
|
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
|
|
rect.left - xPaddingDips);
|
|
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
|
|
rect.top - yPaddingDips);
|
|
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
|
|
rect.right - xPaddingDips);
|
|
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
|
|
rect.bottom - yPaddingDips);
|
|
}
|
|
return options;
|
|
}
|
|
|
|
private void setState(int state) {
|
|
if (DEBUG) {
|
|
Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
|
|
}
|
|
mState = state;
|
|
}
|
|
}
|