From d4b187b997bdd86da2c6788245eba3d257c3e433 Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Wed, 12 Mar 2025 05:52:37 +0000 Subject: [PATCH] Add perf tracing for several key operations in TaskView lifecycle. Fix: 402622741 Test: Manually looking at perf traces Flag: EXEMPT - tracing only Change-Id: If42a30d83dd72ebfe4074fedd7bdefcd102881d6 --- .../quickstep/OverviewCommandHelper.kt | 54 ++-- .../android/quickstep/views/RecentsView.java | 30 +- .../android/quickstep/views/TaskContainer.kt | 87 +++--- .../com/android/quickstep/views/TaskView.kt | 288 +++++++++--------- 4 files changed, 256 insertions(+), 203 deletions(-) diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index bf87291f10..20dfb1039b 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -28,6 +28,7 @@ import android.window.TransitionInfo import androidx.annotation.BinderThread import androidx.annotation.UiThread import androidx.annotation.VisibleForTesting +import com.android.app.tracing.traceSection import com.android.internal.jank.Cuj import com.android.launcher3.Flags.enableAltTabKqsOnConnectedDisplays import com.android.launcher3.Flags.enableLargeDesktopWindowingTile @@ -143,35 +144,38 @@ constructor( * completion (returns false). */ @UiThread - private fun processNextCommand() { - val command: CommandInfo = - commandQueue.firstOrNull() - ?: run { - Log.d(TAG, "no pending commands to be executed.") - return - } - - command.status = CommandStatus.PROCESSING - Log.d(TAG, "executing command: $command") - - if (enableOverviewCommandHelperTimeout()) { - coroutineScope.launch(dispatcherProvider.main) { - withTimeout(QUEUE_WAIT_DURATION_IN_MS) { - executeCommandSuspended(command) - ensureActive() - onCommandFinished(command) - } + private fun processNextCommand() = + traceSection("OverviewCommandHelper.processNextCommand") { + val command: CommandInfo? = commandQueue.firstOrNull() + if (command == null) { + Log.d(TAG, "no pending commands to be executed.") + return@traceSection } - } else { - val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) }) - Log.d(TAG, "command executed: $command with result: $result") - if (result) { - onCommandFinished(command) + + command.status = CommandStatus.PROCESSING + Log.d(TAG, "executing command: $command") + + if (enableOverviewCommandHelperTimeout()) { + coroutineScope.launch(dispatcherProvider.main) { + traceSection("OverviewCommandHelper.executeCommandWithTimeout") { + withTimeout(QUEUE_WAIT_DURATION_IN_MS) { + executeCommandSuspended(command) + ensureActive() + onCommandFinished(command) + } + } + } } else { - Log.d(TAG, "waiting for command callback: $command") + val result = + executeCommand(command, onCallbackResult = { onCommandFinished(command) }) + Log.d(TAG, "command executed: $command with result: $result") + if (result) { + onCommandFinished(command) + } else { + Log.d(TAG, "waiting for command callback: $command") + } } } - } /** * Executes the task and returns true if next task can be executed. If false, then the next task diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 1f3fbf9b4b..07eae21bdc 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -17,6 +17,8 @@ package com.android.quickstep.views; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.os.Trace.traceBegin; +import static android.os.Trace.traceEnd; import static android.view.Surface.ROTATION_0; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.makeMeasureSpec; @@ -104,6 +106,7 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.os.VibrationEffect; import android.text.Layout; @@ -139,6 +142,7 @@ import androidx.annotation.UiThread; import androidx.core.graphics.ColorUtils; import androidx.dynamicanimation.animation.SpringAnimation; +import com.android.app.tracing.TraceUtilsKt; import com.android.internal.jank.Cuj; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener; @@ -1292,6 +1296,7 @@ public abstract class RecentsView< @Override public void onViewRemoved(View child) { + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewRemoved"); super.onViewRemoved(child); // Clear the task data for the removed child if it was visible unless: // - It's the initial taskview for entering split screen, we only pretend to dismiss the @@ -1303,6 +1308,7 @@ public abstract class RecentsView< clearAndRecycleTaskView((TaskView) child); } } + traceEnd(Trace.TRACE_TAG_APP); } private void clearAndRecycleTaskView(TaskView taskView) { @@ -1321,6 +1327,7 @@ public abstract class RecentsView< @Override public void onViewAdded(View child) { + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.onViewAdded"); super.onViewAdded(child); if (child instanceof TaskView) { mTaskViewCount++; @@ -1331,6 +1338,7 @@ public abstract class RecentsView< child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL); mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false); updateEmptyMessage(); + traceEnd(Trace.TRACE_TAG_APP); } @Override @@ -1927,6 +1935,9 @@ public abstract class RecentsView< return; } + // Start here to avoid early returns and empty cases which have special logic + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan"); + TaskView currentTaskView = getTaskViewAt(mCurrentPage); int[] currentTaskIds = null; // Track the current DesktopTaskView through [deskId] as a desk can be empty without any @@ -1972,8 +1983,9 @@ public abstract class RecentsView< // TaskIds will no longer be valid after remove and re-add, clearing mTopRowIdSet. mAnyTaskHasBeenDismissed = false; mTopRowIdSet.clear(); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.removeAllViews"); removeAllViews(); - + traceEnd(Trace.TRACE_TAG_APP); // If we are entering Overview as a result of initiating a split from somewhere else // (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail. int stagedTaskIdToBeRemoved; @@ -2000,6 +2012,7 @@ public abstract class RecentsView< // Add `mAddDesktopButton` as the first child. addView(mAddDesktopButton); } + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop"); // Add views as children based on whether it's grouped or single task. Looping through // taskGroups backwards populates the thumbnail grid from least recent to most recent. @@ -2019,8 +2032,11 @@ public abstract class RecentsView< // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE // to be a temporary container for the remaining task. + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.createTaskView"); TaskView taskView = getTaskViewFromPool( containsStagedTask ? TaskViewType.SINGLE : groupTask.taskViewType); + traceEnd(Trace.TRACE_TAG_APP); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.bind"); if (taskView instanceof GroupedTaskView groupedTaskView) { var splitTask = (SplitTask) groupTask; groupedTaskView.bind(splitTask.getTopLeftTask(), @@ -2038,13 +2054,18 @@ public abstract class RecentsView< taskView.bind(((SingleTask) groupTask).getTask(), mOrientationState, mTaskOverlayFactory); } + traceEnd(Trace.TRACE_TAG_APP); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.forLoop.addTaskView"); addView(taskView); + traceEnd(Trace.TRACE_TAG_APP); // enables instance filtering if the feature flag for it is on if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) { taskView.setUpShowAllInstancesListener(); } } + // For loop end trace + traceEnd(Trace.TRACE_TAG_APP); addView(mClearAllButton); @@ -2064,8 +2085,10 @@ public abstract class RecentsView< setFocusedTaskViewId( newFocusedTaskView != null ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID); + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.layouts"); updateTaskSize(); updateChildTaskOrientations(); + traceEnd(Trace.TRACE_TAG_APP); TaskView newRunningTaskView = mUtils.getDesktopTaskViewForDeskId(runningTaskViewDeskId); if (newRunningTaskView == null) { @@ -2120,6 +2143,7 @@ public abstract class RecentsView< }); } + traceBegin(Trace.TRACE_TAG_APP, "RecentsView.applyLoadPlan.cleanupStates"); if (mIgnoreResetTaskId != INVALID_TASK_ID && getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) { // If the taskView mapping is changing, do not preserve the visuals. Since we are @@ -2134,6 +2158,10 @@ public abstract class RecentsView< if (isPageScrollsInitialized()) { onPageScrollsInitialized(); } + traceEnd(Trace.TRACE_TAG_APP); + + // applyLoadPlan end trace + traceEnd(Trace.TRACE_TAG_APP); } private boolean isModal() { diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index ec6d1c4432..afe7e928ad 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -21,6 +21,7 @@ import android.graphics.Matrix import android.util.Log import android.view.View import android.view.View.OnClickListener +import com.android.app.tracing.traceSection import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.model.data.TaskViewItemInfo import com.android.launcher3.util.SplitConfigurationOptions @@ -100,26 +101,28 @@ class TaskContainer( val itemInfo: TaskViewItemInfo get() = TaskViewItemInfo(taskView, this) - fun bind() { - digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) - if (!enableRefactorTaskThumbnail()) { - thumbnailViewDeprecated.bind(task, overlay, taskView) + fun bind() = + traceSection("TaskContainer.bind") { + digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) + if (!enableRefactorTaskThumbnail()) { + thumbnailViewDeprecated.bind(task, overlay, taskView) + } } - } - fun destroy() { - digitalWellBeingToast?.destroy() - taskContentView.scaleX = 1f - taskContentView.scaleY = 1f - overlay.reset() - if (enableRefactorTaskThumbnail()) { - isThumbnailValid = false - thumbnailData = null - thumbnailView.onRecycle() - } else { - thumbnailViewDeprecated.setShowSplashForSplitSelection(false) + fun destroy() = + traceSection("TaskContainer.destroy") { + digitalWellBeingToast?.destroy() + taskContentView.scaleX = 1f + taskContentView.scaleY = 1f + overlay.reset() + if (enableRefactorTaskThumbnail()) { + isThumbnailValid = false + thumbnailData = null + thumbnailView.onRecycle() + } else { + thumbnailViewDeprecated.setShowSplashForSplitSelection(false) + } } - } fun setOverlayEnabled(enabled: Boolean) { if (!enableRefactorTaskThumbnail()) { @@ -137,23 +140,24 @@ class TaskContainer( } } - fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) { - this.thumbnailPosition = thumbnailPosition - when { - !overlayEnabledStatus -> overlay.reset() - thumbnailPosition == null -> { - Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception()) - overlay.reset() + fun refreshOverlay(thumbnailPosition: ThumbnailPosition?) = + traceSection("TaskContainer.refreshOverlay") { + this.thumbnailPosition = thumbnailPosition + when { + !overlayEnabledStatus -> overlay.reset() + thumbnailPosition == null -> { + Log.e(TAG, "Thumbnail position was null during overlay refresh", Exception()) + overlay.reset() + } + else -> + overlay.initOverlay( + task, + thumbnailData?.thumbnail, + thumbnailPosition.matrix, + thumbnailPosition.isRotated, + ) } - else -> - overlay.initOverlay( - task, - thumbnailData?.thumbnail, - thumbnailPosition.matrix, - thumbnailPosition.isRotated, - ) } - } fun addChildForAccessibility(outChildren: ArrayList) { addAccessibleChildToList(iconView.asView(), outChildren) @@ -168,15 +172,16 @@ class TaskContainer( liveTile: Boolean, hasHeader: Boolean, clickCloseListener: OnClickListener?, - ) { - taskContentView.setState( - TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener), - TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile), - state?.taskId, - ) - thumbnailData = if (state is TaskData.Data) state.thumbnailData else null - overlay.setThumbnailState(thumbnailData) - } + ) = + traceSection("TaskContainer.setState") { + taskContentView.setState( + TaskUiStateMapper.toTaskHeaderState(state, hasHeader, clickCloseListener), + TaskUiStateMapper.toTaskThumbnailUiState(state, liveTile), + state?.taskId, + ) + thumbnailData = if (state is TaskData.Data) state.thumbnailData else null + overlay.setThumbnailState(thumbnailData) + } fun updateTintAmount(tintAmount: Float) { thumbnailView.updateTintAmount(tintAmount) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 29793ade73..cdf5f81be3 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -42,6 +42,7 @@ import androidx.annotation.IntDef import androidx.annotation.VisibleForTesting import androidx.core.view.updateLayoutParams import com.android.app.animation.Interpolators +import com.android.app.tracing.traceSection import com.android.launcher3.Flags.enableCursorHoverStates import com.android.launcher3.Flags.enableDesktopExplodedView import com.android.launcher3.Flags.enableGridOnlyOverview @@ -733,61 +734,63 @@ constructor( ?.inflate() } - override fun onAttachedToWindow() { - super.onAttachedToWindow() - if (enableRefactorTaskThumbnail()) { - // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in - // onRecycle. So it should be initialized at this point. TaskView Lifecycle: - // `bind` -> `onBind` -> onAttachedToWindow() -> onDetachFromWindow -> onRecycle - coroutineJobs += - coroutineScope.launch(dispatcherProvider.main) { - viewModel!!.state.collectLatest(::updateTaskViewState) - } - } - } - - private fun updateTaskViewState(state: TaskTileUiState) { - sysUiStatusNavFlags = state.sysUiStatusNavFlags - - // Updating containers - val mapOfTasks = state.tasks.associateBy { it.taskId } - taskContainers.forEach { container -> - val taskId = container.task.key.id - val containerState = mapOfTasks[taskId] - val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView() - container.setState( - state = containerState, - liveTile = state.isLiveTile, - hasHeader = shouldHaveHeader, - clickCloseListener = - if (shouldHaveHeader) { - { - // Update the layout UI to remove this task from the layout grid, and - // remove the task from ActivityManager afterwards. - recentsView?.dismissTask( - taskId, - /* animate= */ true, - /* removeTask= */ true, - ) - } - } else { - null - }, - ) - updateThumbnailValidity(container) - val thumbnailPosition = - updateThumbnailMatrix( - container = container, - width = container.thumbnailView.width, - height = container.thumbnailView.height, - ) - container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition) - - if (enableOverviewIconMenu()) { - setIconState(container, containerState) + override fun onAttachedToWindow() = + traceSection("TaskView.onAttachedToWindow") { + super.onAttachedToWindow() + if (enableRefactorTaskThumbnail()) { + // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in + // onRecycle. So it should be initialized at this point. TaskView Lifecycle: + // `bind` -> `onBind` -> onAttachedToWindow() -> onDetachFromWindow -> onRecycle + coroutineJobs += + coroutineScope.launch(dispatcherProvider.main) { + viewModel!!.state.collectLatest(::updateTaskViewState) + } + } + } + + private fun updateTaskViewState(state: TaskTileUiState) = + traceSection("TaskView.updateTaskViewState") { + sysUiStatusNavFlags = state.sysUiStatusNavFlags + + // Updating containers + val mapOfTasks = state.tasks.associateBy { it.taskId } + taskContainers.forEach { container -> + val taskId = container.task.key.id + val containerState = mapOfTasks[taskId] + val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView() + container.setState( + state = containerState, + liveTile = state.isLiveTile, + hasHeader = shouldHaveHeader, + clickCloseListener = + if (shouldHaveHeader) { + { + // Update the layout UI to remove this task from the layout grid, + // and remove the task from ActivityManager afterwards. + recentsView?.dismissTask( + taskId, + /* animate= */ true, + /* removeTask= */ true, + ) + } + } else { + null + }, + ) + updateThumbnailValidity(container) + val thumbnailPosition = + updateThumbnailMatrix( + container = container, + width = container.thumbnailView.width, + height = container.thumbnailView.height, + ) + container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition) + + if (enableOverviewIconMenu()) { + setIconState(container, containerState) + } } } - } private fun updateThumbnailValidity(container: TaskContainer) { container.isThumbnailValid = @@ -814,27 +817,33 @@ constructor( container: TaskContainer, width: Int, height: Int, - ): ThumbnailPosition? { - val thumbnailPosition = - viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl) - ?: return null - container.updateThumbnailMatrix(thumbnailPosition.matrix) - return thumbnailPosition - } + ): ThumbnailPosition? = + traceSection("TaskView.updateThumbnailMatrix") { + val thumbnailPosition = + viewModel?.getThumbnailPosition(container.thumbnailData, width, height, isLayoutRtl) + ?: return null + container.updateThumbnailMatrix(thumbnailPosition.matrix) + return thumbnailPosition + } - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - if (enableRefactorTaskThumbnail()) { - // The jobs are being cancelled in the background thread. So we make a copy of the list - // to prevent cleaning a new job that might be added to this list during onAttach - // or another moment in the lifecycle. - val coroutineJobsToCancel = coroutineJobs.toList() - coroutineJobs.clear() - coroutineScope.launch(dispatcherProvider.background) { - coroutineJobsToCancel.forEach { it.cancel("TaskView detaching from window") } + override fun onDetachedFromWindow() = + traceSection("TaskView.onDetachedFromWindow") { + super.onDetachedFromWindow() + if (enableRefactorTaskThumbnail()) { + // The jobs are being cancelled in the background thread. So we make a copy of the + // list to prevent cleaning a new job that might be added to this list during + // onAttach or another moment in the lifecycle. + val coroutineJobsToCancel = coroutineJobs.toList() + coroutineJobs.clear() + coroutineScope.launch(dispatcherProvider.background) { + traceSection("TaskView.onDetachedFromWindow.cancellingJobs") { + coroutineJobsToCancel.forEach { + it.cancel("TaskView detaching from window") + } + } + } } } - } /** Updates this task view to the given {@param task}. */ open fun bind( @@ -860,37 +869,40 @@ constructor( onBind(orientedState) } - protected open fun onBind(orientedState: RecentsOrientedState) { - if (enableRefactorTaskThumbnail()) { - val scopeId = context - Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}") - viewModel = - TaskViewModel( - taskViewType = type, - recentsViewData = RecentsDependencies.get(scopeId), - getTaskUseCase = RecentsDependencies.get(scopeId), - getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId), - isThumbnailValidUseCase = RecentsDependencies.get(scopeId), - getThumbnailPositionUseCase = RecentsDependencies.get(scopeId), - dispatcherProvider = RecentsDependencies.get(scopeId), - ) - .apply { bind(*taskIds) } - } - - taskContainers.forEach { container -> - container.bind() - if (enableRefactorTaskThumbnail()) { - container.taskContentView.cornerRadius = - thumbnailFullscreenParams.currentCornerRadius - container.taskContentView.doOnSizeChange { width, height -> - updateThumbnailValidity(container) - val thumbnailPosition = updateThumbnailMatrix(container, width, height) - container.refreshOverlay(thumbnailPosition) + protected open fun onBind(orientedState: RecentsOrientedState) = + traceSection("TaskView.onBind") { + traceSection("TaskView.onBind.createViewModel") { + if (enableRefactorTaskThumbnail()) { + val scopeId = context + Log.d(TAG, "onBind $scopeId ${orientedState.containerInterface}") + viewModel = + TaskViewModel( + taskViewType = type, + recentsViewData = RecentsDependencies.get(scopeId), + getTaskUseCase = RecentsDependencies.get(scopeId), + getSysUiStatusNavFlagsUseCase = RecentsDependencies.get(scopeId), + isThumbnailValidUseCase = RecentsDependencies.get(scopeId), + getThumbnailPositionUseCase = RecentsDependencies.get(scopeId), + dispatcherProvider = RecentsDependencies.get(scopeId), + ) + .apply { bind(*taskIds) } } } + + taskContainers.forEach { container -> + container.bind() + if (enableRefactorTaskThumbnail()) { + container.taskContentView.cornerRadius = + thumbnailFullscreenParams.currentCornerRadius + container.taskContentView.doOnSizeChange { width, height -> + updateThumbnailValidity(container) + val thumbnailPosition = updateThumbnailMatrix(container, width, height) + container.refreshOverlay(thumbnailPosition) + } + } + } + setOrientationState(orientedState) } - setOrientationState(orientedState) - } private fun applyThumbnailSplashAlpha() { val alpha = getSplashAlphaProgress() @@ -916,22 +928,23 @@ constructor( @IdRes digitalWellbeingBannerId: Int, @StagePosition stagePosition: Int, taskOverlayFactory: TaskOverlayFactory, - ): TaskContainer { - val iconView = findViewById(iconViewId) as TaskViewIcon - val taskContentView = findViewById(taskContentViewId) - return TaskContainer( - this, - task, - taskContentView, - taskContentView.findViewById(thumbnailViewId), - iconView, - TransformingTouchDelegate(iconView.asView()), - stagePosition, - findViewById(digitalWellbeingBannerId)!!, - findViewById(showWindowViewId)!!, - taskOverlayFactory, - ) - } + ): TaskContainer = + traceSection("TaskView.createTaskContainer") { + val iconView = findViewById(iconViewId) as TaskViewIcon + val taskContentView = findViewById(taskContentViewId) + return TaskContainer( + this, + task, + taskContentView, + taskContentView.findViewById(thumbnailViewId), + iconView, + TransformingTouchDelegate(iconView.asView()), + stagePosition, + findViewById(digitalWellbeingBannerId)!!, + findViewById(showWindowViewId)!!, + taskOverlayFactory, + ) + } fun containsMultipleTasks() = taskContainers.size > 1 @@ -944,11 +957,12 @@ constructor( /** Check if given `taskId` is tracked in this view */ fun containsTaskId(taskId: Int) = getTaskContainerById(taskId) != null - open fun setOrientationState(orientationState: RecentsOrientedState) { - this.orientedState = orientationState - taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) } - setThumbnailOrientation(orientationState) - } + open fun setOrientationState(orientationState: RecentsOrientedState) = + traceSection("TaskView.setOrientationState") { + this.orientedState = orientationState + taskContainers.forEach { it.iconView.setIconOrientation(orientationState, isGridTask) } + setThumbnailOrientation(orientationState) + } protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) { taskContainers.forEach { @@ -1095,25 +1109,27 @@ constructor( protected open fun needsUpdate(@TaskDataChanges dataChange: Int, @TaskDataChanges flag: Int) = (dataChange and flag) == flag - protected open fun cancelPendingLoadTasks() { - pendingThumbnailLoadRequests.forEach { it.cancel() } - pendingThumbnailLoadRequests.clear() - pendingIconLoadRequests.forEach { it.cancel() } - pendingIconLoadRequests.clear() - } + protected open fun cancelPendingLoadTasks() = + traceSection("TaskView.cancelPendingLoadTasks") { + pendingThumbnailLoadRequests.forEach { it.cancel() } + pendingThumbnailLoadRequests.clear() + pendingIconLoadRequests.forEach { it.cancel() } + pendingIconLoadRequests.clear() + } - protected open fun setIconState(container: TaskContainer, state: TaskData?) { - if (enableOverviewIconMenu()) { - if (state is TaskData.Data) { - setIcon(container.iconView, state.icon) - container.iconView.setText(state.title) - container.digitalWellBeingToast?.initialize() - } else { - setIcon(container.iconView, null) - container.iconView.setText(null) + protected open fun setIconState(container: TaskContainer, state: TaskData?) = + traceSection("TaskView.setIconState") { + if (enableOverviewIconMenu()) { + if (state is TaskData.Data) { + setIcon(container.iconView, state.icon) + container.iconView.setText(state.title) + container.digitalWellBeingToast?.initialize() + } else { + setIcon(container.iconView, null) + container.iconView.setText(null) + } } } - } protected open fun onIconLoaded(taskContainer: TaskContainer) { setIcon(taskContainer.iconView, taskContainer.task.icon)