11package com.github.grishberg.profiler.androidstudio
22
3- import com.android.ddmlib.IDevice
43import com.android.tools.idea.model.AndroidModel
5- import com.android.tools.idea.run.activity.ActivityLocator
6- import com.android.tools.idea.run.activity.DefaultActivityLocator
74import com.github.grishberg.profiler.common.AppLogger
8- import com.intellij.facet.FacetManager
9- import com.intellij.openapi.module.ModuleManager
105import com.github.grishberg.profiler.ui.dialogs.recorder.ProjectInfo
6+ import com.intellij.facet.FacetManager
117import com.intellij.openapi.application.ApplicationManager
8+ import com.intellij.openapi.module.ModuleManager
129import com.intellij.openapi.project.Project
13- import com.intellij.openapi.util.ThrowableComputable
10+ import java.io.File
11+ import javax.xml.parsers.DocumentBuilderFactory
1412import org.jetbrains.android.facet.AndroidFacet
15- import org.jetbrains.android.sdk.AndroidSdkUtils
13+ import org.w3c.dom.Document
14+ import org.w3c.dom.Element
15+ import org.w3c.dom.NodeList
1616
1717class PluginProjectInfo (
1818 project : Project , private val logger : AppLogger
@@ -22,16 +22,15 @@ class PluginProjectInfo(
2222 override val activityName: String?
2323
2424 init {
25- val facets = try {
25+ val facets = try {
2626 getAndroidFacets(project)
2727 } catch (e: Exception ) {
2828 logger.e(" getAndroidFacets error" , e)
2929 emptyList()
3030 }
3131 packageName = createPackageName(facets)
32- val devices = AndroidSdkUtils .getDebugBridge(project)?.devices ? : emptyArray()
3332 activityName = try {
34- getDefaultActivityName(facets, devices )
33+ getDefaultActivityName(facets)
3534 } catch (e: Exception ) {
3635 logger.e(" PluginProjectInfo: Error while fetching getDefaultActivityName" , e)
3736 null
@@ -62,15 +61,98 @@ class PluginProjectInfo(
6261 return null
6362 }
6463
65- @Throws(ActivityLocator . ActivityLocatorException ::class )
66- private fun getDefaultActivityName (facets : List <AndroidFacet >, devices : Array < IDevice > ): String? {
64+ @Throws(Exception ::class )
65+ private fun getDefaultActivityName (facets : List <AndroidFacet >): String? {
6766 val facet = facets.firstOrNull() ? : return null
68- val device = devices.firstOrNull() ? : return null
69- return ApplicationManager .getApplication()
70- .runReadAction(ThrowableComputable <String , ActivityLocator .ActivityLocatorException ?> {
71- DefaultActivityLocator (
72- facet
73- ).getQualifiedActivityName(device)
74- })
67+ return ApplicationManager .getApplication().runReadAction<String ?> {
68+ try {
69+ val manifestFile = findManifestFileReflection(facet)
70+ if (manifestFile == null || ! manifestFile.exists()) {
71+ logger.d(" Manifest file not found" )
72+ return @runReadAction null
73+ }
74+ val factory = DocumentBuilderFactory .newInstance()
75+ val builder = factory.newDocumentBuilder()
76+ val document: Document = builder.parse(manifestFile)
77+ val activities: NodeList = document.getElementsByTagName(" activity" )
78+ for (i in 0 until activities.length) {
79+ val activity = activities.item(i) as Element
80+ val intentFilters = activity.getElementsByTagName(" intent-filter" )
81+ for (j in 0 until intentFilters.length) {
82+ val intentFilter = intentFilters.item(j) as Element
83+ val actions = intentFilter.getElementsByTagName(" action" )
84+ val categories = intentFilter.getElementsByTagName(" category" )
85+ var hasMainAction = false
86+ var hasLauncherCategory = false
87+ for (k in 0 until actions.length) {
88+ val actionNode = actions.item(k) as Element
89+ val actionName = actionNode.getAttribute(" android:name" )
90+ if (actionName == " android.intent.action.MAIN" ) {
91+ hasMainAction = true
92+ }
93+ }
94+ for (k in 0 until categories.length) {
95+ val categoryNode = categories.item(k) as Element
96+ val categoryName = categoryNode.getAttribute(" android:name" )
97+ if (categoryName == " android.intent.category.LAUNCHER" ) {
98+ hasLauncherCategory = true
99+ }
100+ }
101+ if (hasMainAction && hasLauncherCategory) {
102+ val activityName = activity.getAttribute(" android:name" )
103+ if (activityName.isNotEmpty()) {
104+ logger.d(" Found default activity: $activityName " )
105+ return @runReadAction activityName
106+ }
107+ }
108+ }
109+ }
110+ logger.d(" No default activity found in manifest" )
111+ null
112+ } catch (e: Throwable ) {
113+ logger.e(" Error while parsing manifest" , e)
114+ null
115+ }
116+ }
117+ }
118+
119+ private fun findManifestFileReflection (facet : AndroidFacet ): File ? {
120+ try {
121+ val sourceProviderClass = Class .forName(" org.jetbrains.android.facet.AndroidFacet\$ SourceProvider" )
122+ val sourceProviderGetter = sourceProviderClass.getMethod(" getSourceProvider" )
123+ val sourceProvider = sourceProviderGetter.invoke(facet)
124+ if (sourceProvider != null ) {
125+ val allSourceFilesMethod = sourceProvider.javaClass.getMethod(" getAllSourceFiles" )
126+
127+ @Suppress(" UNCHECKED_CAST" ) val allSourceFiles =
128+ allSourceFilesMethod.invoke(sourceProvider) as List <File >
129+ for (file in allSourceFiles) {
130+ if (file.name == " AndroidManifest.xml" ) {
131+ logger.d(" Found manifest via sourceProvider reflection" )
132+ return file
133+ }
134+ }
135+ }
136+ } catch (e: Throwable ) {
137+ logger.d(" sourceProvider reflection failed: ${e.message} " )
138+ }
139+
140+ try {
141+ val manifestClass = Class .forName(" org.jetbrains.android.dom.manifest.Manifest" )
142+ val manifestGetter = AndroidFacet ::class .java.getMethod(" getManifest" )
143+ val manifest = manifestGetter.invoke(facet)
144+ if (manifest != null ) {
145+ val xmlFileGetter = manifestClass.getMethod(" getXmlFile" )
146+ val xmlFile = xmlFileGetter.invoke(manifest) as ? File
147+ if (xmlFile != null ) {
148+ logger.d(" Found manifest via manifest.xmlFile reflection" )
149+ return xmlFile
150+ }
151+ }
152+ } catch (e: Throwable ) {
153+ logger.d(" manifest.xmlFile reflection failed: ${e.message} " )
154+ }
155+
156+ return null
75157 }
76158}
0 commit comments