08ffaae3b6
on clicking promise app icon in All Apps. Only the progress will be changed with animation on progress update, no relayout is performed. If the icon is newly bound, the progress will not be animated. Bug: 23952570 Change-Id: I98d3f945f08a2abadf53f20e6007c15e56d5d410
616 lines
22 KiB
Java
616 lines
22 KiB
Java
/*
|
|
* Copyright (C) 2008 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;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.ColorStateList;
|
|
import android.content.res.Resources;
|
|
import android.content.res.TypedArray;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Region;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.util.AttributeSet;
|
|
import android.util.TypedValue;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewConfiguration;
|
|
import android.view.ViewDebug;
|
|
import android.view.ViewParent;
|
|
import android.widget.TextView;
|
|
|
|
import com.android.launcher3.IconCache.IconLoadRequest;
|
|
import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
|
|
import com.android.launcher3.badge.BadgeInfo;
|
|
import com.android.launcher3.badge.BadgeRenderer;
|
|
import com.android.launcher3.folder.FolderIconPreviewVerifier;
|
|
import com.android.launcher3.graphics.DrawableFactory;
|
|
import com.android.launcher3.graphics.HolographicOutlineHelper;
|
|
import com.android.launcher3.graphics.PreloadIconDrawable;
|
|
import com.android.launcher3.model.PackageItemInfo;
|
|
import com.android.launcher3.popup.PopupContainerWithArrow;
|
|
|
|
import java.text.NumberFormat;
|
|
|
|
/**
|
|
* TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
|
|
* because we want to make the bubble taller than the text and TextView's clip is
|
|
* too aggressive.
|
|
*/
|
|
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
|
|
|
|
// Dimensions in DP
|
|
private static final float AMBIENT_SHADOW_RADIUS = 2.5f;
|
|
private static final float KEY_SHADOW_RADIUS = 1f;
|
|
private static final float KEY_SHADOW_OFFSET = 0.5f;
|
|
private static final int AMBIENT_SHADOW_COLOR = 0x33000000;
|
|
private static final int KEY_SHADOW_COLOR = 0x66000000;
|
|
|
|
private static final int DISPLAY_WORKSPACE = 0;
|
|
private static final int DISPLAY_ALL_APPS = 1;
|
|
private static final int DISPLAY_FOLDER = 2;
|
|
|
|
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
|
|
|
|
private final Launcher mLauncher;
|
|
private Drawable mIcon;
|
|
private final boolean mCenterVertically;
|
|
private final Drawable mBackground;
|
|
private OnLongClickListener mOnLongClickListener;
|
|
private final CheckLongPressHelper mLongPressHelper;
|
|
private final HolographicOutlineHelper mOutlineHelper;
|
|
private final StylusEventHelper mStylusEventHelper;
|
|
|
|
private boolean mBackgroundSizeChanged;
|
|
|
|
private Bitmap mPressedBackground;
|
|
|
|
private float mSlop;
|
|
|
|
private final boolean mDeferShadowGenerationOnTouch;
|
|
private final boolean mCustomShadowsEnabled;
|
|
private final boolean mLayoutHorizontal;
|
|
private final int mIconSize;
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private int mTextColor;
|
|
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mStayPressed;
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mIgnorePressedStateChange;
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mDisableRelayout = false;
|
|
|
|
private IconLoadRequest mIconLoadRequest;
|
|
|
|
public BubbleTextView(Context context) {
|
|
this(context, null, 0);
|
|
}
|
|
|
|
public BubbleTextView(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
mLauncher = Launcher.getLauncher(context);
|
|
DeviceProfile grid = mLauncher.getDeviceProfile();
|
|
|
|
TypedArray a = context.obtainStyledAttributes(attrs,
|
|
R.styleable.BubbleTextView, defStyle, 0);
|
|
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, false);
|
|
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
|
|
mDeferShadowGenerationOnTouch =
|
|
a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
|
|
|
|
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
|
|
int defaultIconSize = grid.iconSizePx;
|
|
if (display == DISPLAY_WORKSPACE) {
|
|
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
|
} else if (display == DISPLAY_ALL_APPS) {
|
|
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
|
|
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
|
|
defaultIconSize = grid.allAppsIconSizePx;
|
|
} else if (display == DISPLAY_FOLDER) {
|
|
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
|
|
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
|
|
defaultIconSize = grid.folderChildIconSizePx;
|
|
}
|
|
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
|
|
|
|
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
|
|
defaultIconSize);
|
|
a.recycle();
|
|
|
|
if (mCustomShadowsEnabled) {
|
|
// Draw the background itself as the parent is drawn twice.
|
|
mBackground = getBackground();
|
|
setBackground(null);
|
|
|
|
// Set shadow layer as the larger shadow to that the textView does not clip the shadow.
|
|
float density = getResources().getDisplayMetrics().density;
|
|
setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, AMBIENT_SHADOW_COLOR);
|
|
} else {
|
|
mBackground = null;
|
|
}
|
|
|
|
mLongPressHelper = new CheckLongPressHelper(this);
|
|
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
|
|
|
|
mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
|
|
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
|
|
}
|
|
|
|
public void applyFromShortcutInfo(ShortcutInfo info) {
|
|
applyFromShortcutInfo(info, false);
|
|
}
|
|
|
|
public void applyFromShortcutInfo(ShortcutInfo info, boolean promiseStateChanged) {
|
|
applyIconAndLabel(info.iconBitmap, info);
|
|
setTag(info);
|
|
if (promiseStateChanged || info.isPromise()) {
|
|
applyPromiseState(promiseStateChanged);
|
|
}
|
|
|
|
applyBadgeState(info, false /* animate */);
|
|
}
|
|
|
|
public void applyFromApplicationInfo(AppInfo info) {
|
|
applyIconAndLabel(info.iconBitmap, info);
|
|
|
|
// We don't need to check the info since it's not a ShortcutInfo
|
|
super.setTag(info);
|
|
|
|
// Verify high res immediately
|
|
verifyHighRes();
|
|
|
|
if (info instanceof PromiseAppInfo) {
|
|
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
|
|
applyProgressLevel(promiseAppInfo.level);
|
|
}
|
|
applyBadgeState(info, false /* animate */);
|
|
}
|
|
|
|
public void applyFromPackageItemInfo(PackageItemInfo info) {
|
|
applyIconAndLabel(info.iconBitmap, info);
|
|
// We don't need to check the info since it's not a ShortcutInfo
|
|
super.setTag(info);
|
|
|
|
// Verify high res immediately
|
|
verifyHighRes();
|
|
}
|
|
|
|
private void applyIconAndLabel(Bitmap icon, ItemInfo info) {
|
|
FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(icon, info);
|
|
iconDrawable.setIsDisabled(info.isDisabled());
|
|
setIcon(iconDrawable);
|
|
setText(info.title);
|
|
if (info.contentDescription != null) {
|
|
setContentDescription(info.isDisabled()
|
|
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
|
|
: info.contentDescription);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Overrides the default long press timeout.
|
|
*/
|
|
public void setLongPressTimeout(int longPressTimeout) {
|
|
mLongPressHelper.setLongPressTimeout(longPressTimeout);
|
|
}
|
|
|
|
@Override
|
|
protected boolean setFrame(int left, int top, int right, int bottom) {
|
|
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
|
|
mBackgroundSizeChanged = true;
|
|
}
|
|
return super.setFrame(left, top, right, bottom);
|
|
}
|
|
|
|
@Override
|
|
protected boolean verifyDrawable(Drawable who) {
|
|
return who == mBackground || super.verifyDrawable(who);
|
|
}
|
|
|
|
@Override
|
|
public void setTag(Object tag) {
|
|
if (tag != null) {
|
|
LauncherModel.checkItemInfo((ItemInfo) tag);
|
|
}
|
|
super.setTag(tag);
|
|
}
|
|
|
|
@Override
|
|
public void refreshDrawableState() {
|
|
if (!mIgnorePressedStateChange) {
|
|
super.refreshDrawableState();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected int[] onCreateDrawableState(int extraSpace) {
|
|
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
|
|
if (mStayPressed) {
|
|
mergeDrawableStates(drawableState, STATE_PRESSED);
|
|
}
|
|
return drawableState;
|
|
}
|
|
|
|
/** Returns the icon for this view. */
|
|
public Drawable getIcon() {
|
|
return mIcon;
|
|
}
|
|
|
|
/** Returns whether the layout is horizontal. */
|
|
public boolean isLayoutHorizontal() {
|
|
return mLayoutHorizontal;
|
|
}
|
|
|
|
@Override
|
|
public void setOnLongClickListener(OnLongClickListener l) {
|
|
super.setOnLongClickListener(l);
|
|
mOnLongClickListener = l;
|
|
}
|
|
|
|
public OnLongClickListener getOnLongClickListener() {
|
|
return mOnLongClickListener;
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
// Call the superclass onTouchEvent first, because sometimes it changes the state to
|
|
// isPressed() on an ACTION_UP
|
|
boolean result = super.onTouchEvent(event);
|
|
|
|
// Check for a stylus button press, if it occurs cancel any long press checks.
|
|
if (mStylusEventHelper.onMotionEvent(event)) {
|
|
mLongPressHelper.cancelLongPress();
|
|
result = true;
|
|
}
|
|
|
|
switch (event.getAction()) {
|
|
case MotionEvent.ACTION_DOWN:
|
|
// So that the pressed outline is visible immediately on setStayPressed(),
|
|
// we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
|
|
// to create it)
|
|
if (!mDeferShadowGenerationOnTouch && mPressedBackground == null) {
|
|
mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
|
|
}
|
|
|
|
// If we're in a stylus button press, don't check for long press.
|
|
if (!mStylusEventHelper.inStylusButtonPressed()) {
|
|
mLongPressHelper.postCheckForLongPress();
|
|
}
|
|
break;
|
|
case MotionEvent.ACTION_CANCEL:
|
|
case MotionEvent.ACTION_UP:
|
|
// If we've touched down and up on an item, and it's still not "pressed", then
|
|
// destroy the pressed outline
|
|
if (!isPressed()) {
|
|
mPressedBackground = null;
|
|
}
|
|
|
|
mLongPressHelper.cancelLongPress();
|
|
break;
|
|
case MotionEvent.ACTION_MOVE:
|
|
if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
|
|
mLongPressHelper.cancelLongPress();
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void setStayPressed(boolean stayPressed) {
|
|
mStayPressed = stayPressed;
|
|
if (!stayPressed) {
|
|
HolographicOutlineHelper.getInstance(getContext()).recycleShadowBitmap(mPressedBackground);
|
|
mPressedBackground = null;
|
|
} else {
|
|
if (mPressedBackground == null) {
|
|
mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
|
|
}
|
|
}
|
|
|
|
// Only show the shadow effect when persistent pressed state is set.
|
|
ViewParent parent = getParent();
|
|
if (parent != null && parent.getParent() instanceof BubbleTextShadowHandler) {
|
|
((BubbleTextShadowHandler) parent.getParent()).setPressedIcon(
|
|
this, mPressedBackground);
|
|
}
|
|
|
|
refreshDrawableState();
|
|
}
|
|
|
|
void clearPressedBackground() {
|
|
setPressed(false);
|
|
setStayPressed(false);
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
if (super.onKeyDown(keyCode, event)) {
|
|
// Pre-create shadow so show immediately on click.
|
|
if (mPressedBackground == null) {
|
|
mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
// Unlike touch events, keypress event propagate pressed state change immediately,
|
|
// without waiting for onClickHandler to execute. Disable pressed state changes here
|
|
// to avoid flickering.
|
|
mIgnorePressedStateChange = true;
|
|
boolean result = super.onKeyUp(keyCode, event);
|
|
|
|
mPressedBackground = null;
|
|
mIgnorePressedStateChange = false;
|
|
refreshDrawableState();
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void draw(Canvas canvas) {
|
|
if (!mCustomShadowsEnabled) {
|
|
super.draw(canvas);
|
|
return;
|
|
}
|
|
|
|
final Drawable background = mBackground;
|
|
if (background != null) {
|
|
final int scrollX = getScrollX();
|
|
final int scrollY = getScrollY();
|
|
|
|
if (mBackgroundSizeChanged) {
|
|
background.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
|
|
mBackgroundSizeChanged = false;
|
|
}
|
|
|
|
if ((scrollX | scrollY) == 0) {
|
|
background.draw(canvas);
|
|
} else {
|
|
canvas.translate(scrollX, scrollY);
|
|
background.draw(canvas);
|
|
canvas.translate(-scrollX, -scrollY);
|
|
}
|
|
}
|
|
|
|
// If text is transparent, don't draw any shadow
|
|
if ((getCurrentTextColor() >> 24) == 0) {
|
|
getPaint().clearShadowLayer();
|
|
super.draw(canvas);
|
|
return;
|
|
}
|
|
|
|
// We enhance the shadow by drawing the shadow twice
|
|
float density = getResources().getDisplayMetrics().density;
|
|
getPaint().setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, AMBIENT_SHADOW_COLOR);
|
|
super.draw(canvas);
|
|
canvas.save(Canvas.CLIP_SAVE_FLAG);
|
|
canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
|
|
getScrollX() + getWidth(),
|
|
getScrollY() + getHeight(), Region.Op.INTERSECT);
|
|
getPaint().setShadowLayer(
|
|
density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, KEY_SHADOW_COLOR);
|
|
super.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
|
|
@Override
|
|
protected void onAttachedToWindow() {
|
|
super.onAttachedToWindow();
|
|
|
|
if (mBackground != null) mBackground.setCallback(this);
|
|
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
if (mCenterVertically) {
|
|
Paint.FontMetrics fm = getPaint().getFontMetrics();
|
|
int cellHeightPx = mIconSize + getCompoundDrawablePadding() +
|
|
(int) Math.ceil(fm.bottom - fm.top);
|
|
int height = MeasureSpec.getSize(heightMeasureSpec);
|
|
setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
|
|
getPaddingBottom());
|
|
}
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
}
|
|
|
|
@Override
|
|
protected void onDetachedFromWindow() {
|
|
super.onDetachedFromWindow();
|
|
if (mBackground != null) mBackground.setCallback(null);
|
|
}
|
|
|
|
@Override
|
|
public void setTextColor(int color) {
|
|
mTextColor = color;
|
|
super.setTextColor(color);
|
|
}
|
|
|
|
@Override
|
|
public void setTextColor(ColorStateList colors) {
|
|
mTextColor = colors.getDefaultColor();
|
|
super.setTextColor(colors);
|
|
}
|
|
|
|
public void setTextVisibility(boolean visible) {
|
|
Resources res = getResources();
|
|
if (visible) {
|
|
super.setTextColor(mTextColor);
|
|
} else {
|
|
super.setTextColor(res.getColor(android.R.color.transparent));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void cancelLongPress() {
|
|
super.cancelLongPress();
|
|
|
|
mLongPressHelper.cancelLongPress();
|
|
}
|
|
|
|
public void applyPromiseState(boolean promiseStateChanged) {
|
|
if (getTag() instanceof ShortcutInfo) {
|
|
ShortcutInfo info = (ShortcutInfo) getTag();
|
|
final boolean isPromise = info.isPromise();
|
|
final int progressLevel = isPromise ?
|
|
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
|
|
info.getInstallProgress() : 0)) : 100;
|
|
|
|
PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel);
|
|
if (preloadDrawable != null && promiseStateChanged) {
|
|
preloadDrawable.maybePerformFinishedAnimation();
|
|
}
|
|
}
|
|
}
|
|
|
|
public PreloadIconDrawable applyProgressLevel(int progressLevel) {
|
|
if (getTag() instanceof ItemInfoWithIcon) {
|
|
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
|
|
setContentDescription(progressLevel > 0
|
|
? getContext().getString(R.string.app_downloading_title, info.title,
|
|
NumberFormat.getPercentInstance().format(progressLevel * 0.01))
|
|
: getContext().getString(R.string.app_waiting_download_title, info.title));
|
|
|
|
if (mIcon != null) {
|
|
final PreloadIconDrawable preloadDrawable;
|
|
if (mIcon instanceof PreloadIconDrawable) {
|
|
preloadDrawable = (PreloadIconDrawable) mIcon;
|
|
preloadDrawable.setLevel(progressLevel);
|
|
} else {
|
|
preloadDrawable = DrawableFactory.get(getContext())
|
|
.newPendingIcon(info.iconBitmap, getContext());
|
|
preloadDrawable.setLevel(progressLevel);
|
|
setIcon(preloadDrawable);
|
|
}
|
|
return preloadDrawable;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void applyBadgeState(ItemInfo itemInfo, boolean animate) {
|
|
if (mIcon instanceof FastBitmapDrawable) {
|
|
BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
|
|
BadgeRenderer badgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
|
|
PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(mLauncher);
|
|
if (popup != null) {
|
|
popup.updateNotificationHeader(badgeInfo, itemInfo);
|
|
}
|
|
((FastBitmapDrawable) mIcon).applyIconBadge(badgeInfo, badgeRenderer, animate);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the icon for this view based on the layout direction.
|
|
*/
|
|
private void setIcon(Drawable icon) {
|
|
mIcon = icon;
|
|
mIcon.setBounds(0, 0, mIconSize, mIconSize);
|
|
applyCompoundDrawables(mIcon);
|
|
}
|
|
|
|
protected void applyCompoundDrawables(Drawable icon) {
|
|
if (mLayoutHorizontal) {
|
|
setCompoundDrawablesRelative(icon, null, null, null);
|
|
} else {
|
|
setCompoundDrawables(null, icon, null, null);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void requestLayout() {
|
|
if (!mDisableRelayout) {
|
|
super.requestLayout();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Applies the item info if it is same as what the view is pointing to currently.
|
|
*/
|
|
@Override
|
|
public void reapplyItemInfo(ItemInfoWithIcon info) {
|
|
if (getTag() == info) {
|
|
mIconLoadRequest = null;
|
|
mDisableRelayout = true;
|
|
|
|
if (info instanceof AppInfo) {
|
|
applyFromApplicationInfo((AppInfo) info);
|
|
} else if (info instanceof ShortcutInfo) {
|
|
applyFromShortcutInfo((ShortcutInfo) info);
|
|
FolderIconPreviewVerifier verifier =
|
|
new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
|
|
if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
|
|
View folderIcon =
|
|
mLauncher.getWorkspace().getHomescreenIconByItemId(info.container);
|
|
if (folderIcon != null) {
|
|
folderIcon.invalidate();
|
|
}
|
|
}
|
|
} else if (info instanceof PackageItemInfo) {
|
|
applyFromPackageItemInfo((PackageItemInfo) info);
|
|
}
|
|
|
|
mDisableRelayout = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the current icon is high-res otherwise posts a request to load the icon.
|
|
*/
|
|
public void verifyHighRes() {
|
|
if (mIconLoadRequest != null) {
|
|
mIconLoadRequest.cancel();
|
|
mIconLoadRequest = null;
|
|
}
|
|
if (getTag() instanceof ItemInfoWithIcon) {
|
|
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
|
|
if (info.usingLowResIcon) {
|
|
mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
|
|
.updateIconInBackground(BubbleTextView.this, info);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if the view can show custom shortcuts.
|
|
*/
|
|
public boolean hasDeepShortcuts() {
|
|
return !mLauncher.getPopupDataProvider().getShortcutIdsForItem((ItemInfo) getTag())
|
|
.isEmpty();
|
|
}
|
|
|
|
public int getIconSize() {
|
|
return mIconSize;
|
|
}
|
|
|
|
/**
|
|
* Interface to be implemented by the grand parent to allow click shadow effect.
|
|
*/
|
|
public interface BubbleTextShadowHandler {
|
|
void setPressedIcon(BubbleTextView icon, Bitmap background);
|
|
}
|
|
}
|