From 9db14afd3e9f7a66cd65d96f9db4293203749978 Mon Sep 17 00:00:00 2001 From: kyd3snik Date: Thu, 5 Aug 2021 20:41:37 +0300 Subject: [PATCH] added an action for navigation to resumed activity --- .../action/NavigateToResumedActivityAction.kt | 9 +++ .../developerphil/adbidea/adb/AdbFacade.kt | 1 + .../NavigateToResumedActivityCommand.kt | 66 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 7 ++ 4 files changed, 83 insertions(+) create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/NavigateToResumedActivityAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/adb/command/NavigateToResumedActivityCommand.kt diff --git a/src/main/kotlin/com/developerphil/adbidea/action/NavigateToResumedActivityAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/NavigateToResumedActivityAction.kt new file mode 100644 index 00000000..294dd973 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/NavigateToResumedActivityAction.kt @@ -0,0 +1,9 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class NavigateToResumedActivityAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.navigateToResumedActivity(project) +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt index e9a506f3..c3714860 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt @@ -28,6 +28,7 @@ object AdbFacade { fun disableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(WIFI, false)) fun enableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(MOBILE, true)) fun disableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(MOBILE, false)) + fun navigateToResumedActivity(project: Project) = executeOnDevice(project, NavigateToResumedActivityCommand()) private fun executeOnDevice(project: Project, runnable: Command) { if (AdbUtil.isGradleSyncInProgress(project)) { diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/NavigateToResumedActivityCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/NavigateToResumedActivityCommand.kt new file mode 100644 index 00000000..05fe6d3d --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/NavigateToResumedActivityCommand.kt @@ -0,0 +1,66 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.android.tools.idea.actions.PsiClassNavigation +import com.developerphil.adbidea.adb.AdbUtil +import com.developerphil.adbidea.adb.command.receiver.GenericReceiver +import com.developerphil.adbidea.invokeLater +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.developerphil.adbidea.ui.NotificationHelper.info +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +class NavigateToResumedActivityCommand : Command { + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + if (AdbUtil.isAppInstalled(device, packageName)) { + val activityClassPath = device.findResumedActivityClassPath() + val classNavigations = PsiClassNavigation.getNavigationForClass( + project, + activityClassPath + )?.filterNotNull() + + when { + activityClassPath == null -> error("Couldn't find resumed activity! Make sure that screen is turned on and device unlocked") + classNavigations.isNullOrEmpty() -> error("Couldn't find class in the project. ClassPath=$activityClassPath") + else -> navigate(classNavigations) + } + return true + } else { + error("$packageName is not installed on ${device.name}") + } + } catch (e1: Exception) { + error("Couldn't find resumed activity... " + e1.message) + } + return false + } + + private fun IDevice.findResumedActivityClassPath(): String? { + val receiver = GenericReceiver() + executeShellCommand("dumpsys activity | grep mResumedActivity", receiver, 15L, TimeUnit.SECONDS) + return receiver.adbOutputLines.mapNotNull { it.parseFullActivityClassPath() }.firstOrNull() + } + + private fun String.parseFullActivityClassPath(): String? { + val activityMatch = ACTIVITY_RECORD_REGEX.find(this)?.groups?.lastOrNull()?.value ?: return null + val (packageName, classPath) = activityMatch.split("/") + val isRelativeClassPath = classPath.startsWith(".") + return if (isRelativeClassPath) packageName + classPath else classPath + } + + private fun navigate(navigations: List) { + if (navigations.size > 1) { + val classes = navigations.joinToString(prefix = "[", postfix = "]") { it.psiFile.virtualFile.path } + info("Found multiple implementations $classes, navigating to the first one") + } + invokeLater { + navigations.first().navigate(true) + } + } + + private companion object { + val ACTIVITY_RECORD_REGEX = Regex("""ActivityRecord\{.* .* ([\w/\\.]*) .*}""") + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d2d871d6..9b61b908 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -251,6 +251,13 @@ description="Disable mobile data on device or emulator"> + + + +