List of usage examples for android.text TextUtils ellipsize
public static CharSequence ellipsize(CharSequence text, TextPaint p, float avail, TruncateAt where)
From source file:au.com.zacher.popularmovies.activity.layout.CollapsingTitleLayout.java
private void setInterpolatedTextSize(final float textSize) { if (this.mTitle == null) { return;/*from w w w .j a va 2s . c o m*/ } if (isClose(textSize, this.mCollapsedTitleTextSize) || isClose(textSize, this.mExpandedTitleTextSize) || this.mTitleToDraw == null) { // If the text size is 'close' to being a decimal, then we use this as a sync-point. // We disable our manual scaling and set the paint's text size. this.mTextPaint.setTextSize(textSize); this.mScale = 1f; // We also use this as an opportunity to ellipsize the string final CharSequence title = TextUtils.ellipsize(this.mTitle, this.mTextPaint, this.mTextRight - this.mTextLeft, TextUtils.TruncateAt.END); if (title != this.mTitleToDraw) { // If the title has changed, turn it into a string this.mTitleToDraw = title.toString(); } if (USE_SCALING_TEXTURE && isClose(textSize, this.mExpandedTitleTextSize)) { this.ensureExpandedTexture(); } this.mUseTexture = false; } else { // We're not close to a decimal so use our canvas scaling method if (this.mExpandedTitleTexture != null) { this.mScale = textSize / this.mExpandedTitleTextSize; } else { this.mScale = textSize / this.mTextPaint.getTextSize(); } this.mUseTexture = USE_SCALING_TEXTURE; } ViewCompat.postInvalidateOnAnimation(this); }
From source file:com.lamcreations.scaffold.common.utils.CollapsingTextHelper.java
private void setInterpolatedTextSize(float textSize) { if (this.mText != null) { boolean updateDrawText = false; float availableWidth; float newTextSize; if (isClose(textSize, this.mCollapsedTextSize)) { availableWidth = (float) this.mCollapsedBounds.width(); newTextSize = this.mCollapsedTextSize; this.mScale = 1.0F; } else {/*from w w w . j a v a 2 s . com*/ availableWidth = (float) this.mExpandedBounds.width(); newTextSize = this.mExpandedTextSize; if (isClose(textSize, this.mExpandedTextSize)) { this.mScale = 1.0F; } else { this.mScale = textSize / this.mExpandedTextSize; } } if (availableWidth > 0.0F) { updateDrawText = this.mCurrentTextSize != newTextSize; this.mCurrentTextSize = newTextSize; } if (this.mTextToDraw == null || updateDrawText) { this.mTextPaint.setTextSize(this.mCurrentTextSize); CharSequence title = TextUtils.ellipsize(this.mText, this.mTextPaint, availableWidth, TextUtils.TruncateAt.END); if (this.mTextToDraw == null || !this.mTextToDraw.equals(title)) { this.mTextToDraw = title; } this.mIsRtl = this.calculateIsRtl(this.mTextToDraw); this.mTextWidth = this.mTextPaint.measureText(this.mTextToDraw, 0, this.mTextToDraw.length()); } this.mUseTexture = USE_SCALING_TEXTURE && this.mScale != 1.0F; if (this.mUseTexture) { this.ensureExpandedTexture(); } ViewCompat.postInvalidateOnAnimation(this.mView); } }
From source file:org.wikipedia.page.shareafact.SnippetImage.java
/** * If the title or text is too long we first reduce the font size. * If that is not enough it gets ellipsized. */// w w w . j a va 2 s. com private static StaticLayout optimizeTextSize(TextLayoutParams params, int maxHeight, int maxLines, float maxFontSize, float minFontSize) { final float threshold1 = 60.0f; final float threshold2 = 40.0f; final float extraStep1 = 3.0f; final float extraStep2 = 1.0f; boolean fits = false; StaticLayout textLayout = null; // Try decreasing font size first for (float fontSize = maxFontSize; fontSize >= minFontSize; fontSize -= 1.0f) { params.textPaint.setTextSize(fontSize); textLayout = buildLayout(params); if (textLayout.getHeight() <= maxHeight) { fits = true; break; } // make it go faster at the beginning... if (fontSize > threshold1) { fontSize -= extraStep1; } else if (fontSize > threshold2) { fontSize -= extraStep2; } } // Then do own ellipsize: cut text off after last fitting space and add "..." // Didn't want to cut off randomly in the middle of a line or word. if (!fits) { final String textStr = params.text.toString(); final int ellipsisLength = 3; final int ellipsisStart = textLayout != null ? textLayout.getLineStart(maxLines) - ellipsisLength : textStr.length(); final int end = textStr.lastIndexOf(' ', ellipsisStart) + 1; if (end > 0) { textLayout = buildLayout(new TextLayoutParams(params, textStr.substring(0, end) + "...")); if (textLayout.getLineCount() <= maxLines) { fits = true; } } } // last resort: use TextUtils.ellipsize() if (!fits) { final float textRatio = .87f; final float maxWidth = textRatio * maxLines * params.lineWidth; textLayout = buildLayout(new TextLayoutParams(params, TextUtils.ellipsize(params.text, params.textPaint, maxWidth, TextUtils.TruncateAt.END))); } return textLayout; }
From source file:org.telegram.ui.Cells.ProfileSearchCell.java
public void buildLayout() { CharSequence nameString;//from w ww. jav a 2 s .co m TextPaint currentNamePaint; drawNameBroadcast = false; drawNameLock = false; drawNameGroup = false; drawCheck = false; drawNameBot = false; if (encryptedChat != null) { drawNameLock = true; dialog_id = ((long) encryptedChat.id) << 32; if (!LocaleController.isRTL) { nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + lockDrawable.getIntrinsicWidth(); } else { nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline + 2) - lockDrawable.getIntrinsicWidth(); nameLeft = AndroidUtilities.dp(11); } nameLockTop = AndroidUtilities.dp(16.5f); } else { if (chat != null) { if (chat.id < 0) { dialog_id = AndroidUtilities.makeBroadcastId(chat.id); drawNameBroadcast = true; nameLockTop = AndroidUtilities.dp(28.5f); } else { dialog_id = -chat.id; if (ChatObject.isChannel(chat) && !chat.megagroup) { drawNameBroadcast = true; nameLockTop = AndroidUtilities.dp(28.5f); } else { drawNameGroup = true; nameLockTop = AndroidUtilities.dp(30); } } drawCheck = chat.verified; if (!LocaleController.isRTL) { nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + (drawNameGroup ? groupDrawable.getIntrinsicWidth() : broadcastDrawable.getIntrinsicWidth()); } else { nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline + 2) - (drawNameGroup ? groupDrawable.getIntrinsicWidth() : broadcastDrawable.getIntrinsicWidth()); nameLeft = AndroidUtilities.dp(11); } } else { dialog_id = user.id; if (!LocaleController.isRTL) { nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); } else { nameLeft = AndroidUtilities.dp(11); } if (user.bot) { drawNameBot = true; if (!LocaleController.isRTL) { nameLockLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline + 4) + botDrawable.getIntrinsicWidth(); } else { nameLockLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline + 2) - botDrawable.getIntrinsicWidth(); nameLeft = AndroidUtilities.dp(11); } nameLockTop = AndroidUtilities.dp(16.5f); } else { nameLockTop = AndroidUtilities.dp(17); } drawCheck = user.verified; } } if (currentName != null) { nameString = currentName; } else { String nameString2 = ""; if (chat != null) { nameString2 = chat.title; } else if (user != null) { nameString2 = UserObject.getUserName(user); } nameString = nameString2.replace('\n', ' '); } if (nameString.length() == 0) { if (user != null && user.phone != null && user.phone.length() != 0) { nameString = PhoneFormat.getInstance().format("+" + user.phone); } else { nameString = LocaleController.getString("HiddenName", R.string.HiddenName); } } if (encryptedChat != null) { currentNamePaint = nameEncryptedPaint; } else { currentNamePaint = namePaint; } int onlineWidth; int nameWidth; if (!LocaleController.isRTL) { onlineWidth = nameWidth = getMeasuredWidth() - nameLeft - AndroidUtilities.dp(14); } else { onlineWidth = nameWidth = getMeasuredWidth() - nameLeft - AndroidUtilities.dp(AndroidUtilities.leftBaseline); } if (drawNameLock) { nameWidth -= AndroidUtilities.dp(6) + lockDrawable.getIntrinsicWidth(); } else if (drawNameBroadcast) { nameWidth -= AndroidUtilities.dp(6) + broadcastDrawable.getIntrinsicWidth(); } else if (drawNameGroup) { nameWidth -= AndroidUtilities.dp(6) + groupDrawable.getIntrinsicWidth(); } else if (drawNameBot) { nameWidth -= AndroidUtilities.dp(6) + botDrawable.getIntrinsicWidth(); } if (drawCount) { TLRPC.TL_dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id); if (dialog != null && dialog.unread_count != 0) { lastUnreadCount = dialog.unread_count; String countString = String.format("%d", dialog.unread_count); countWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(countPaint.measureText(countString))); countLayout = new StaticLayout(countString, countPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); int w = countWidth + AndroidUtilities.dp(18); nameWidth -= w; if (!LocaleController.isRTL) { countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(19); } else { countLeft = AndroidUtilities.dp(19); nameLeft += w; } } else { lastUnreadCount = 0; countLayout = null; } } else { lastUnreadCount = 0; countLayout = null; } CharSequence nameStringFinal = TextUtils.ellipsize(nameString, currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (chat == null || subLabel != null) { if (!LocaleController.isRTL) { onlineLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); } else { onlineLeft = AndroidUtilities.dp(11); } CharSequence onlineString = ""; TextPaint currentOnlinePaint = offlinePaint; if (subLabel != null) { onlineString = subLabel; } else if (user != null) { if (user.bot) { onlineString = LocaleController.getString("Bot", R.string.Bot); } else { onlineString = LocaleController.formatUserStatus(user); if (user != null && (user.id == UserConfig.getClientUserId() || user.status != null && user.status.expires > ConnectionsManager.getInstance().getCurrentTime())) { currentOnlinePaint = onlinePaint; onlineString = LocaleController.getString("Online", R.string.Online); } } } CharSequence onlineStringFinal = TextUtils.ellipsize(onlineString, currentOnlinePaint, onlineWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); onlineLayout = new StaticLayout(onlineStringFinal, currentOnlinePaint, onlineWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); nameTop = AndroidUtilities.dp(13); if (subLabel != null && chat != null) { nameLockTop -= AndroidUtilities.dp(12); } } else { onlineLayout = null; nameTop = AndroidUtilities.dp(25); } int avatarLeft; if (!LocaleController.isRTL) { avatarLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 13 : 9); } else { avatarLeft = getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.isTablet() ? 65 : 61); } avatarImage.setImageCoords(avatarLeft, AndroidUtilities.dp(10), AndroidUtilities.dp(52), AndroidUtilities.dp(52)); double widthpx; float left; if (LocaleController.isRTL) { if (nameLayout.getLineCount() > 0) { left = nameLayout.getLineLeft(0); if (left == 0) { widthpx = Math.ceil(nameLayout.getLineWidth(0)); if (widthpx < nameWidth) { nameLeft += (nameWidth - widthpx); } } } if (onlineLayout != null && onlineLayout.getLineCount() > 0) { left = onlineLayout.getLineLeft(0); if (left == 0) { widthpx = Math.ceil(onlineLayout.getLineWidth(0)); if (widthpx < onlineWidth) { onlineLeft += (onlineWidth - widthpx); } } } } else { if (nameLayout.getLineCount() > 0) { left = nameLayout.getLineRight(0); if (left == nameWidth) { widthpx = Math.ceil(nameLayout.getLineWidth(0)); if (widthpx < nameWidth) { nameLeft -= (nameWidth - widthpx); } } } if (onlineLayout != null && onlineLayout.getLineCount() > 0) { left = onlineLayout.getLineRight(0); if (left == onlineWidth) { widthpx = Math.ceil(onlineLayout.getLineWidth(0)); if (widthpx < onlineWidth) { onlineLeft -= (onlineWidth - widthpx); } } } } }
From source file:org.cocos2dx.lib.Cocos2dxBitmap.java
private static String getStringWithEllipsis(String originalText, float width, float fontSize) { if (TextUtils.isEmpty(originalText)) { return ""; }/*from w w w.j a v a2s. com*/ TextPaint paint = new TextPaint(); paint.setTypeface(Typeface.DEFAULT); paint.setTextSize(fontSize); return TextUtils.ellipsize(originalText, paint, width, TextUtils.TruncateAt.valueOf("END")).toString(); }
From source file:xyz.berial.textinputlayout.CollapsingTextHelper.java
private void setInterpolatedTextSize(final float textSize) { if (mText == null) return;/* w w w . ja v a2s .c o m*/ final float availableWidth; final float newTextSize; boolean updateDrawText = false; if (isClose(textSize, mCollapsedTextSize)) { availableWidth = mCollapsedBounds.width(); newTextSize = mCollapsedTextSize; mScale = 1f; } else { availableWidth = mExpandedBounds.width(); newTextSize = mExpandedTextSize; if (isClose(textSize, mExpandedTextSize)) { // If we're close to the expanded text size, snap to it and use a scale of 1 mScale = 1f; } else { // Else, we'll scale down from the expanded text size mScale = textSize / mExpandedTextSize; } } if (availableWidth > 0) { updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged; mCurrentTextSize = newTextSize; mBoundsChanged = false; } if (mTextToDraw == null || updateDrawText) { mTextPaint.setTextSize(mCurrentTextSize); // If we don't currently have text to draw, or the text size has changed, ellipsize... final CharSequence title = TextUtils.ellipsize(mText, mTextPaint, availableWidth, TextUtils.TruncateAt.END); if (mTextToDraw == null || !mTextToDraw.equals(title)) { mTextToDraw = title; } mIsRtl = calculateIsRtl(mTextToDraw); } // Use our texture if the scale isn't 1.0 mUseTexture = USE_SCALING_TEXTURE && mScale != 1f; if (mUseTexture) { // Make sure we have an expanded texture if needed ensureExpandedTexture(); } ViewCompat.postInvalidateOnAnimation(mView); }
From source file:com.silentcircle.contacts.list.ShortcutIntentBuilder.java
/** * Generates a phone number shortcut icon. Adds an overlay describing the type of the phone * number, and if there is a photo also adds the call action icon. *///from w w w. j a va 2s . c o m private Bitmap generatePhoneNumberIcon(Drawable photo, int phoneType, String phoneLabel, int actionResId) { final Resources r = mContext.getResources(); final float density = r.getDisplayMetrics().density; Bitmap phoneIcon = ((BitmapDrawable) r.getDrawableForDensity(actionResId, mIconDensity)).getBitmap(); Bitmap icon = generateQuickContactIcon(photo); Canvas canvas = new Canvas(icon); // Copy in the photo Paint photoPaint = new Paint(); photoPaint.setDither(true); photoPaint.setFilterBitmap(true); Rect dst = new Rect(0, 0, mIconSize, mIconSize); // Create an overlay for the phone number type CharSequence overlay = Phone.getTypeLabel(r, phoneType, phoneLabel); if (overlay != null) { TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); textPaint.setTextSize(r.getDimension(R.dimen.shortcut_overlay_text_size)); textPaint.setColor(ContextCompat.getColor(mContext, R.color.textColorIconOverlay)); textPaint.setShadowLayer(4f, 0, 2f, ContextCompat.getColor(mContext, R.color.textColorIconOverlayShadow)); final FontMetricsInt fmi = textPaint.getFontMetricsInt(); // First fill in a darker background around the text to be drawn final Paint workPaint = new Paint(); workPaint.setColor(mOverlayTextBackgroundColor); workPaint.setStyle(Paint.Style.FILL); final int textPadding = r.getDimensionPixelOffset(R.dimen.shortcut_overlay_text_background_padding); final int textBandHeight = (fmi.descent - fmi.ascent) + textPadding * 2; dst.set(0, mIconSize - textBandHeight, mIconSize, mIconSize); canvas.drawRect(dst, workPaint); overlay = TextUtils.ellipsize(overlay, textPaint, mIconSize, TruncateAt.END); final float textWidth = textPaint.measureText(overlay, 0, overlay.length()); canvas.drawText(overlay, 0, overlay.length(), (mIconSize - textWidth) / 2, mIconSize - fmi.descent - textPadding, textPaint); } // Draw the phone action icon as an overlay Rect src = new Rect(0, 0, phoneIcon.getWidth(), phoneIcon.getHeight()); int iconWidth = icon.getWidth(); dst.set(iconWidth - ((int) (20 * density)), -1, iconWidth, ((int) (19 * density))); canvas.drawBitmap(phoneIcon, src, dst, photoPaint); canvas.setBitmap(null); return icon; }
From source file:com.android.contacts.common.list.ShortcutIntentBuilder.java
/** * Generates a phone number shortcut icon. Adds an overlay describing the type of the phone * number, and if there is a photo also adds the call action icon. *//*from ww w. ja va2 s . com*/ private Bitmap generatePhoneNumberIcon(Drawable photo, int phoneType, String phoneLabel, int actionResId) { final Resources r = mContext.getResources(); final float density = r.getDisplayMetrics().density; Bitmap phoneIcon = ((BitmapDrawable) r.getDrawableForDensity(actionResId, mIconDensity)).getBitmap(); Bitmap icon = generateQuickContactIcon(photo); Canvas canvas = new Canvas(icon); // Copy in the photo Paint photoPaint = new Paint(); photoPaint.setDither(true); photoPaint.setFilterBitmap(true); Rect dst = new Rect(0, 0, mIconSize, mIconSize); // Create an overlay for the phone number type CharSequence overlay = Phone.getTypeLabel(r, phoneType, phoneLabel); if (overlay != null) { TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); textPaint.setTextSize(r.getDimension(R.dimen.shortcut_overlay_text_size)); textPaint.setColor(r.getColor(R.color.textColorIconOverlay)); textPaint.setShadowLayer(4f, 0, 2f, r.getColor(R.color.textColorIconOverlayShadow)); final FontMetricsInt fmi = textPaint.getFontMetricsInt(); // First fill in a darker background around the text to be drawn final Paint workPaint = new Paint(); workPaint.setColor(mOverlayTextBackgroundColor); workPaint.setStyle(Paint.Style.FILL); final int textPadding = r.getDimensionPixelOffset(R.dimen.shortcut_overlay_text_background_padding); final int textBandHeight = (fmi.descent - fmi.ascent) + textPadding * 2; dst.set(0, mIconSize - textBandHeight, mIconSize, mIconSize); canvas.drawRect(dst, workPaint); overlay = TextUtils.ellipsize(overlay, textPaint, mIconSize, TruncateAt.END); final float textWidth = textPaint.measureText(overlay, 0, overlay.length()); canvas.drawText(overlay, 0, overlay.length(), (mIconSize - textWidth) / 2, mIconSize - fmi.descent - textPadding, textPaint); } // Draw the phone action icon as an overlay Rect src = new Rect(0, 0, phoneIcon.getWidth(), phoneIcon.getHeight()); int iconWidth = icon.getWidth(); dst.set(iconWidth - ((int) (20 * density)), -1, iconWidth, ((int) (19 * density))); canvas.drawBitmap(phoneIcon, src, dst, photoPaint); canvas.setBitmap(null); return icon; }
From source file:com.amitupadhyay.aboutexample.util.CollapsingTextHelper.java
private void setInterpolatedTextSize(final float textSize) { if (mText == null) return;/* w w w .java2 s. c o m*/ final float availableWidth; final float newTextSize; boolean updateDrawText = false; if (isClose(textSize, mCollapsedTextSize)) { availableWidth = mCollapsedBounds.width(); newTextSize = mCollapsedTextSize; mScale = 1f; } else { availableWidth = mExpandedBounds.width(); newTextSize = mExpandedTextSize; if (isClose(textSize, mExpandedTextSize)) { // If we're close to the expanded text size, snap to it and use a scale of 1 mScale = 1f; } else { // Else, we'll scale down from the expanded text size mScale = textSize / mExpandedTextSize; } } if (availableWidth > 0) { updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged; mCurrentTextSize = newTextSize; mBoundsChanged = false; } if (mTextToDraw == null || updateDrawText) { mTextPaint.setTextSize(mCurrentTextSize); // If we don't currently have text to draw, or the text size has changed, ellipsize... final CharSequence title = TextUtils.ellipsize(mText, mTextPaint, availableWidth, TextUtils.TruncateAt.END); if (mTextToDraw == null || !mTextToDraw.equals(title)) { mTextToDraw = title; } mIsRtl = calculateIsRtl(mTextToDraw); } // Use our texture if the scale isn't 1.0 mUseTexture = USE_SCALING_TEXTURE && mScale != 1f; if (mUseTexture) { // Make sure we have an expanded texture if needed ensureExpandedTexture(); } ViewCompat.postInvalidateOnAnimation(mView); }
From source file:com.android.contacts.ShortcutIntentBuilder.java
/** * Generates a phone number shortcut icon. Adds an overlay describing the type of the phone * number, and if there is a photo also adds the call action icon. *//*from w ww . j av a 2 s .c o m*/ private Bitmap generatePhoneNumberIcon(Drawable photo, int phoneType, String phoneLabel, int actionResId) { final Resources r = mContext.getResources(); final float density = r.getDisplayMetrics().density; final Drawable phoneDrawable = r.getDrawableForDensity(actionResId, mIconDensity); // These icons have the same height and width so either is fine for the size. final Bitmap phoneIcon = BitmapUtil.drawableToBitmap(phoneDrawable, phoneDrawable.getIntrinsicHeight()); Bitmap icon = generateQuickContactIcon(photo); Canvas canvas = new Canvas(icon); // Copy in the photo Paint photoPaint = new Paint(); photoPaint.setDither(true); photoPaint.setFilterBitmap(true); Rect dst = new Rect(0, 0, mIconSize, mIconSize); // Create an overlay for the phone number type if we're pre-O. O created shortcuts have the // app badge which overlaps the type overlay. CharSequence overlay = Phone.getTypeLabel(r, phoneType, phoneLabel); if (!BuildCompat.isAtLeastO() && overlay != null) { TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); textPaint.setTextSize(r.getDimension(R.dimen.shortcut_overlay_text_size)); textPaint.setColor(r.getColor(R.color.textColorIconOverlay)); textPaint.setShadowLayer(4f, 0, 2f, r.getColor(R.color.textColorIconOverlayShadow)); final FontMetricsInt fmi = textPaint.getFontMetricsInt(); // First fill in a darker background around the text to be drawn final Paint workPaint = new Paint(); workPaint.setColor(mOverlayTextBackgroundColor); workPaint.setStyle(Paint.Style.FILL); final int textPadding = r.getDimensionPixelOffset(R.dimen.shortcut_overlay_text_background_padding); final int textBandHeight = (fmi.descent - fmi.ascent) + textPadding * 2; dst.set(0, mIconSize - textBandHeight, mIconSize, mIconSize); canvas.drawRect(dst, workPaint); overlay = TextUtils.ellipsize(overlay, textPaint, mIconSize, TruncateAt.END); final float textWidth = textPaint.measureText(overlay, 0, overlay.length()); canvas.drawText(overlay, 0, overlay.length(), (mIconSize - textWidth) / 2, mIconSize - fmi.descent - textPadding, textPaint); } // Draw the phone action icon as an overlay int iconWidth = icon.getWidth(); if (BuildCompat.isAtLeastO()) { // On O we need to calculate where the phone icon goes slightly differently. The whole // canvas area is 108dp, a centered circle with a diameter of 66dp is the "safe zone". // So we start the drawing the phone icon at // 108dp - 21 dp (distance from right edge of safe zone to the edge of the canvas) // - 24 dp (size of the phone icon) on the x axis (left) // The y axis is simply 21dp for the distance to the safe zone (top). // See go/o-icons-eng for more details and a handy picture. final int left = (int) (mIconSize - (45 * density)); final int top = (int) (21 * density); canvas.drawBitmap(phoneIcon, left, top, photoPaint); } else { dst.set(iconWidth - ((int) (20 * density)), -1, iconWidth, ((int) (19 * density))); canvas.drawBitmap(phoneIcon, null, dst, photoPaint); } canvas.setBitmap(null); return icon; }