Merge "Fix stalled background thread bug" into udc-dev

This commit is contained in:
Jeff DeCew
2023-06-27 19:02:58 +00:00
committed by Android (Google) Code Review

View File

@@ -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
@@ -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(
@@ -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,
@@ -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)