Merge "Animate the priority ring in the onboarding" into rvc-dev am: 675d4a78cb
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11795077 Change-Id: Id6fad7790eb0a8c70568acf4444af23a62b3f539
This commit is contained in:
@@ -3957,6 +3957,13 @@
|
||||
<java-symbol type="id" name="conversation_unread_count" />
|
||||
<java-symbol type="string" name="unread_convo_overflow" />
|
||||
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
|
||||
<java-symbol type="drawable" name="conversation_badge_background" />
|
||||
<java-symbol type="drawable" name="conversation_badge_ring" />
|
||||
<java-symbol type="color" name="conversation_important_highlight" />
|
||||
<java-symbol type="dimen" name="importance_ring_stroke_width" />
|
||||
<java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" />
|
||||
<java-symbol type="dimen" name="importance_ring_size" />
|
||||
<java-symbol type="dimen" name="conversation_icon_size_badged" />
|
||||
|
||||
<!-- Intent resolver and share sheet -->
|
||||
<java-symbol type="string" name="resolver_personal_tab" />
|
||||
|
||||
@@ -86,7 +86,7 @@ public class ConversationIconFactory extends BaseIconFactory {
|
||||
/**
|
||||
* Returns the conversation info drawable
|
||||
*/
|
||||
private Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
|
||||
public Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
|
||||
return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class ConversationIconFactory extends BaseIconFactory {
|
||||
* Get the {@link Drawable} that represents the app icon, badged with the work profile icon
|
||||
* if appropriate.
|
||||
*/
|
||||
private Drawable getAppBadge(String packageName, int userId) {
|
||||
public Drawable getAppBadge(String packageName, int userId) {
|
||||
Drawable badge = null;
|
||||
try {
|
||||
final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
|
||||
|
||||
@@ -38,11 +38,61 @@
|
||||
android:background="@drawable/rounded_bg_full"
|
||||
>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:padding="12dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
>
|
||||
|
||||
<!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
|
||||
<ImageView
|
||||
android:id="@+id/conversation_icon"
|
||||
android:layout_width="@dimen/notification_guts_conversation_icon_size"
|
||||
android:layout_height="@dimen/notification_guts_conversation_icon_size"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
android:layout_width="@*android:dimen/conversation_avatar_size"
|
||||
android:layout_height="@*android:dimen/conversation_avatar_size"
|
||||
android:scaleType="centerCrop"
|
||||
android:importantForAccessibility="no"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_icon_badge"
|
||||
android:layout_width="@*android:dimen/conversation_icon_size_badged"
|
||||
android:layout_height="@*android:dimen/conversation_icon_size_badged"
|
||||
android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin"
|
||||
android:layout_marginTop="@*android:dimen/conversation_badge_side_margin"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
<ImageView
|
||||
android:id="@+id/conversation_icon_badge_bg"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:src="@*android:drawable/conversation_badge_background"
|
||||
android:forceHasOverlappingRendering="false"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp"
|
||||
android:layout_gravity="center"
|
||||
android:forceHasOverlappingRendering="false"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/conversation_icon_badge_ring"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@*android:drawable/conversation_badge_ring"
|
||||
android:forceHasOverlappingRendering="false"
|
||||
android:clipToPadding="false"
|
||||
android:scaleType="center"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
|
||||
@@ -124,7 +124,7 @@ public final class Prefs {
|
||||
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
|
||||
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
|
||||
/** Tracks whether the user has seen the onboarding screen for priority conversations */
|
||||
String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding";
|
||||
String HAS_SEEN_PRIORITY_ONBOARDING = "HasUserSeenPriorityOnboarding";
|
||||
}
|
||||
|
||||
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
@@ -540,7 +541,9 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
.setView(onboardingView)
|
||||
.setIgnoresDnd(ignoreDnd)
|
||||
.setShowsAsBubble(showAsBubble)
|
||||
.setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable())
|
||||
.setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo))
|
||||
.setBadge(mIconFactory.getAppBadge(
|
||||
mPackageName, UserHandle.getUserId(mSbn.getUid())))
|
||||
.setOnSettingsClick(mOnConversationSettingsClickListener)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -16,41 +16,57 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.row
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.BulletSpan
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.view.Window
|
||||
import android.view.WindowInsets.Type.statusBars
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.Interpolator
|
||||
import android.view.animation.PathInterpolator
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN
|
||||
import com.android.systemui.Prefs
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* Controller to handle presenting the priority conversations onboarding dialog
|
||||
*/
|
||||
class PriorityOnboardingDialogController @Inject constructor(
|
||||
val view: View,
|
||||
val context: Context,
|
||||
val ignoresDnd: Boolean,
|
||||
val showsAsBubble: Boolean,
|
||||
val icon : Drawable,
|
||||
val onConversationSettingsClickListener : OnConversationSettingsClickListener
|
||||
val view: View,
|
||||
val context: Context,
|
||||
private val ignoresDnd: Boolean,
|
||||
private val showsAsBubble: Boolean,
|
||||
val icon : Drawable,
|
||||
private val onConversationSettingsClickListener : OnConversationSettingsClickListener,
|
||||
val badge : Drawable
|
||||
) {
|
||||
|
||||
private lateinit var dialog: Dialog
|
||||
private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f)
|
||||
private val IMPORTANCE_ANIM_DELAY = 150L
|
||||
private val IMPORTANCE_ANIM_GROW_DURATION = 250L
|
||||
private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L
|
||||
private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L
|
||||
|
||||
fun init() {
|
||||
initDialog()
|
||||
@@ -81,6 +97,7 @@ class PriorityOnboardingDialogController @Inject constructor(
|
||||
private lateinit var icon: Drawable
|
||||
private lateinit var onConversationSettingsClickListener
|
||||
: OnConversationSettingsClickListener
|
||||
private lateinit var badge : Drawable
|
||||
|
||||
fun setView(v: View): Builder {
|
||||
view = v
|
||||
@@ -106,6 +123,10 @@ class PriorityOnboardingDialogController @Inject constructor(
|
||||
icon = draw
|
||||
return this
|
||||
}
|
||||
fun setBadge(badge : Drawable) : Builder {
|
||||
this.badge = badge
|
||||
return this
|
||||
}
|
||||
|
||||
fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
|
||||
onConversationSettingsClickListener = onClick
|
||||
@@ -115,7 +136,7 @@ class PriorityOnboardingDialogController @Inject constructor(
|
||||
fun build(): PriorityOnboardingDialogController {
|
||||
val controller = PriorityOnboardingDialogController(
|
||||
view, context, ignoresDnd, showAsBubble, icon,
|
||||
onConversationSettingsClickListener)
|
||||
onConversationSettingsClickListener, badge)
|
||||
return controller
|
||||
}
|
||||
}
|
||||
@@ -143,6 +164,65 @@ class PriorityOnboardingDialogController @Inject constructor(
|
||||
}
|
||||
|
||||
findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
|
||||
findViewById<ImageView>(R.id.icon)?.setImageDrawable(badge)
|
||||
val mImportanceRingView = findViewById<ImageView>(R.id.conversation_icon_badge_ring)
|
||||
val conversationIconBadgeBg = findViewById<ImageView>(R.id.conversation_icon_badge_bg)
|
||||
|
||||
val ring: GradientDrawable = mImportanceRingView.drawable as GradientDrawable
|
||||
ring.mutate()
|
||||
val bg = conversationIconBadgeBg.drawable as GradientDrawable
|
||||
bg.mutate()
|
||||
val ringColor = context.getResources()
|
||||
.getColor(com.android.internal.R.color.conversation_important_highlight)
|
||||
val standardThickness = context.resources.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.importance_ring_stroke_width)
|
||||
val largeThickness = context.resources.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.importance_ring_anim_max_stroke_width)
|
||||
val standardSize = context.resources.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.importance_ring_size)
|
||||
val baseSize = standardSize - standardThickness * 2
|
||||
val largeSize = baseSize + largeThickness * 2
|
||||
val bgSize = context.resources.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.conversation_icon_size_badged)
|
||||
|
||||
val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener
|
||||
= ValueAnimator.AnimatorUpdateListener { animation ->
|
||||
val strokeWidth = animation.animatedValue as Int
|
||||
ring.setStroke(strokeWidth, ringColor)
|
||||
val newSize = baseSize + strokeWidth * 2
|
||||
ring.setSize(newSize, newSize)
|
||||
mImportanceRingView.invalidate()
|
||||
}
|
||||
|
||||
val growAnimation: ValueAnimator = ValueAnimator.ofInt(0, largeThickness)
|
||||
growAnimation.interpolator = LINEAR_OUT_SLOW_IN
|
||||
growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION
|
||||
growAnimation.addUpdateListener(animatorUpdateListener)
|
||||
|
||||
val shrinkAnimation: ValueAnimator
|
||||
= ValueAnimator.ofInt(largeThickness, standardThickness)
|
||||
shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION
|
||||
shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY
|
||||
shrinkAnimation.interpolator = OVERSHOOT
|
||||
shrinkAnimation.addUpdateListener(animatorUpdateListener)
|
||||
shrinkAnimation.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator?) {
|
||||
// Shrink the badge bg so that it doesn't peek behind the animation
|
||||
bg.setSize(baseSize, baseSize);
|
||||
conversationIconBadgeBg.invalidate();
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
// Reset bg back to normal size
|
||||
bg.setSize(bgSize, bgSize);
|
||||
conversationIconBadgeBg.invalidate();
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
val anims = AnimatorSet()
|
||||
anims.startDelay = IMPORTANCE_ANIM_DELAY
|
||||
anims.playSequentially(growAnimation, shrinkAnimation)
|
||||
|
||||
val gapWidth = dialog.context.getResources().getDimensionPixelSize(
|
||||
R.dimen.conversation_onboarding_bullet_gap_width)
|
||||
@@ -180,6 +260,7 @@ class PriorityOnboardingDialogController @Inject constructor(
|
||||
height = WRAP_CONTENT
|
||||
}
|
||||
}
|
||||
anims.start()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user