Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/Navigation to resumed activity class #133

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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("<b>$packageName</b> 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<PsiClassNavigation>) {
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/\\.]*) .*}""")
}
}
7 changes: 7 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@
description="Disable mobile data on device or emulator">
</action>

<separator/>
<action id="com.developerphil.adbidea.action.NavigateToResumedActivityAction"
class="com.developerphil.adbidea.action.NavigateToResumedActivityAction"
text="ADB Navigate To Resumed Activity"
description="Find and navigate to resumed activity">
</action>

</group>
</actions>

Expand Down