blob: 76c4a22bd482c81a6c26f1fea86a9732787ec61e [file] [log] [blame]
/*
* Copyright (C) 2017 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.tools.idea.profilers
import com.android.tools.idea.flags.StudioFlags
import com.android.tools.idea.projectsystem.getProjectSystem
import com.android.tools.idea.run.profiler.AbstractProfilerExecutorGroup
import com.android.tools.idea.run.profiler.ProfilingMode
import com.android.tools.idea.util.CommonAndroidUtil
import com.intellij.execution.Executor
import com.intellij.execution.ExecutorRegistry
import com.intellij.execution.configurations.RunProfile
import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionGroup
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.Presentation
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindowId
import icons.StudioIcons
import javax.swing.Icon
/**
* Executor group to support profiling app as profileable or debuggable in a dropdown menu.
*/
class ProfileRunExecutorGroup : AbstractProfilerExecutorGroup<ProfileRunExecutorGroup.ProfilerSetting>() {
/**
* A setting maps to a child executor in the group, containing metadata for the child executor.
*/
class ProfilerSetting(profilingMode: ProfilingMode) : AbstractProfilerSetting(profilingMode) {
override val actionName: String
get() = if (StudioFlags.PROFILER_TASK_BASED_UX.get()) {
when (profilingMode) {
ProfilingMode.PROFILEABLE -> "Profiler: Run as profileable (low overhead)"
ProfilingMode.DEBUGGABLE -> "Profiler: Run as debuggable (complete data)"
else -> "Profiler: Run"
}
}
else {
when (profilingMode) {
ProfilingMode.PROFILEABLE -> "Profile with low overhead (profileable)"
ProfilingMode.DEBUGGABLE -> "Profile with complete data (debuggable)"
else -> "Profile"
}
}
override val icon: Icon
get() = when (profilingMode) {
ProfilingMode.PROFILEABLE -> PROFILEABLE_ICON
ProfilingMode.DEBUGGABLE -> DEBUGGABLE_ICON
else -> StudioIcons.Shell.Toolbar.PROFILER
}
override val startActionText = "Profile"
override fun canRun(profile: RunProfile) = true
override fun isApplicable(project: Project) = true
override fun getStartActionText(configurationName: String) = if (StudioFlags.PROFILER_TASK_BASED_UX.get()) {
when (profilingMode) {
ProfilingMode.PROFILEABLE -> "Profiler: Run '$configurationName' as profileable (low overhead)"
ProfilingMode.DEBUGGABLE -> "Profiler: Run '$configurationName' as debuggable (complete data)"
else -> "Profiler: Run '$configurationName'"
}
}
else {
when (profilingMode) {
ProfilingMode.PROFILEABLE -> "Profile '$configurationName' with low overhead (profileable)"
ProfilingMode.DEBUGGABLE -> "Profile '$configurationName' with complete data (debuggable)"
else -> "Profile '$configurationName'"
}
}
}
private class GroupWrapper(actionGroup: ActionGroup) : ExecutorGroupWrapper(actionGroup) {
/**
* @return true if the Profileable Builds feature flag is true and the project's build system supports profiling mode (e.g. Gradle).
*/
override fun groupShouldBeVisible(e: AnActionEvent): Boolean {
val isProfilingModeSupported = e.project?.getProjectSystem()?.supportsProfilingMode() ?: false
return isProfilingModeSupported && StudioFlags.PROFILEABLE_BUILDS.get()
}
override fun updateDisabledActionPresentation(eventPresentation: Presentation) {
eventPresentation.icon = PROFILEABLE_ICON
eventPresentation.text = "Profile"
}
}
init {
// Register profiling modes as RunExecutorSettings, each mapped to a child executor.
// To determine which profiling mode is selected by the user action, perform a look-up
// via ProfileRunExecutorGroup#getRegisteredSettings(executorId).
registerSettings(ProfilerSetting(ProfilingMode.PROFILEABLE))
registerSettings(ProfilerSetting(ProfilingMode.DEBUGGABLE))
}
override fun getIcon(): Icon = PROFILEABLE_ICON
override fun getDisabledIcon(): Icon = toolWindowIcon
override fun getDescription(): String = "Profile selected configuration"
override fun getActionName(): String = "Profile"
override fun getId(): String = EXECUTOR_ID
override fun getStartActionText(): String = "Profile"
override fun getContextActionId(): String = "ProfileGroupRunClass"
override fun getHelpId(): String? = null
override fun isApplicable(project: Project): Boolean = CommonAndroidUtil.getInstance().isAndroidProject(project)
override fun getRunToolbarActionText(param: String): String = "Profile"
override fun getRunToolbarChooserText(): String = "Profile"
override fun getToolWindowIcon(): Icon = AllIcons.Toolwindows.ToolWindowRun
/**
* WARNING: do not call this to get the Profiler tool window ID, instead use [AndroidProfilerToolWindowFactory.ID] directly.
*
* Because "Profile" is a Run task, the Run tool window is also updated. This tool window ID is used by the IDEA platform
* (RunContentManager) to look up the Run tool window, so it should be "Run" instead of "Android Profiler".
* On the other hand, Profiler instantiates its tool window using [AndroidProfilerToolWindowFactory.ID] directly and never calls this
* method.
*/
override fun getToolWindowId(): String = ToolWindowId.RUN
override fun createExecutorGroupWrapper(actionGroup: ActionGroup): ExecutorGroupWrapper = GroupWrapper(actionGroup)
/**
* Returns the child executor for the given profiling mode.
*
* The child executor's IDs are in the format of "Android Profiler Group#1", per the implementation of ExecutorGroup. Because
* the IDs are not very readable, action name is compared to locate the executor.
*/
fun getChildExecutor(profilingMode: ProfilingMode): Executor = childExecutors().filter { e ->
e.actionName == ProfilerSetting(profilingMode).actionName
}.first()
companion object {
private val PROFILEABLE_ICON = StudioIcons.Shell.Toolbar.PROFILER_LOW_OVERHEAD
private val DEBUGGABLE_ICON = StudioIcons.Shell.Toolbar.PROFILER_DETAILED
@JvmStatic
fun getInstance(): ProfileRunExecutorGroup? {
return ExecutorRegistry.getInstance().getExecutorById(EXECUTOR_ID) as? ProfileRunExecutorGroup
}
}
}