Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt +64 −6 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,13 @@ import android.app.PendingIntent import android.app.RemoteInput import android.app.RemoteInput import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.graphics.Bitmap import android.graphics.ImageDecoder import android.graphics.drawable.AdaptiveIconDrawable import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon import android.os.Build import android.os.Build import android.os.Bundle import android.os.Bundle import android.os.SystemClock import android.os.SystemClock Loading @@ -48,7 +55,13 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplyState.SuppressedA import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies import java.util.concurrent.FutureTask import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Inject import kotlin.system.measureTimeMillis /** Returns whether we should show the smart reply view and its smart suggestions. */ /** Returns whether we should show the smart reply view and its smart suggestions. */ fun shouldShowSmartReplyView( fun shouldShowSmartReplyView( Loading Loading @@ -281,6 +294,51 @@ interface SmartActionInflater { ): Button ): Button } } private const val ICON_TASK_TIMEOUT_MS = 500L private val iconTaskThreadPool = ThreadPoolExecutor(0, 25, 1, TimeUnit.MINUTES, SynchronousQueue()) private fun loadIconDrawableWithTimeout( icon: Icon, packageContext: Context, targetSize: Int, ): Drawable? { if (icon.type != Icon.TYPE_URI && icon.type != Icon.TYPE_URI_ADAPTIVE_BITMAP) { return icon.loadDrawable(packageContext) } val bitmapTask = FutureTask { val bitmap: Bitmap? val durationMillis = measureTimeMillis { val source = ImageDecoder.createSource(packageContext.contentResolver, icon.uri) bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ -> decoder.setTargetSize(targetSize, targetSize) decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT } } if (durationMillis > ICON_TASK_TIMEOUT_MS) { Log.w(TAG, "Loading $icon took ${durationMillis / 1000f} sec") } checkNotNull(bitmap) { "ImageDecoder.decodeBitmap() returned null" } } val bitmap = runCatching { iconTaskThreadPool.execute(bitmapTask) bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS) }.getOrElse { ex -> Log.e(TAG, "Failed to load $icon: $ex") bitmapTask.cancel(true) return null } // TODO(b/288561520): rewrite Icon so that we don't need to duplicate this logic val bitmapDrawable = BitmapDrawable(packageContext.resources, bitmap) val result = if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) AdaptiveIconDrawable(null, bitmapDrawable) else bitmapDrawable if (icon.hasTint()) { result.mutate() result.setTintList(icon.tintList) result.setTintBlendMode(icon.tintBlendMode) } return result } /* internal */ class SmartActionInflaterImpl @Inject constructor( /* internal */ class SmartActionInflaterImpl @Inject constructor( private val constants: SmartReplyConstants, private val constants: SmartReplyConstants, private val activityStarter: ActivityStarter, private val activityStarter: ActivityStarter, Loading @@ -304,12 +362,12 @@ interface SmartActionInflater { // We received the Icon from the application - so use the Context of the application to // We received the Icon from the application - so use the Context of the application to // reference icon resources. // reference icon resources. val iconDrawable = action.getIcon().loadDrawable(packageContext) val newIconSize = context.resources .apply { .getDimensionPixelSize(R.dimen.smart_action_button_icon_size) val newIconSize: Int = context.resources.getDimensionPixelSize( val iconDrawable = R.dimen.smart_action_button_icon_size) loadIconDrawableWithTimeout(action.getIcon(), packageContext, newIconSize) setBounds(0, 0, newIconSize, newIconSize) ?: GradientDrawable() } iconDrawable.setBounds(0, 0, newIconSize, newIconSize) // Add the action icon to the Smart Action button. // Add the action icon to the Smart Action button. setCompoundDrawablesRelative(iconDrawable, null, null, null) setCompoundDrawablesRelative(iconDrawable, null, null, null) Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt +64 −6 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,13 @@ import android.app.PendingIntent import android.app.RemoteInput import android.app.RemoteInput import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.graphics.Bitmap import android.graphics.ImageDecoder import android.graphics.drawable.AdaptiveIconDrawable import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon import android.os.Build import android.os.Build import android.os.Bundle import android.os.Bundle import android.os.SystemClock import android.os.SystemClock Loading @@ -48,7 +55,13 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplyState.SuppressedA import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies import java.util.concurrent.FutureTask import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Inject import kotlin.system.measureTimeMillis /** Returns whether we should show the smart reply view and its smart suggestions. */ /** Returns whether we should show the smart reply view and its smart suggestions. */ fun shouldShowSmartReplyView( fun shouldShowSmartReplyView( Loading Loading @@ -281,6 +294,51 @@ interface SmartActionInflater { ): Button ): Button } } private const val ICON_TASK_TIMEOUT_MS = 500L private val iconTaskThreadPool = ThreadPoolExecutor(0, 25, 1, TimeUnit.MINUTES, SynchronousQueue()) private fun loadIconDrawableWithTimeout( icon: Icon, packageContext: Context, targetSize: Int, ): Drawable? { if (icon.type != Icon.TYPE_URI && icon.type != Icon.TYPE_URI_ADAPTIVE_BITMAP) { return icon.loadDrawable(packageContext) } val bitmapTask = FutureTask { val bitmap: Bitmap? val durationMillis = measureTimeMillis { val source = ImageDecoder.createSource(packageContext.contentResolver, icon.uri) bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ -> decoder.setTargetSize(targetSize, targetSize) decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT } } if (durationMillis > ICON_TASK_TIMEOUT_MS) { Log.w(TAG, "Loading $icon took ${durationMillis / 1000f} sec") } checkNotNull(bitmap) { "ImageDecoder.decodeBitmap() returned null" } } val bitmap = runCatching { iconTaskThreadPool.execute(bitmapTask) bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS) }.getOrElse { ex -> Log.e(TAG, "Failed to load $icon: $ex") bitmapTask.cancel(true) return null } // TODO(b/288561520): rewrite Icon so that we don't need to duplicate this logic val bitmapDrawable = BitmapDrawable(packageContext.resources, bitmap) val result = if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) AdaptiveIconDrawable(null, bitmapDrawable) else bitmapDrawable if (icon.hasTint()) { result.mutate() result.setTintList(icon.tintList) result.setTintBlendMode(icon.tintBlendMode) } return result } /* internal */ class SmartActionInflaterImpl @Inject constructor( /* internal */ class SmartActionInflaterImpl @Inject constructor( private val constants: SmartReplyConstants, private val constants: SmartReplyConstants, private val activityStarter: ActivityStarter, private val activityStarter: ActivityStarter, Loading @@ -304,12 +362,12 @@ interface SmartActionInflater { // We received the Icon from the application - so use the Context of the application to // We received the Icon from the application - so use the Context of the application to // reference icon resources. // reference icon resources. val iconDrawable = action.getIcon().loadDrawable(packageContext) val newIconSize = context.resources .apply { .getDimensionPixelSize(R.dimen.smart_action_button_icon_size) val newIconSize: Int = context.resources.getDimensionPixelSize( val iconDrawable = R.dimen.smart_action_button_icon_size) loadIconDrawableWithTimeout(action.getIcon(), packageContext, newIconSize) setBounds(0, 0, newIconSize, newIconSize) ?: GradientDrawable() } iconDrawable.setBounds(0, 0, newIconSize, newIconSize) // Add the action icon to the Smart Action button. // Add the action icon to the Smart Action button. setCompoundDrawablesRelative(iconDrawable, null, null, null) setCompoundDrawablesRelative(iconDrawable, null, null, null) Loading