1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.shortcuts; 18 19 import android.content.Context; 20 import android.content.pm.ShortcutInfo; 21 import android.content.res.ColorStateList; 22 import android.graphics.Color; 23 import android.graphics.Point; 24 import android.graphics.drawable.ColorDrawable; 25 import android.graphics.drawable.Drawable; 26 import android.graphics.drawable.GradientDrawable; 27 import android.graphics.drawable.RippleDrawable; 28 import android.text.TextUtils; 29 import android.util.AttributeSet; 30 import android.view.View; 31 import android.widget.FrameLayout; 32 33 import com.android.launcher3.BubbleTextView; 34 import com.android.launcher3.Launcher; 35 import com.android.launcher3.R; 36 import com.android.launcher3.Utilities; 37 import com.android.launcher3.model.data.WorkspaceItemInfo; 38 import com.android.launcher3.popup.PopupContainerWithArrow; 39 import com.android.launcher3.util.Themes; 40 import com.android.launcher3.views.BubbleTextHolder; 41 42 /** 43 * A {@link android.widget.FrameLayout} that contains an icon and a {@link BubbleTextView} for text. 44 * This lets us animate the child BubbleTextView's background (transparent ripple) separately from 45 * the {@link DeepShortcutView} background color. 46 */ 47 public class DeepShortcutView extends FrameLayout implements BubbleTextHolder { 48 49 private static final Point sTempPoint = new Point(); 50 51 private final Drawable mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT); 52 53 private BubbleTextView mBubbleText; 54 private View mIconView; 55 56 private WorkspaceItemInfo mInfo; 57 private ShortcutInfo mDetail; 58 DeepShortcutView(Context context)59 public DeepShortcutView(Context context) { 60 this(context, null, 0); 61 } 62 DeepShortcutView(Context context, AttributeSet attrs)63 public DeepShortcutView(Context context, AttributeSet attrs) { 64 this(context, attrs, 0); 65 } 66 DeepShortcutView(Context context, AttributeSet attrs, int defStyle)67 public DeepShortcutView(Context context, AttributeSet attrs, int defStyle) { 68 super(context, attrs, defStyle); 69 } 70 71 @Override onFinishInflate()72 protected void onFinishInflate() { 73 super.onFinishInflate(); 74 mBubbleText = findViewById(R.id.bubble_text); 75 mBubbleText.setHideBadge(true); 76 mIconView = findViewById(R.id.icon); 77 tryUpdateTextBackground(); 78 } 79 80 @Override setBackground(Drawable background)81 public void setBackground(Drawable background) { 82 super.setBackground(background); 83 tryUpdateTextBackground(); 84 } 85 86 @Override setBackgroundResource(int resid)87 public void setBackgroundResource(int resid) { 88 super.setBackgroundResource(resid); 89 tryUpdateTextBackground(); 90 } 91 92 /** 93 * Updates the text background to match the shape of this background (when applicable). 94 */ tryUpdateTextBackground()95 private void tryUpdateTextBackground() { 96 if (!(getBackground() instanceof GradientDrawable) || mBubbleText == null) { 97 return; 98 } 99 GradientDrawable background = (GradientDrawable) getBackground(); 100 101 int color = Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight); 102 GradientDrawable backgroundMask = new GradientDrawable(); 103 backgroundMask.setColor(color); 104 backgroundMask.setShape(GradientDrawable.RECTANGLE); 105 if (background.getCornerRadii() != null) { 106 backgroundMask.setCornerRadii(background.getCornerRadii()); 107 } else { 108 backgroundMask.setCornerRadius(background.getCornerRadius()); 109 } 110 111 RippleDrawable drawable = new RippleDrawable(ColorStateList.valueOf(color), 112 mTransparentDrawable, backgroundMask); 113 mBubbleText.setBackground(drawable); 114 } 115 116 @Override getBubbleText()117 public BubbleTextView getBubbleText() { 118 return mBubbleText; 119 } 120 setWillDrawIcon(boolean willDraw)121 public void setWillDrawIcon(boolean willDraw) { 122 mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE); 123 } 124 willDrawIcon()125 public boolean willDrawIcon() { 126 return mIconView.getVisibility() == View.VISIBLE; 127 } 128 129 /** 130 * Returns the position of the center of the icon relative to the container. 131 */ getIconCenter()132 public Point getIconCenter() { 133 sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2; 134 if (Utilities.isRtl(getResources())) { 135 sTempPoint.x = getMeasuredWidth() - sTempPoint.x; 136 } 137 return sTempPoint; 138 } 139 140 /** package private **/ applyShortcutInfo(WorkspaceItemInfo info, ShortcutInfo detail, PopupContainerWithArrow container)141 public void applyShortcutInfo(WorkspaceItemInfo info, ShortcutInfo detail, 142 PopupContainerWithArrow container) { 143 mInfo = info; 144 mDetail = detail; 145 mBubbleText.applyFromWorkspaceItem(info); 146 mIconView.setBackground(mBubbleText.getIcon()); 147 148 // Use the long label as long as it exists and fits. 149 CharSequence longLabel = mDetail.getLongLabel(); 150 int availableWidth = mBubbleText.getWidth() - mBubbleText.getTotalPaddingLeft() 151 - mBubbleText.getTotalPaddingRight(); 152 boolean usingLongLabel = !TextUtils.isEmpty(longLabel) 153 && mBubbleText.getPaint().measureText(longLabel.toString()) <= availableWidth; 154 mBubbleText.setText(usingLongLabel ? longLabel : mDetail.getShortLabel()); 155 156 // TODO: Add the click handler to this view directly and not the child view. 157 mBubbleText.setOnClickListener(container.getItemClickListener()); 158 mBubbleText.setOnLongClickListener(container.getItemDragHandler()); 159 mBubbleText.setOnTouchListener(container.getItemDragHandler()); 160 } 161 162 /** 163 * Returns the shortcut info that is suitable to be added on the homescreen 164 */ getFinalInfo()165 public WorkspaceItemInfo getFinalInfo() { 166 final WorkspaceItemInfo badged = new WorkspaceItemInfo(mInfo); 167 // Queue an update task on the worker thread. This ensures that the badged 168 // shortcut eventually gets its icon updated. 169 Launcher.getLauncher(getContext()).getModel() 170 .updateAndBindWorkspaceItem(badged, mDetail); 171 return badged; 172 } 173 getIconView()174 public View getIconView() { 175 return mIconView; 176 } 177 getDetail()178 public ShortcutInfo getDetail() { 179 return mDetail; 180 } 181 } 182