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 mIconView = findViewById(R.id.icon); 76 tryUpdateTextBackground(); 77 } 78 79 @Override setBackground(Drawable background)80 public void setBackground(Drawable background) { 81 super.setBackground(background); 82 tryUpdateTextBackground(); 83 } 84 85 @Override setBackgroundResource(int resid)86 public void setBackgroundResource(int resid) { 87 super.setBackgroundResource(resid); 88 tryUpdateTextBackground(); 89 } 90 91 /** 92 * Updates the text background to match the shape of this background (when applicable). 93 */ tryUpdateTextBackground()94 private void tryUpdateTextBackground() { 95 if (!(getBackground() instanceof GradientDrawable) || mBubbleText == null) { 96 return; 97 } 98 GradientDrawable background = (GradientDrawable) getBackground(); 99 100 int color = Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight); 101 GradientDrawable backgroundMask = new GradientDrawable(); 102 backgroundMask.setColor(color); 103 backgroundMask.setShape(GradientDrawable.RECTANGLE); 104 if (background.getCornerRadii() != null) { 105 backgroundMask.setCornerRadii(background.getCornerRadii()); 106 } else { 107 backgroundMask.setCornerRadius(background.getCornerRadius()); 108 } 109 110 RippleDrawable drawable = new RippleDrawable(ColorStateList.valueOf(color), 111 mTransparentDrawable, backgroundMask); 112 mBubbleText.setBackground(drawable); 113 } 114 115 @Override getBubbleText()116 public BubbleTextView getBubbleText() { 117 return mBubbleText; 118 } 119 setWillDrawIcon(boolean willDraw)120 public void setWillDrawIcon(boolean willDraw) { 121 mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE); 122 } 123 willDrawIcon()124 public boolean willDrawIcon() { 125 return mIconView.getVisibility() == View.VISIBLE; 126 } 127 128 /** 129 * Returns the position of the center of the icon relative to the container. 130 */ getIconCenter()131 public Point getIconCenter() { 132 sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2; 133 if (Utilities.isRtl(getResources())) { 134 sTempPoint.x = getMeasuredWidth() - sTempPoint.x; 135 } 136 return sTempPoint; 137 } 138 139 /** package private **/ applyShortcutInfo(WorkspaceItemInfo info, ShortcutInfo detail, PopupContainerWithArrow container)140 public void applyShortcutInfo(WorkspaceItemInfo info, ShortcutInfo detail, 141 PopupContainerWithArrow container) { 142 mInfo = info; 143 mDetail = detail; 144 mBubbleText.applyFromWorkspaceItem(info); 145 mIconView.setBackground(mBubbleText.getIcon()); 146 147 // Use the long label as long as it exists and fits. 148 CharSequence longLabel = mDetail.getLongLabel(); 149 int availableWidth = mBubbleText.getWidth() - mBubbleText.getTotalPaddingLeft() 150 - mBubbleText.getTotalPaddingRight(); 151 boolean usingLongLabel = !TextUtils.isEmpty(longLabel) 152 && mBubbleText.getPaint().measureText(longLabel.toString()) <= availableWidth; 153 mBubbleText.setText(usingLongLabel ? longLabel : mDetail.getShortLabel()); 154 155 // TODO: Add the click handler to this view directly and not the child view. 156 mBubbleText.setOnClickListener(container.getItemClickListener()); 157 mBubbleText.setOnLongClickListener(container.getItemDragHandler()); 158 mBubbleText.setOnTouchListener(container.getItemDragHandler()); 159 } 160 161 /** 162 * Returns the shortcut info that is suitable to be added on the homescreen 163 */ getFinalInfo()164 public WorkspaceItemInfo getFinalInfo() { 165 final WorkspaceItemInfo badged = new WorkspaceItemInfo(mInfo); 166 // Queue an update task on the worker thread. This ensures that the badged 167 // shortcut eventually gets its icon updated. 168 Launcher.getLauncher(getContext()).getModel() 169 .updateAndBindWorkspaceItem(badged, mDetail); 170 return badged; 171 } 172 getIconView()173 public View getIconView() { 174 return mIconView; 175 } 176 getDetail()177 public ShortcutInfo getDetail() { 178 return mDetail; 179 } 180 } 181