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">
+
+
+
+