Loading res/layout/widget_cell.xml +2 −2 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ android:fadingEdge="horizontal" android:textColor="#FFFFFFFF" android:textSize="12sp" android:textSize="16sp" android:textAlignment="viewStart" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" Loading @@ -64,7 +64,7 @@ android:layout_weight="0" android:gravity="start" android:textColor="#FFFFFFFF" android:textSize="12sp" android:textSize="16sp" android:textAlignment="viewStart" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" Loading src/com/android/launcher3/AppWidgetResizeFrame.java +1 −1 Original line number Diff line number Diff line Loading @@ -349,7 +349,7 @@ public class AppWidgetResizeFrame extends FrameLayout { mTmpRect.right, mTmpRect.bottom); } static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) { public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) { if (rect == null) { rect = new Rect(); } Loading src/com/android/launcher3/Launcher.java +2 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetsContainerView; import java.io.DataInputStream; Loading Loading @@ -3944,7 +3945,7 @@ public class Launcher extends Activity pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; Bundle options = null; // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo); WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( Loading src/com/android/launcher3/widget/WidgetCell.java +55 −157 Original line number Diff line number Diff line Loading @@ -24,8 +24,6 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.view.View.OnLayoutChangeListener; import android.widget.ImageView; Loading @@ -43,7 +41,7 @@ import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest; import com.android.launcher3.compat.AppWidgetManagerCompat; /** * The linear layout used strictly for the widget tray. * Represents the individual cell of the widget inside the widget tray. */ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { Loading @@ -53,14 +51,12 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { private static final int FADE_IN_DURATION_MS = 70; private int mPresetPreviewSize; private static WidgetCell sShortpressTarget = null; private ImageView mWidgetImage; private TextView mWidgetName; private TextView mWidgetDims; private final Rect mOriginalImagePadding = new Rect(); private String mDimensionsFormatString; private CheckForShortPress mPendingCheckForShortPress = null; private ShortPressListener mShortPressListener = null; private boolean mShortPressTriggered = false; private boolean mIsAppWidget; private Object mInfo; Loading Loading @@ -92,57 +88,27 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { protected void onFinishInflate() { super.onFinishInflate(); final ImageView image = (ImageView) findViewById(R.id.widget_preview); mOriginalImagePadding.left = image.getPaddingLeft(); mOriginalImagePadding.top = image.getPaddingTop(); mOriginalImagePadding.right = image.getPaddingRight(); mOriginalImagePadding.bottom = image.getPaddingBottom(); mWidgetImage = (ImageView) findViewById(R.id.widget_preview); mOriginalImagePadding.left = mWidgetImage.getPaddingLeft(); mOriginalImagePadding.top = mWidgetImage.getPaddingTop(); mOriginalImagePadding.right = mWidgetImage.getPaddingRight(); mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom(); // Ensure we are using the right text size LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); TextView name = (TextView) findViewById(R.id.widget_name); if (name != null) { name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); } TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); } } @Override protected void onDetachedFromWindow() { if (DEBUG) { Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString())); } super.onDetachedFromWindow(); deletePreview(false); DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); mWidgetName = ((TextView) findViewById(R.id.widget_name)); mWidgetDims = ((TextView) findViewById(R.id.widget_dims)); } public void reset() { ImageView image = (ImageView) findViewById(R.id.widget_preview); final TextView name = (TextView) findViewById(R.id.widget_name); final TextView dims = (TextView) findViewById(R.id.widget_dims); image.setImageDrawable(null); name.setText(null); dims.setText(null); } public void deletePreview(boolean recycleImage) { if (recycleImage) { final ImageView image = (ImageView) findViewById(R.id.widget_preview); if (image != null) { image.setImageDrawable(null); } } if (mActiveRequest != null) { mActiveRequest.cancel(recycleImage); mActiveRequest = null; } mWidgetImage.setImageDrawable(null); mWidgetName.setText(null); mWidgetDims.setText(null); } /** * Apply the widget provider info to the view. */ public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info, int maxWidth, WidgetPreviewLoader loader) { LauncherAppState app = LauncherAppState.getInstance(); Loading @@ -150,37 +116,41 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { mIsAppWidget = true; mInfo = info; final ImageView image = (ImageView) findViewById(R.id.widget_preview); if (maxWidth > -1) { image.setMaxWidth(maxWidth); mWidgetImage.setMaxWidth(maxWidth); } final TextView name = (TextView) findViewById(R.id.widget_name); name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { // TODO(hyunyoungs): setup a cache for these labels. mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); int hSpan = Math.min(info.spanX, (int) grid.numColumns); int vSpan = Math.min(info.spanY, (int) grid.numRows); dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); } mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); mWidgetPreviewLoader = loader; } /** * Apply the resolve info to the view. */ public void applyFromResolveInfo( PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) { mIsAppWidget = false; mInfo = info; CharSequence label = info.loadLabel(pm); final TextView name = (TextView) findViewById(R.id.widget_name); name.setText(label); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { dims.setText(String.format(mDimensionsFormatString, 1, 1)); } mWidgetName.setText(label); mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1)); mWidgetPreviewLoader = loader; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); deletePreview(false); if (DEBUG) { Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString())); } } public int[] getPreviewSize() { final ImageView i = (ImageView) findViewById(R.id.widget_preview); int[] maxSize = new int[2]; maxSize[0] = mPresetPreviewSize; maxSize[1] = mPresetPreviewSize; Loading @@ -189,110 +159,28 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { public void applyPreview(Bitmap bitmap) { FastBitmapDrawable preview = new FastBitmapDrawable(bitmap); final WidgetImageView image = (WidgetImageView) findViewById(R.id.widget_preview); if (DEBUG) { Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s", getTagToString(), preview)); } if (preview != null) { image.mAllowRequestLayout = false; image.setImageDrawable(preview); mWidgetImage.setImageDrawable(preview); if (mIsAppWidget) { // center horizontally int[] imageSize = getPreviewSize(); int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2; image.setPadding(mOriginalImagePadding.left + centerAmount, mWidgetImage.setPadding(mOriginalImagePadding.left + centerAmount, mOriginalImagePadding.top, mOriginalImagePadding.right, mOriginalImagePadding.bottom); } image.setAlpha(0f); image.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS); image.mAllowRequestLayout = true; image.requestLayout(); } } void setShortPressListener(ShortPressListener listener) { mShortPressListener = listener; } interface ShortPressListener { void onShortPress(View v); void cleanUpShortPress(View v); } class CheckForShortPress implements Runnable { public void run() { if (sShortpressTarget != null) return; if (mShortPressListener != null) { mShortPressListener.onShortPress(WidgetCell.this); sShortpressTarget = WidgetCell.this; } mShortPressTriggered = true; mWidgetImage.setAlpha(0f); mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS); // TODO(hyunyoungs): figure out why this has to be called explicitly. mWidgetImage.requestLayout(); } } private void checkForShortPress() { if (sShortpressTarget != null) return; if (mPendingCheckForShortPress == null) { mPendingCheckForShortPress = new CheckForShortPress(); } postDelayed(mPendingCheckForShortPress, 120); } /** * Remove the longpress detection timer. */ private void removeShortPressCallback() { if (mPendingCheckForShortPress != null) { removeCallbacks(mPendingCheckForShortPress); } } private void cleanUpShortPress() { removeShortPressCallback(); if (mShortPressTriggered) { if (mShortPressListener != null) { mShortPressListener.cleanUpShortPress(WidgetCell.this); } mShortPressTriggered = false; } } static void resetShortPressTarget() { sShortpressTarget = null; } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: cleanUpShortPress(); break; case MotionEvent.ACTION_DOWN: checkForShortPress(); break; case MotionEvent.ACTION_CANCEL: cleanUpShortPress(); break; case MotionEvent.ACTION_MOVE: break; } // We eat up the touch events here, since the PagedView (which uses the same swiping // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when // the user is scrolling between pages. This means that if the pages themselves don't // handle touch events, it gets forwarded up to PagedView itself, and it's own // onTouchEvent() handling will prevent further intercept touch events from being called // (it's the same view in that case). This is not ideal, but to prevent more changes, // we just always mark the touch event as handled. return true; } public void ensurePreview() { if (mActiveRequest != null) { return; Loading Loading @@ -331,6 +219,16 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { return Math.min(size[0], info.spanX * cellWidth); } private void deletePreview(boolean recycleImage) { mWidgetImage.setImageDrawable(null); if (mActiveRequest != null) { mActiveRequest.cancel(recycleImage); mActiveRequest = null; } } /** * Helper method to get the string info of the tag. */ Loading src/com/android/launcher3/widget/WidgetHostViewLoader.java 0 → 100644 +197 −0 Original line number Diff line number Diff line 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; } } Loading
res/layout/widget_cell.xml +2 −2 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ android:fadingEdge="horizontal" android:textColor="#FFFFFFFF" android:textSize="12sp" android:textSize="16sp" android:textAlignment="viewStart" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" Loading @@ -64,7 +64,7 @@ android:layout_weight="0" android:gravity="start" android:textColor="#FFFFFFFF" android:textSize="12sp" android:textSize="16sp" android:textAlignment="viewStart" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" Loading
src/com/android/launcher3/AppWidgetResizeFrame.java +1 −1 Original line number Diff line number Diff line Loading @@ -349,7 +349,7 @@ public class AppWidgetResizeFrame extends FrameLayout { mTmpRect.right, mTmpRect.bottom); } static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) { public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) { if (rect == null) { rect = new Rect(); } Loading
src/com/android/launcher3/Launcher.java +2 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetsContainerView; import java.io.DataInputStream; Loading Loading @@ -3944,7 +3945,7 @@ public class Launcher extends Activity pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; Bundle options = null; // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo); WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( Loading
src/com/android/launcher3/widget/WidgetCell.java +55 −157 Original line number Diff line number Diff line Loading @@ -24,8 +24,6 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.view.View.OnLayoutChangeListener; import android.widget.ImageView; Loading @@ -43,7 +41,7 @@ import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest; import com.android.launcher3.compat.AppWidgetManagerCompat; /** * The linear layout used strictly for the widget tray. * Represents the individual cell of the widget inside the widget tray. */ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { Loading @@ -53,14 +51,12 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { private static final int FADE_IN_DURATION_MS = 70; private int mPresetPreviewSize; private static WidgetCell sShortpressTarget = null; private ImageView mWidgetImage; private TextView mWidgetName; private TextView mWidgetDims; private final Rect mOriginalImagePadding = new Rect(); private String mDimensionsFormatString; private CheckForShortPress mPendingCheckForShortPress = null; private ShortPressListener mShortPressListener = null; private boolean mShortPressTriggered = false; private boolean mIsAppWidget; private Object mInfo; Loading Loading @@ -92,57 +88,27 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { protected void onFinishInflate() { super.onFinishInflate(); final ImageView image = (ImageView) findViewById(R.id.widget_preview); mOriginalImagePadding.left = image.getPaddingLeft(); mOriginalImagePadding.top = image.getPaddingTop(); mOriginalImagePadding.right = image.getPaddingRight(); mOriginalImagePadding.bottom = image.getPaddingBottom(); mWidgetImage = (ImageView) findViewById(R.id.widget_preview); mOriginalImagePadding.left = mWidgetImage.getPaddingLeft(); mOriginalImagePadding.top = mWidgetImage.getPaddingTop(); mOriginalImagePadding.right = mWidgetImage.getPaddingRight(); mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom(); // Ensure we are using the right text size LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); TextView name = (TextView) findViewById(R.id.widget_name); if (name != null) { name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); } TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); } } @Override protected void onDetachedFromWindow() { if (DEBUG) { Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString())); } super.onDetachedFromWindow(); deletePreview(false); DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); mWidgetName = ((TextView) findViewById(R.id.widget_name)); mWidgetDims = ((TextView) findViewById(R.id.widget_dims)); } public void reset() { ImageView image = (ImageView) findViewById(R.id.widget_preview); final TextView name = (TextView) findViewById(R.id.widget_name); final TextView dims = (TextView) findViewById(R.id.widget_dims); image.setImageDrawable(null); name.setText(null); dims.setText(null); } public void deletePreview(boolean recycleImage) { if (recycleImage) { final ImageView image = (ImageView) findViewById(R.id.widget_preview); if (image != null) { image.setImageDrawable(null); } } if (mActiveRequest != null) { mActiveRequest.cancel(recycleImage); mActiveRequest = null; } mWidgetImage.setImageDrawable(null); mWidgetName.setText(null); mWidgetDims.setText(null); } /** * Apply the widget provider info to the view. */ public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info, int maxWidth, WidgetPreviewLoader loader) { LauncherAppState app = LauncherAppState.getInstance(); Loading @@ -150,37 +116,41 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { mIsAppWidget = true; mInfo = info; final ImageView image = (ImageView) findViewById(R.id.widget_preview); if (maxWidth > -1) { image.setMaxWidth(maxWidth); mWidgetImage.setMaxWidth(maxWidth); } final TextView name = (TextView) findViewById(R.id.widget_name); name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { // TODO(hyunyoungs): setup a cache for these labels. mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); int hSpan = Math.min(info.spanX, (int) grid.numColumns); int vSpan = Math.min(info.spanY, (int) grid.numRows); dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); } mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); mWidgetPreviewLoader = loader; } /** * Apply the resolve info to the view. */ public void applyFromResolveInfo( PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) { mIsAppWidget = false; mInfo = info; CharSequence label = info.loadLabel(pm); final TextView name = (TextView) findViewById(R.id.widget_name); name.setText(label); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { dims.setText(String.format(mDimensionsFormatString, 1, 1)); } mWidgetName.setText(label); mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1)); mWidgetPreviewLoader = loader; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); deletePreview(false); if (DEBUG) { Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString())); } } public int[] getPreviewSize() { final ImageView i = (ImageView) findViewById(R.id.widget_preview); int[] maxSize = new int[2]; maxSize[0] = mPresetPreviewSize; maxSize[1] = mPresetPreviewSize; Loading @@ -189,110 +159,28 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { public void applyPreview(Bitmap bitmap) { FastBitmapDrawable preview = new FastBitmapDrawable(bitmap); final WidgetImageView image = (WidgetImageView) findViewById(R.id.widget_preview); if (DEBUG) { Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s", getTagToString(), preview)); } if (preview != null) { image.mAllowRequestLayout = false; image.setImageDrawable(preview); mWidgetImage.setImageDrawable(preview); if (mIsAppWidget) { // center horizontally int[] imageSize = getPreviewSize(); int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2; image.setPadding(mOriginalImagePadding.left + centerAmount, mWidgetImage.setPadding(mOriginalImagePadding.left + centerAmount, mOriginalImagePadding.top, mOriginalImagePadding.right, mOriginalImagePadding.bottom); } image.setAlpha(0f); image.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS); image.mAllowRequestLayout = true; image.requestLayout(); } } void setShortPressListener(ShortPressListener listener) { mShortPressListener = listener; } interface ShortPressListener { void onShortPress(View v); void cleanUpShortPress(View v); } class CheckForShortPress implements Runnable { public void run() { if (sShortpressTarget != null) return; if (mShortPressListener != null) { mShortPressListener.onShortPress(WidgetCell.this); sShortpressTarget = WidgetCell.this; } mShortPressTriggered = true; mWidgetImage.setAlpha(0f); mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS); // TODO(hyunyoungs): figure out why this has to be called explicitly. mWidgetImage.requestLayout(); } } private void checkForShortPress() { if (sShortpressTarget != null) return; if (mPendingCheckForShortPress == null) { mPendingCheckForShortPress = new CheckForShortPress(); } postDelayed(mPendingCheckForShortPress, 120); } /** * Remove the longpress detection timer. */ private void removeShortPressCallback() { if (mPendingCheckForShortPress != null) { removeCallbacks(mPendingCheckForShortPress); } } private void cleanUpShortPress() { removeShortPressCallback(); if (mShortPressTriggered) { if (mShortPressListener != null) { mShortPressListener.cleanUpShortPress(WidgetCell.this); } mShortPressTriggered = false; } } static void resetShortPressTarget() { sShortpressTarget = null; } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: cleanUpShortPress(); break; case MotionEvent.ACTION_DOWN: checkForShortPress(); break; case MotionEvent.ACTION_CANCEL: cleanUpShortPress(); break; case MotionEvent.ACTION_MOVE: break; } // We eat up the touch events here, since the PagedView (which uses the same swiping // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when // the user is scrolling between pages. This means that if the pages themselves don't // handle touch events, it gets forwarded up to PagedView itself, and it's own // onTouchEvent() handling will prevent further intercept touch events from being called // (it's the same view in that case). This is not ideal, but to prevent more changes, // we just always mark the touch event as handled. return true; } public void ensurePreview() { if (mActiveRequest != null) { return; Loading Loading @@ -331,6 +219,16 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { return Math.min(size[0], info.spanX * cellWidth); } private void deletePreview(boolean recycleImage) { mWidgetImage.setImageDrawable(null); if (mActiveRequest != null) { mActiveRequest.cancel(recycleImage); mActiveRequest = null; } } /** * Helper method to get the string info of the tag. */ Loading
src/com/android/launcher3/widget/WidgetHostViewLoader.java 0 → 100644 +197 −0 Original line number Diff line number Diff line 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; } }