summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/widget/PendingAppWidgetHostView.java')
-rw-r--r--src/com/android/launcher3/widget/PendingAppWidgetHostView.java318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
new file mode 100644
index 000000000..24bcebb2e
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+
+public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
+ implements OnClickListener, ItemInfoUpdateReceiver {
+ private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
+ private static final float MIN_SATUNATION = 0.7f;
+
+ private final Rect mRect = new Rect();
+ private View mDefaultView;
+ private OnClickListener mClickListener;
+ private final LauncherAppWidgetInfo mInfo;
+ private final int mStartState;
+ private final boolean mDisabledForSafeMode;
+
+ private Bitmap mIcon;
+
+ private Drawable mCenterDrawable;
+ private Drawable mSettingIconDrawable;
+
+ private boolean mDrawableSizeChanged;
+
+ private final TextPaint mPaint;
+ private Layout mSetupTextLayout;
+
+ public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
+ IconCache cache, boolean disabledForSafeMode) {
+ super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
+
+ mInfo = info;
+ mStartState = info.restoreStatus;
+ mDisabledForSafeMode = disabledForSafeMode;
+
+ mPaint = new TextPaint();
+ mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
+ mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
+ mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+ setBackgroundResource(R.drawable.pending_widget_bg);
+ setWillNotDraw(false);
+
+ setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
+ updateAppWidget(null);
+ setOnClickListener(mLauncher);
+
+ if (info.pendingItemInfo == null) {
+ info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName());
+ info.pendingItemInfo.user = info.user;
+ cache.updateIconInBackground(this, info.pendingItemInfo);
+ } else {
+ reapplyItemInfo(info.pendingItemInfo);
+ }
+ }
+
+ @Override
+ public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
+ int maxHeight) {
+ // No-op
+ }
+
+ @Override
+ protected View getDefaultView() {
+ if (mDefaultView == null) {
+ mDefaultView = mInflater.inflate(R.layout.appwidget_not_ready, this, false);
+ mDefaultView.setOnClickListener(this);
+ applyState();
+ }
+ return mDefaultView;
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener l) {
+ mClickListener = l;
+ }
+
+ public boolean isReinflateIfNeeded() {
+ return mStartState != mInfo.restoreStatus;
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mDrawableSizeChanged = true;
+ }
+
+ @Override
+ public void reapplyItemInfo(ItemInfoWithIcon info) {
+ Bitmap icon = info.iconBitmap;
+ if (mIcon == icon) {
+ return;
+ }
+ mIcon = icon;
+ if (mCenterDrawable != null) {
+ mCenterDrawable.setCallback(null);
+ mCenterDrawable = null;
+ }
+ if (mIcon != null) {
+ // The view displays three modes,
+ // 1) App icon in the center
+ // 2) Preload icon in the center
+ // 3) Setup icon in the center and app icon in the top right corner.
+ DrawableFactory drawableFactory = DrawableFactory.get(getContext());
+ if (mDisabledForSafeMode) {
+ FastBitmapDrawable disabledIcon = drawableFactory.newIcon(mIcon, mInfo);
+ disabledIcon.setIsDisabled(true);
+ mCenterDrawable = disabledIcon;
+ mSettingIconDrawable = null;
+ } else if (isReadyForClickSetup()) {
+ mCenterDrawable = drawableFactory.newIcon(mIcon, mInfo);
+ mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
+
+ updateSettingColor();
+ } else {
+ mCenterDrawable = DrawableFactory.get(getContext())
+ .newPendingIcon(mIcon, getContext());
+ mCenterDrawable.setCallback(this);
+ mSettingIconDrawable = null;
+ applyState();
+ }
+ mDrawableSizeChanged = true;
+ }
+ invalidate();
+ }
+
+ private void updateSettingColor() {
+ int color = Utilities.findDominantColorByHue(mIcon, 20);
+ // Make the dominant color bright.
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ hsv[1] = Math.min(hsv[1], MIN_SATUNATION);
+ hsv[2] = 1;
+ color = Color.HSVToColor(hsv);
+
+ mSettingIconDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return (who == mCenterDrawable) || super.verifyDrawable(who);
+ }
+
+ public void applyState() {
+ if (mCenterDrawable != null) {
+ mCenterDrawable.setLevel(Math.max(mInfo.installProgress, 0));
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ // AppWidgetHostView blocks all click events on the root view. Instead handle click events
+ // on the content and pass it along.
+ if (mClickListener != null) {
+ mClickListener.onClick(this);
+ }
+ }
+
+ /**
+ * A pending widget is ready for setup after the provider is installed and
+ * 1) Widget id is not valid: the widget id is not yet bound to the provider, probably
+ * because the launcher doesn't have appropriate permissions.
+ * Note that we would still have an allocated id as that does not
+ * require any permissions and can be done during view inflation.
+ * 2) UI is not ready: the id is valid and the bound. But the widget has a configure activity
+ * which needs to be called once.
+ */
+ public boolean isReadyForClickSetup() {
+ return !mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
+ && (mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
+ || mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID));
+ }
+
+ private void updateDrawableBounds() {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ int paddingTop = getPaddingTop();
+ int paddingBottom = getPaddingBottom();
+ int paddingLeft = getPaddingLeft();
+ int paddingRight = getPaddingRight();
+
+ int minPadding = getResources()
+ .getDimensionPixelSize(R.dimen.pending_widget_min_padding);
+
+ int availableWidth = getWidth() - paddingLeft - paddingRight - 2 * minPadding;
+ int availableHeight = getHeight() - paddingTop - paddingBottom - 2 * minPadding;
+
+ if (mSettingIconDrawable == null) {
+ int maxSize = grid.iconSizePx;
+ int size = Math.min(maxSize, Math.min(availableWidth, availableHeight));
+
+ mRect.set(0, 0, size, size);
+ mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2);
+ mCenterDrawable.setBounds(mRect);
+ } else {
+ float iconSize = Math.max(0, Math.min(availableWidth, availableHeight));
+
+ // Use twice the setting size factor, as the setting is drawn at a corner and the
+ // icon is drawn in the center.
+ float settingIconScaleFactor = 1 + SETUP_ICON_SIZE_FACTOR * 2;
+ int maxSize = Math.max(availableWidth, availableHeight);
+ if (iconSize * settingIconScaleFactor > maxSize) {
+ // There is an overlap
+ iconSize = maxSize / settingIconScaleFactor;
+ }
+
+ int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx);
+
+ // Icon top when we do not draw the text
+ int iconTop = (getHeight() - actualIconSize) / 2;
+ mSetupTextLayout = null;
+
+ if (availableWidth > 0) {
+ // Recreate the setup text.
+ mSetupTextLayout = new StaticLayout(
+ getResources().getText(R.string.gadget_setup_text), mPaint, availableWidth,
+ Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+ int textHeight = mSetupTextLayout.getHeight();
+
+ // Extra icon size due to the setting icon
+ float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor
+ + grid.iconDrawablePaddingPx;
+
+ if (minHeightWithText < availableHeight) {
+ // We can draw the text as well
+ iconTop = (getHeight() - textHeight -
+ grid.iconDrawablePaddingPx - actualIconSize) / 2;
+
+ } else {
+ // We can't draw the text. Let the iconTop be same as before.
+ mSetupTextLayout = null;
+ }
+ }
+
+ mRect.set(0, 0, actualIconSize, actualIconSize);
+ mRect.offset((getWidth() - actualIconSize) / 2, iconTop);
+ mCenterDrawable.setBounds(mRect);
+
+ mRect.left = paddingLeft + minPadding;
+ mRect.right = mRect.left + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
+ mRect.top = paddingTop + minPadding;
+ mRect.bottom = mRect.top + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
+ mSettingIconDrawable.setBounds(mRect);
+
+ if (mSetupTextLayout != null) {
+ // Set up position for dragging the text
+ mRect.left = paddingLeft + minPadding;
+ mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx;
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mCenterDrawable == null) {
+ // Nothing to draw
+ return;
+ }
+
+ if (mDrawableSizeChanged) {
+ updateDrawableBounds();
+ mDrawableSizeChanged = false;
+ }
+
+ mCenterDrawable.draw(canvas);
+ if (mSettingIconDrawable != null) {
+ mSettingIconDrawable.draw(canvas);
+ }
+ if (mSetupTextLayout != null) {
+ canvas.save();
+ canvas.translate(mRect.left, mRect.top);
+ mSetupTextLayout.draw(canvas);
+ canvas.restore();
+ }
+
+ }
+}