summaryrefslogtreecommitdiff
path: root/logcat
diff options
context:
space:
mode:
authorAlon Albert <aalbert@google.com>2022-07-31 15:26:47 +0000
committeraalbert <aalbert@google.com>2022-07-31 09:03:59 -0700
commit772529591783de23904de1d908b48489edb86976 (patch)
treeb97b76eedf96fc35d08cd547ed8e22fcf5736e98 /logcat
parent54643825b6236e49621f1817750c46f8c38e0f1b (diff)
downloadidea-772529591783de23904de1d908b48489edb86976.tar.gz
Roll Forward of 19436573
Original Title: Use AndroidModel.getAllApplicationIds() To Get App Ids Revert "Revert Change I8567cc58" This reverts commit 8708d76e110f2279ac5ce0f0283590f64439bb19. Reason for revert: Roll forward with fixed fake. The failure was caused by a bug in the FakeProjectApplicationIdsProvider. It published the topic before applying the change to itself. Fixes: 233630777 Test: Added Change-Id: I71c43dec9d73e7555df9b982ec51c9f27f5cdb13
Diffstat (limited to 'logcat')
-rw-r--r--logcat/BUILD2
-rw-r--r--logcat/intellij.android.logcat.iml1
-rw-r--r--logcat/intellij.android.logcat.tests.iml1
-rw-r--r--logcat/src/META-INF/logcat.xml3
-rw-r--r--logcat/src/com/android/tools/idea/logcat/LogcatHeaderPanel.kt3
-rw-r--r--logcat/src/com/android/tools/idea/logcat/LogcatMainPanel.kt25
-rw-r--r--logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProvider.kt (renamed from logcat/src/com/android/tools/idea/logcat/ProjectPackageNamesProvider.kt)25
-rw-r--r--logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImpl.kt50
-rw-r--r--logcat/testSrc/com/android/tools/idea/logcat/FakeProjectApplicationIdsProvider.kt39
-rw-r--r--logcat/testSrc/com/android/tools/idea/logcat/LogcatMainPanelTest.kt56
-rw-r--r--logcat/testSrc/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImplTest.kt126
11 files changed, 300 insertions, 31 deletions
diff --git a/logcat/BUILD b/logcat/BUILD
index 54a310c87ea..2d9dad64644 100644
--- a/logcat/BUILD
+++ b/logcat/BUILD
@@ -27,6 +27,7 @@ iml_module(
"//tools/adt/idea/.idea/libraries:studio-analytics-proto",
"//tools/adt/idea/.idea/libraries:kotlinx-coroutines-guava",
"//tools/adt/idea/android-adb-ui:intellij.android.adb.ui[module]",
+ "//tools/adt/idea/project-system:intellij.android.projectSystem[module]",
],
)
@@ -61,5 +62,6 @@ iml_module(
"//tools/adt/idea/android-adb:intellij.android.adb[module, test]",
"//tools/base/fakeadbserver:studio.android.sdktools.fakeadbserver[module, test]",
"//tools/base/adblib-ddmlibcompatibility:studio.android.sdktools.adblib.ddmlibcompatibility[module, test]",
+ "//tools/adt/idea/project-system:intellij.android.projectSystem[module, test]",
],
)
diff --git a/logcat/intellij.android.logcat.iml b/logcat/intellij.android.logcat.iml
index b92af772d43..cb6c94adbc0 100644
--- a/logcat/intellij.android.logcat.iml
+++ b/logcat/intellij.android.logcat.iml
@@ -23,5 +23,6 @@
<orderEntry type="library" name="studio-analytics-proto" level="project" />
<orderEntry type="library" name="kotlinx-coroutines-guava" level="project" />
<orderEntry type="module" module-name="intellij.android.adb.ui" />
+ <orderEntry type="module" module-name="intellij.android.projectSystem" />
</component>
</module> \ No newline at end of file
diff --git a/logcat/intellij.android.logcat.tests.iml b/logcat/intellij.android.logcat.tests.iml
index da7ed0ea38f..b3c5cbfbb3b 100644
--- a/logcat/intellij.android.logcat.tests.iml
+++ b/logcat/intellij.android.logcat.tests.iml
@@ -28,6 +28,7 @@
<orderEntry type="module" module-name="intellij.android.adb" scope="TEST" />
<orderEntry type="module" module-name="android.sdktools.fakeadbserver" scope="TEST" />
<orderEntry type="module" module-name="android.sdktools.adblib.ddmlibcompatibility" scope="TEST" />
+ <orderEntry type="module" module-name="intellij.android.projectSystem" scope="TEST" />
</component>
<component name="TestModuleProperties" production-module="intellij.android.logcat" />
</module> \ No newline at end of file
diff --git a/logcat/src/META-INF/logcat.xml b/logcat/src/META-INF/logcat.xml
index 37f40b55f57..149bbfaff90 100644
--- a/logcat/src/META-INF/logcat.xml
+++ b/logcat/src/META-INF/logcat.xml
@@ -57,6 +57,9 @@
<applicationService serviceImplementation="com.android.tools.idea.logcat.filters.AndroidLogcatNamedFilters"/>
<applicationService serviceImplementation="com.android.tools.idea.logcat.filters.AndroidLogcatFilterHistory"/>
<applicationService serviceImplementation="com.android.tools.idea.ui.screenrecording.ScreenRecorderPersistentOptions"/>
+ <projectService
+ serviceInterface="com.android.tools.idea.logcat.ProjectApplicationIdsProvider"
+ serviceImplementation="com.android.tools.idea.logcat.ProjectApplicationIdsProviderImpl"/>
<additionalTextAttributes scheme="Default" file="colorSchemes/LogcatColorSchemeDefault.xml"/>
<additionalTextAttributes scheme="Darcula" file="colorSchemes/LogcatColorSchemeDarcula.xml"/>
diff --git a/logcat/src/com/android/tools/idea/logcat/LogcatHeaderPanel.kt b/logcat/src/com/android/tools/idea/logcat/LogcatHeaderPanel.kt
index 5fcd717d443..54a8962b216 100644
--- a/logcat/src/com/android/tools/idea/logcat/LogcatHeaderPanel.kt
+++ b/logcat/src/com/android/tools/idea/logcat/LogcatHeaderPanel.kt
@@ -46,7 +46,7 @@ import javax.swing.JPanel
internal class LogcatHeaderPanel(
project: Project,
val logcatPresenter: LogcatPresenter,
- packageNamesProvider: PackageNamesProvider,
+ private val filterParser: LogcatFilterParser,
filter: String,
initialDevice: Device?,
adbSession: AdbSession,
@@ -55,7 +55,6 @@ internal class LogcatHeaderPanel(
logcatPresenter,
initialDevice,
DeviceComboBoxDeviceTracker(project, initialDevice, adbSession))
- private val filterParser = LogcatFilterParser(project, packageNamesProvider)
private val filterComponent: FilterTextComponent = FilterTextComponent.createComponent(project, logcatPresenter, filterParser, filter)
diff --git a/logcat/src/com/android/tools/idea/logcat/LogcatMainPanel.kt b/logcat/src/com/android/tools/idea/logcat/LogcatMainPanel.kt
index 5d41dfbb87f..35deaae85bc 100644
--- a/logcat/src/com/android/tools/idea/logcat/LogcatMainPanel.kt
+++ b/logcat/src/com/android/tools/idea/logcat/LogcatMainPanel.kt
@@ -32,6 +32,8 @@ import com.android.tools.idea.logcat.LogcatPanelConfig.FormattingConfig
import com.android.tools.idea.logcat.LogcatPanelConfig.FormattingConfig.Custom
import com.android.tools.idea.logcat.LogcatPanelConfig.FormattingConfig.Preset
import com.android.tools.idea.logcat.LogcatPresenter.Companion.LOGCAT_PRESENTER_ACTION
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.Companion.PROJECT_APPLICATION_IDS_CHANGED_TOPIC
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.ProjectApplicationIdsListener
import com.android.tools.idea.logcat.actions.ClearLogcatAction
import com.android.tools.idea.logcat.actions.CreateScratchFileAction
import com.android.tools.idea.logcat.actions.LogcatFoldLinesLikeThisAction
@@ -175,7 +177,6 @@ internal class LogcatMainPanel(
androidProjectDetector: AndroidProjectDetector = AndroidProjectDetectorImpl(),
hyperlinkDetector: HyperlinkDetector? = null,
foldingDetector: FoldingDetector? = null,
- packageNamesProvider: PackageNamesProvider = ProjectPackageNamesProvider(project),
adbSession: AdbSession = AdbLibService.getInstance(project).session,
private val logcatService: LogcatService =
LogcatServiceImpl(project, { AdbLibService.getInstance(project).session.deviceServices }, ProcessNameMonitor.getInstance(project)),
@@ -205,18 +206,19 @@ internal class LogcatMainPanel(
private val tags = MostRecentlyAddedSet<String>(MAX_TAGS)
private val packages = MostRecentlyAddedSet<String>(MAX_PACKAGE_NAMES)
private val processNames = MostRecentlyAddedSet<String>(MAX_PROCESS_NAMES)
+ private val packageNamesProvider: ProjectApplicationIdsProvider = ProjectApplicationIdsProvider.getInstance(project)
+ private val logcatFilterParser = LogcatFilterParser(project, packageNamesProvider, androidProjectDetector)
@VisibleForTesting
val headerPanel = LogcatHeaderPanel(
project,
logcatPresenter = this,
- packageNamesProvider,
+ logcatFilterParser,
state?.filter ?: getDefaultFilter(project, androidProjectDetector),
state?.device,
adbSession,
)
- private val logcatFilterParser = LogcatFilterParser(project, packageNamesProvider, androidProjectDetector)
@VisibleForTesting
internal val messageProcessor = MessageProcessor(
@@ -283,11 +285,18 @@ internal class LogcatMainPanel(
.setFilter(logcatFilterParser.getUsageTrackingEvent(headerPanel.filter))
.setFormatConfiguration(state?.formattingConfig.toUsageTracking())))
- project.messageBus.connect(this).subscribe(ClearLogcatListener.TOPIC, ClearLogcatListener {
- if (connectedDevice.get()?.serialNumber == it) {
- clearMessageView()
- }
- })
+ project.messageBus.let { messageBus ->
+ messageBus.connect(this).subscribe(ClearLogcatListener.TOPIC, ClearLogcatListener {
+ if (connectedDevice.get()?.serialNumber == it) {
+ clearMessageView()
+ }
+ })
+ messageBus.connect(this).subscribe(PROJECT_APPLICATION_IDS_CHANGED_TOPIC, ProjectApplicationIdsListener {
+ if (getFilter().contains(LogcatFilter.MY_PACKAGE)) {
+ reloadMessages()
+ }
+ })
+ }
coroutineScope.launch(workerThread) {
headerPanel.trackSelectedDevice().collect { device ->
diff --git a/logcat/src/com/android/tools/idea/logcat/ProjectPackageNamesProvider.kt b/logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProvider.kt
index 4569cbd8273..f75e3c1284d 100644
--- a/logcat/src/com/android/tools/idea/logcat/ProjectPackageNamesProvider.kt
+++ b/logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProvider.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -15,15 +15,20 @@
*/
package com.android.tools.idea.logcat
-import com.android.tools.idea.model.AndroidModuleInfo
-import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
+import com.intellij.util.messages.Topic
-class ProjectPackageNamesProvider(project: Project) : PackageNamesProvider {
- private val moduleManager = ModuleManager.getInstance(project)
+/**
+ * Provides a set of application ids associated with the project
+ */
+internal interface ProjectApplicationIdsProvider : PackageNamesProvider {
+ fun interface ProjectApplicationIdsListener {
+ fun applicationIdsChanged(applicationIds: Set<String>)
+ }
+
+ companion object {
+ fun getInstance(project: Project): ProjectApplicationIdsProvider = project.getService(ProjectApplicationIdsProvider::class.java)
- // TODO(b/206675088): Maybe get package names from run configurations too?
- // TODO(b/206675088): Maybe get notified when the set of package names might change?
- override fun getPackageNames(): Set<String> =
- moduleManager.modules.mapNotNullTo(mutableSetOf()) { AndroidModuleInfo.getInstance(it)?.`package` }
-} \ No newline at end of file
+ val PROJECT_APPLICATION_IDS_CHANGED_TOPIC = Topic("ProjectApplicationIdsChanged", ProjectApplicationIdsListener::class.java)
+ }
+}
diff --git a/logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImpl.kt b/logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImpl.kt
new file mode 100644
index 00000000000..e3819001239
--- /dev/null
+++ b/logcat/src/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImpl.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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.logcat
+
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.Companion.PROJECT_APPLICATION_IDS_CHANGED_TOPIC
+import com.android.tools.idea.model.AndroidModel
+import com.android.tools.idea.projectsystem.PROJECT_SYSTEM_SYNC_TOPIC
+import com.android.tools.idea.projectsystem.ProjectSystemSyncManager
+import com.android.tools.idea.projectsystem.ProjectSystemSyncManager.SyncResult
+import com.android.tools.idea.projectsystem.getAndroidFacets
+import com.intellij.openapi.project.Project
+
+/**
+ * Prod implementation of [ProjectApplicationIdsProvider]
+ */
+internal class ProjectApplicationIdsProviderImpl(private val project: Project) : ProjectApplicationIdsProvider {
+ private var applicationIds = loadApplicationIds()
+
+ init {
+ project.messageBus.connect(project).subscribe(PROJECT_SYSTEM_SYNC_TOPIC, RefreshApplicationIds())
+ }
+
+ override fun getPackageNames(): Set<String> = applicationIds
+
+ private fun loadApplicationIds(): Set<String> =
+ project.getAndroidFacets().flatMapTo(mutableSetOf()) { AndroidModel.get(it)?.allApplicationIds ?: emptyList() }
+
+ private inner class RefreshApplicationIds : ProjectSystemSyncManager.SyncResultListener {
+ override fun syncEnded(result: SyncResult) {
+ val newIds = loadApplicationIds()
+ if (newIds != applicationIds) {
+ applicationIds = newIds
+ project.messageBus.syncPublisher(PROJECT_APPLICATION_IDS_CHANGED_TOPIC).applicationIdsChanged(newIds)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/logcat/testSrc/com/android/tools/idea/logcat/FakeProjectApplicationIdsProvider.kt b/logcat/testSrc/com/android/tools/idea/logcat/FakeProjectApplicationIdsProvider.kt
new file mode 100644
index 00000000000..5eefe6ba0e6
--- /dev/null
+++ b/logcat/testSrc/com/android/tools/idea/logcat/FakeProjectApplicationIdsProvider.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.logcat
+
+import com.android.annotations.concurrency.UiThread
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.Companion.PROJECT_APPLICATION_IDS_CHANGED_TOPIC
+import com.intellij.openapi.project.Project
+
+/** Test implementation of [ProjectApplicationIdsProvider] */
+internal class FakeProjectApplicationIdsProvider(
+ private val project: Project,
+ vararg initialValue: String,
+) : ProjectApplicationIdsProvider {
+ private var applicationIds = initialValue.toSet()
+
+ @UiThread
+ fun setApplicationIds(vararg value: String) {
+ val newIds = value.toSet()
+ if (applicationIds != newIds) {
+ applicationIds = newIds
+ project.messageBus.syncPublisher(PROJECT_APPLICATION_IDS_CHANGED_TOPIC).applicationIdsChanged(newIds)
+ }
+ }
+
+ override fun getPackageNames() = applicationIds
+}
diff --git a/logcat/testSrc/com/android/tools/idea/logcat/LogcatMainPanelTest.kt b/logcat/testSrc/com/android/tools/idea/logcat/LogcatMainPanelTest.kt
index 9b0dd3b4872..7044b37f79f 100644
--- a/logcat/testSrc/com/android/tools/idea/logcat/LogcatMainPanelTest.kt
+++ b/logcat/testSrc/com/android/tools/idea/logcat/LogcatMainPanelTest.kt
@@ -136,13 +136,14 @@ class LogcatMainPanelTest {
private val mockFoldingDetector = mock<FoldingDetector>()
private val fakeAdbSession = FakeAdbSession()
private val androidLogcatFormattingOptions = AndroidLogcatFormattingOptions()
+ private val project get() = projectRule.project
@Before
fun setUp() {
ApplicationManager.getApplication().replaceService(
AndroidLogcatFormattingOptions::class.java,
androidLogcatFormattingOptions,
- projectRule.project)
+ project)
}
@RunsInEdt
@@ -377,7 +378,7 @@ class LogcatMainPanelTest {
}
}
- projectRule.project.messageBus.syncPublisher(ClearLogcatListener.TOPIC).clearLogcat("device1")
+ project.messageBus.syncPublisher(ClearLogcatListener.TOPIC).clearLogcat("device1")
ConcurrencyUtil.awaitQuiescence(AndroidExecutors.getInstance().workerThreadExecutor as ThreadPoolExecutor, TIMEOUT_SEC, SECONDS)
runInEdtAndWait { }
@@ -399,7 +400,7 @@ class LogcatMainPanelTest {
}
}
- projectRule.project.messageBus.syncPublisher(ClearLogcatListener.TOPIC).clearLogcat("device2")
+ project.messageBus.syncPublisher(ClearLogcatListener.TOPIC).clearLogcat("device2")
ConcurrencyUtil.awaitQuiescence(AndroidExecutors.getInstance().workerThreadExecutor as ThreadPoolExecutor, TIMEOUT_SEC, SECONDS)
runInEdtAndWait { }
@@ -996,9 +997,9 @@ class LogcatMainPanelTest {
val testDevice = TestDevice("device1", DeviceState.ONLINE, 11, 30, "Google", "Pixel", "")
fakeAdbSession.deviceServices.setupCommandsForDevice(testDevice)
fakeAdbSession.hostServices.setDevices(testDevice)
- val fakePackageNamesProvider = FakePackageNamesProvider("myapp")
+ val fakePackageNamesProvider = FakeProjectApplicationIdsProvider(project, "myapp")
val logcatMainPanel = runInEdtAndGet {
- logcatMainPanel(adbSession = fakeAdbSession, packageNamesProvider = fakePackageNamesProvider).also {
+ logcatMainPanel(adbSession = fakeAdbSession, projectApplicationIdsProvider = fakePackageNamesProvider).also {
waitForCondition { it.getConnectedDevice() != null }
}
}
@@ -1028,6 +1029,38 @@ class LogcatMainPanelTest {
assertThat(AndroidDebugBridge.getDeviceChangeListenerCount() == 0)
}
+ @Test
+ fun projectApplicationIdsChange_withPackageMine_reloadsMessages() = runBlocking {
+ val fakeProjectApplicationIdsProvider = FakeProjectApplicationIdsProvider(project)
+ val logcatMainPanel = runInEdtAndGet {
+ logcatMainPanel(projectApplicationIdsProvider = fakeProjectApplicationIdsProvider)
+ }
+ logcatMainPanel.processMessages(listOf(
+ LogcatMessage(LogcatHeader(WARN, 1, 2, "app1", "", "tag1", Instant.ofEpochMilli(1000)), "message1"),
+ LogcatMessage(LogcatHeader(WARN, 1, 2, "app2", "", "tag2", Instant.ofEpochMilli(1000)), "message2"),
+ ))
+ runInEdtAndWait {
+ logcatMainPanel.setFilter("package:mine | tag:tag2")
+ }
+ waitForCondition {
+ logcatMainPanel.editor.document.text.trim() == """
+ 1970-01-01 04:00:01.000 1-2 tag2 app2 W message2
+ """.trimIndent()
+ }
+
+ runInEdtAndWait {
+ fakeProjectApplicationIdsProvider.setApplicationIds("app1")
+ }
+
+ ConcurrencyUtil.awaitQuiescence(AndroidExecutors.getInstance().workerThreadExecutor as ThreadPoolExecutor, TIMEOUT_SEC, SECONDS)
+ logcatMainPanel.messageProcessor.onIdle {
+ assertThat(logcatMainPanel.editor.document.text.trim()).isEqualTo("""
+ 1970-01-01 04:00:01.000 1-2 tag1 app1 W message1
+ 1970-01-01 04:00:01.000 1-2 tag2 app2 W message2
+ """.trimIndent())
+ }
+ }
+
private fun logcatMainPanel(
splitterPopupActionGroup: ActionGroup = EMPTY_GROUP,
logcatColors: LogcatColors = LogcatColors(),
@@ -1036,13 +1069,14 @@ class LogcatMainPanelTest {
androidProjectDetector: AndroidProjectDetector = FakeAndroidProjectDetector(true),
hyperlinkDetector: HyperlinkDetector? = null,
foldingDetector: FoldingDetector? = null,
- packageNamesProvider: PackageNamesProvider = FakePackageNamesProvider(),
+ projectApplicationIdsProvider: ProjectApplicationIdsProvider = FakeProjectApplicationIdsProvider(project),
adbSession: AdbSession = FakeAdbSession(),
logcatService: LogcatService = FakeLogcatService(),
zoneId: ZoneId = ZoneId.of("Asia/Yerevan"),
- ) =
- LogcatMainPanel(
- projectRule.project,
+ ): LogcatMainPanel {
+ project.replaceService(ProjectApplicationIdsProvider::class.java, projectApplicationIdsProvider, project)
+ return LogcatMainPanel(
+ project,
splitterPopupActionGroup,
logcatColors,
state,
@@ -1050,13 +1084,13 @@ class LogcatMainPanelTest {
androidProjectDetector,
hyperlinkDetector,
foldingDetector,
- packageNamesProvider,
adbSession,
logcatService,
zoneId,
).also {
- Disposer.register(projectRule.project, it)
+ Disposer.register(project, it)
}
+ }
}
private fun LogcatMessage.length() = FormattingOptions().getHeaderWidth() + message.length
diff --git a/logcat/testSrc/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImplTest.kt b/logcat/testSrc/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImplTest.kt
new file mode 100644
index 00000000000..f2b378a0666
--- /dev/null
+++ b/logcat/testSrc/com/android/tools/idea/logcat/ProjectApplicationIdsProviderImplTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 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.logcat
+
+import com.android.testutils.MockitoKt.mock
+import com.android.testutils.MockitoKt.whenever
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.Companion.PROJECT_APPLICATION_IDS_CHANGED_TOPIC
+import com.android.tools.idea.logcat.ProjectApplicationIdsProvider.ProjectApplicationIdsListener
+import com.android.tools.idea.model.AndroidModel
+import com.android.tools.idea.model.TestAndroidModel
+import com.android.tools.idea.projectsystem.PROJECT_SYSTEM_SYNC_TOPIC
+import com.android.tools.idea.projectsystem.ProjectSystemSyncManager.SyncResult.SUCCESS
+import com.android.tools.idea.testing.registerServiceInstance
+import com.google.common.truth.Truth.assertThat
+import com.intellij.facet.ProjectFacetManager
+import com.intellij.mock.MockModule
+import com.intellij.openapi.util.Disposer
+import com.intellij.testFramework.ProjectRule
+import com.intellij.testFramework.RuleChain
+import org.jetbrains.android.facet.AndroidFacet
+import org.jetbrains.android.facet.AndroidFacetConfiguration
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * Tests for [ProjectApplicationIdsProviderImpl]
+ */
+class ProjectApplicationIdsProviderImplTest {
+ private val projectRule = ProjectRule()
+
+ @get:Rule
+ val rule = RuleChain(projectRule)
+
+ private val project get() = projectRule.project
+ private val mockProjectFacetManager = mock<ProjectFacetManager>()
+
+ @Before
+ fun setUp() {
+ project.registerServiceInstance(ProjectFacetManager::class.java, mockProjectFacetManager, project)
+ }
+
+ @Test
+ fun initialize_loadsApplicationIds() {
+ val facet1 = mockFacet("app1")
+ val facet2 = mockFacet("app2", "app3")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet1, facet2))
+
+ val projectApplicationIdsProviderImpl = ProjectApplicationIdsProviderImpl(project)
+
+ assertThat(projectApplicationIdsProviderImpl.getPackageNames()).containsExactly(
+ "app1",
+ "app2",
+ "app3",
+ )
+ }
+
+ @Test
+ fun syncEnds_reloadsApplicationIds() {
+ val facet1 = mockFacet("app1")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet1))
+ val projectApplicationIdsProviderImpl = ProjectApplicationIdsProviderImpl(project)
+
+ val facet2 = mockFacet("app2", "app3")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet1, facet2))
+ project.messageBus.syncPublisher(PROJECT_SYSTEM_SYNC_TOPIC).syncEnded(SUCCESS)
+
+ assertThat(projectApplicationIdsProviderImpl.getPackageNames()).containsExactly(
+ "app1",
+ "app2",
+ "app3",
+ )
+ }
+
+ @Test
+ fun syncEnds_applicationIdsChange_notifies() {
+ val facet1 = mockFacet("app1")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet1))
+ ProjectApplicationIdsProviderImpl(project)
+ var notified = false
+ project.messageBus.connect(project).subscribe(PROJECT_APPLICATION_IDS_CHANGED_TOPIC, ProjectApplicationIdsListener {
+ notified = true
+ })
+
+ val facet2 = mockFacet("app2")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet2))
+ project.messageBus.syncPublisher(PROJECT_SYSTEM_SYNC_TOPIC).syncEnded(SUCCESS)
+
+ assertThat(notified).isTrue()
+ }
+
+ @Test
+ fun syncEnds_applicationIdsDoNotChange_doesNotNotifies() {
+ val facet1 = mockFacet("app1")
+ whenever(mockProjectFacetManager.getFacets(AndroidFacet.ID)).thenReturn(listOf(facet1))
+ ProjectApplicationIdsProviderImpl(project)
+ var notified = false
+ project.messageBus.connect(project).subscribe(PROJECT_APPLICATION_IDS_CHANGED_TOPIC, ProjectApplicationIdsListener {
+ notified = true
+ })
+
+ project.messageBus.syncPublisher(PROJECT_SYSTEM_SYNC_TOPIC).syncEnded(SUCCESS)
+
+ assertThat(notified).isFalse()
+ }
+
+ private fun mockFacet(vararg applicationIds: String): AndroidFacet {
+ val facet = AndroidFacet(MockModule(project), "ProjectApplicationIdsProviderImplTest:Facet", AndroidFacetConfiguration())
+ Disposer.register(project, facet)
+ AndroidModel.set(facet, TestAndroidModel(allApplicationIds = applicationIds.toSet()))
+ return facet
+ }
+} \ No newline at end of file