Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 344731a8 authored by Mady Mellor's avatar Mady Mellor Committed by Android (Google) Code Review
Browse files

Merge "Closer to notification model & updates on bubbles"

parents c8238f4c 3f2efdbf
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
@@ -586,7 +586,7 @@ public class ContrastColorUtil {
     *
     * @param color the base color to use
     * @param amount the amount from 1 to 100 how much to modify the color
     * @return the now color that was modified
     * @return the new color that was modified
     */
    public static int getShiftedColor(int color, int amount) {
        final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
@@ -599,6 +599,19 @@ public class ContrastColorUtil {
        return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
    }

    /**
     * Blends the provided color with white to create a muted version.
     *
     * @param color the color to mute
     * @param alpha the amount from 0 to 1 to set the alpha component of the white scrim
     * @return the new color that was modified
     */
    public static int getMutedColor(int color, float alpha) {
        int whiteScrim = ColorUtilsFromCompat.setAlphaComponent(
                Color.WHITE, (int) (255 * alpha));
        return compositeColors(whiteScrim, color);
    }

    private static boolean shouldUseDark(int backgroundColor, boolean defaultBackgroundIsDark) {
        if (backgroundColor == Notification.COLOR_DEFAULT) {
            return !defaultBackgroundIsDark;
@@ -674,6 +687,18 @@ public class ContrastColorUtil {
            return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
        }

        /**
         * Set the alpha component of {@code color} to be {@code alpha}.
         */
        @ColorInt
        public static int setAlphaComponent(@ColorInt int color,
                @IntRange(from = 0x0, to = 0xFF) int alpha) {
            if (alpha < 0 || alpha > 255) {
                throw new IllegalArgumentException("alpha must be between 0 and 255.");
            }
            return (color & 0x00ffffff) | (alpha << 24);
        }

        /**
         * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
         * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
+38 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2018 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
  -->
<com.android.systemui.bubbles.BubbleView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:id="@+id/bubble_view">

    <com.android.systemui.bubbles.BadgedImageView
        android:id="@+id/bubble_image"
        android:layout_width="@dimen/bubble_size"
        android:layout_height="@dimen/bubble_size"
        android:padding="@dimen/bubble_view_padding"
        android:clipToPadding="false"/>

    <TextView
        android:id="@+id/message_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minWidth="@dimen/bubble_message_min_width"
        android:maxWidth="@dimen/bubble_message_max_width"
        android:padding="@dimen/bubble_message_padding"/>

</com.android.systemui.bubbles.BubbleView>
+12 −4
Original line number Diff line number Diff line
@@ -981,14 +981,16 @@

    <!-- How much a bubble is elevated -->
    <dimen name="bubble_elevation">8dp</dimen>
    <!-- Padding around a collapsed bubble -->
    <dimen name="bubble_view_padding">0dp</dimen>
    <!-- Padding between bubbles when displayed in expanded state -->
    <dimen name="bubble_padding">8dp</dimen>
    <!-- Padding around the view displayed when the bubble is expanded -->
    <dimen name="bubble_expanded_view_padding">8dp</dimen>
    <!-- Size of the collapsed bubble -->
    <dimen name="bubble_size">56dp</dimen>
    <!-- Size of an icon displayed within the bubble -->
    <dimen name="bubble_icon_size">24dp</dimen>
    <!-- How much to inset the icon in the circle -->
    <dimen name="bubble_icon_inset">16dp</dimen>
    <!-- Padding around the view displayed when the bubble is expanded -->
    <dimen name="bubble_expanded_view_padding">8dp</dimen>
    <!-- Default height of the expanded view shown when the bubble is expanded -->
    <dimen name="bubble_expanded_default_height">400dp</dimen>
    <!-- Height of the triangle that points to the expanded bubble -->
@@ -1001,4 +1003,10 @@
    <dimen name="bubble_expanded_header_height">48dp</dimen>
    <!-- Left and right padding applied to the header. -->
    <dimen name="bubble_expanded_header_horizontal_padding">24dp</dimen>
    <!-- Max width of the message bubble-->
    <dimen name="bubble_message_max_width">144dp</dimen>
    <!-- Min width of the message bubble -->
    <dimen name="bubble_message_min_width">32dp</dimen>
    <!-- Interior padding of the message bubble -->
    <dimen name="bubble_message_padding">4dp</dimen>
</resources>
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.systemui.bubbles;

import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;

// XXX: Mostly opied from launcher code / can we share?
/**
 * Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge).
 */
public class BadgeRenderer {

    private static final String TAG = "BadgeRenderer";

    // The badge sizes are defined as percentages of the app icon size.
    private static final float SIZE_PERCENTAGE = 0.38f;

    // Extra scale down of the dot
    private static final float DOT_SCALE = 0.6f;

    private final float mDotCenterOffset;
    private final float mCircleRadius;
    private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);

    public BadgeRenderer(int iconSizePx) {
        mDotCenterOffset = SIZE_PERCENTAGE * iconSizePx;
        int size = (int) (DOT_SCALE * mDotCenterOffset);
        mCircleRadius = size / 2f;
    }

    /**
     * Draw a circle in the top right corner of the given bounds.
     *
     * @param color The color (based on the icon) to use for the badge.
     * @param iconBounds The bounds of the icon being badged.
     * @param badgeScale The progress of the animation, from 0 to 1.
     * @param spaceForOffset How much space to offset the badge up and to the left or right.
     * @param onLeft Whether the badge should be draw on left or right side.
     */
    public void draw(Canvas canvas, int color, Rect iconBounds, float badgeScale,
            Point spaceForOffset, boolean onLeft) {
        if (iconBounds == null) {
            Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
            return;
        }
        canvas.save();
        // We draw the badge relative to its center.
        int x = onLeft ? iconBounds.left : iconBounds.right;
        float offset = onLeft ? (mDotCenterOffset / 2) : -(mDotCenterOffset / 2);
        float badgeCenterX = x + offset;
        float badgeCenterY = iconBounds.top + mDotCenterOffset / 2;

        canvas.translate(badgeCenterX + spaceForOffset.x, badgeCenterY - spaceForOffset.y);

        canvas.scale(badgeScale, badgeScale);
        mCirclePaint.setColor(color);
        canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);
        canvas.restore();
    }
}
+129 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.systemui.bubbles;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.android.systemui.R;

/**
 * View that circle crops its contents and supports displaying a coloured dot on a top corner.
 */
public class BadgedImageView extends ImageView {

    private BadgeRenderer mDotRenderer;
    private int mIconSize;
    private Rect mTempBounds = new Rect();
    private Point mTempPoint = new Point();
    private Path mClipPath = new Path();

    private float mDotScale = 0f;
    private int mUpdateDotColor;
    private boolean mShowUpdateDot;
    private boolean mOnLeft;

    public BadgedImageView(Context context) {
        this(context, null);
    }

    public BadgedImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setScaleType(ScaleType.CENTER_CROP);
        mIconSize = getResources().getDimensionPixelSize(R.dimen.bubble_size);
        mDotRenderer = new BadgeRenderer(mIconSize);
    }

    // TODO: Clipping oval path isn't great: rerender image into a separate, rounded bitmap and
    // then draw would be better
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        // Circle crop
        mClipPath.addOval(getPaddingStart(), getPaddingTop(),
                getWidth() - getPaddingEnd(), getHeight() - getPaddingBottom(), Path.Direction.CW);
        canvas.clipPath(mClipPath);
        super.onDraw(canvas);

        // After we've circle cropped what we're showing, restore so we don't clip the badge
        canvas.restore();

        // Draw the badge
        if (mShowUpdateDot) {
            getDrawingRect(mTempBounds);
            mTempPoint.set((getWidth() - mIconSize) / 2, getPaddingTop());
            mDotRenderer.draw(canvas, mUpdateDotColor, mTempBounds, mDotScale, mTempPoint,
                    mOnLeft);
        }
    }

    /**
     * Set whether the dot should appear on left or right side of the view.
     */
    public void setDotPosition(boolean onLeft) {
        mOnLeft = onLeft;
        invalidate();
    }

    /**
     * Set whether the dot should show or not.
     */
    public void setShowDot(boolean showBadge) {
        mShowUpdateDot = showBadge;
        invalidate();
    }

    /**
     * @return whether the dot is being displayed.
     */
    public boolean isShowingDot() {
        return mShowUpdateDot;
    }

    /**
     * The colour to use for the dot.
     */
    public void setDotColor(int color) {
        mUpdateDotColor = color;
        invalidate();
    }

    /**
     * How big the dot should be, fraction from 0 to 1.
     */
    public void setDotScale(float fraction) {
        mDotScale = fraction;
        invalidate();
    }

    public float getDotScale() {
        return mDotScale;
    }
}
Loading