diff options
4 files changed, 115 insertions, 21 deletions
diff --git a/android-test-framework/testSrc/com/android/tools/idea/rendering/RenderTestUtil.java b/android-test-framework/testSrc/com/android/tools/idea/rendering/RenderTestUtil.java index 1291267c2d2..ca1ae74ea6b 100644 --- a/android-test-framework/testSrc/com/android/tools/idea/rendering/RenderTestUtil.java +++ b/android-test-framework/testSrc/com/android/tools/idea/rendering/RenderTestUtil.java @@ -102,7 +102,7 @@ public class RenderTestUtil { } @NotNull - private static Device findDeviceById(ConfigurationManager manager, String id) { + public static Device findDeviceById(ConfigurationManager manager, String id) { for (Device device : manager.getDevices()) { if (device.getId().equals(id)) { return device; diff --git a/designer/src/com/android/tools/idea/common/error/DesignerCommonIssueNode.kt b/designer/src/com/android/tools/idea/common/error/DesignerCommonIssueNode.kt index 5220c161d57..2c66683f39d 100644 --- a/designer/src/com/android/tools/idea/common/error/DesignerCommonIssueNode.kt +++ b/designer/src/com/android/tools/idea/common/error/DesignerCommonIssueNode.kt @@ -15,6 +15,7 @@ */ package com.android.tools.idea.common.error +import com.android.ide.common.rendering.HardwareConfigHelper import com.android.tools.idea.common.surface.navigateToComponent import com.android.tools.idea.uibuilder.visual.ConfigurationSet import com.android.tools.idea.uibuilder.visual.VisualizationToolWindowFactory @@ -292,15 +293,19 @@ class VisualLintIssueNode(private val visualLintIssue: VisualLintRenderIssue, pa val targetComponent = visualLintIssue.components .filterNot { it.isVisualLintErrorSuppressed(visualLintIssue.type) } .firstOrNull() - val selectWindowSizeNavigatable = SelectWindowSizeDevicesNavigatable(project) + val openLayoutValidationNavigatable = if (HardwareConfigHelper.isWear(visualLintIssue.models.firstOrNull()?.configuration?.device)) { + SelectWearDevicesNavigatable(project) + } else { + SelectWindowSizeDevicesNavigatable(project) + } if (targetComponent == null) { - return selectWindowSizeNavigatable + return openLayoutValidationNavigatable } return object : Navigatable { override fun navigate(requestFocus: Boolean) { navigateToComponent(targetComponent, true) - selectWindowSizeNavigatable.navigate(requestFocus) + openLayoutValidationNavigatable.navigate(requestFocus) } override fun canNavigate(): Boolean = project != null override fun canNavigateToSource(): Boolean = project != null @@ -309,9 +314,14 @@ class VisualLintIssueNode(private val visualLintIssue: VisualLintRenderIssue, pa } @VisibleForTesting -class SelectWindowSizeDevicesNavigatable(project: Project): Navigatable { +class SelectWindowSizeDevicesNavigatable(project: Project): OpenLayoutValidationNavigatable(project, ConfigurationSet.WindowSizeDevices) + +@VisibleForTesting +class SelectWearDevicesNavigatable(project: Project): OpenLayoutValidationNavigatable(project, ConfigurationSet.WearDevices) - private val task = { VisualizationToolWindowFactory.openAndSetConfigurationSet(project, ConfigurationSet.WindowSizeDevices) } +@VisibleForTesting +open class OpenLayoutValidationNavigatable(project: Project, configurationSetToSelect: ConfigurationSet) : Navigatable { + private val task = { VisualizationToolWindowFactory.openAndSetConfigurationSet(project, configurationSetToSelect) } override fun navigate(requestFocus: Boolean) { task() diff --git a/designer/src/com/android/tools/idea/uibuilder/visual/visuallint/VisualLintService.kt b/designer/src/com/android/tools/idea/uibuilder/visual/visuallint/VisualLintService.kt index bb5cbff6b44..4a710daf24e 100644 --- a/designer/src/com/android/tools/idea/uibuilder/visual/visuallint/VisualLintService.kt +++ b/designer/src/com/android/tools/idea/uibuilder/visual/visuallint/VisualLintService.kt @@ -15,6 +15,7 @@ */ package com.android.tools.idea.uibuilder.visual.visuallint +import com.android.ide.common.rendering.HardwareConfigHelper import com.android.tools.idea.common.error.IssueModel import com.android.tools.idea.common.model.ModelListener import com.android.tools.idea.common.model.NlModel @@ -25,6 +26,7 @@ import com.android.tools.idea.rendering.RenderResult import com.android.tools.idea.rendering.RenderService import com.android.tools.idea.rendering.errors.ui.RenderErrorModel import com.android.tools.idea.uibuilder.scene.NlModelHierarchyUpdater.updateHierarchy +import com.android.tools.idea.uibuilder.visual.WearDeviceModelsProvider import com.android.tools.idea.uibuilder.visual.WindowSizeModelsProvider import com.android.tools.idea.uibuilder.visual.analytics.VisualLintUsageTracker import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.AtfAnalyzer @@ -36,6 +38,7 @@ import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.LocaleAnalyz import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.LongTextAnalyzer import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.OverlapAnalyzer import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.TextFieldSizeAnalyzer +import com.android.tools.idea.uibuilder.visual.visuallint.analyzers.WearMarginAnalyzer import com.google.common.annotations.VisibleForTesting import com.intellij.codeInsight.daemon.HighlightDisplayKey import com.intellij.codeInspection.InspectionProfile @@ -74,8 +77,10 @@ class VisualLintService(project: Project) { /** Default issue provider for Visual Lint Service. */ val issueProvider = VisualLintIssueProvider(project) - private val basicAnalyzers = listOf(BoundsAnalyzer, BottomNavAnalyzer, BottomAppBarAnalyzer, TextFieldSizeAnalyzer, - OverlapAnalyzer, LongTextAnalyzer, ButtonSizeAnalyzer) + private val basicAnalyzers = listOf(BoundsAnalyzer, OverlapAnalyzer) + private val adaptiveAnalyzers = listOf(BottomNavAnalyzer, BottomAppBarAnalyzer, TextFieldSizeAnalyzer, + LongTextAnalyzer, ButtonSizeAnalyzer) + private val wearAnalyzers = listOf(WearMarginAnalyzer) private val ignoredTypes: MutableList<VisualLintErrorType> @@ -136,8 +141,11 @@ class VisualLintService(project: Project) { } displayingModel.addListener(listener) try { - val modelsToAnalyze = WindowSizeModelsProvider.createNlModels(displayingModel, displayingModel.file, - displayingModel.facet) + val modelsToAnalyze = if (HardwareConfigHelper.isWear(displayingModel.configuration.device)) { + WearDeviceModelsProvider.createNlModels(displayingModel, displayingModel.file, displayingModel.facet) + } else { + WindowSizeModelsProvider.createNlModels(displayingModel, displayingModel.file, displayingModel.facet) + } val latch = CountDownLatch(modelsToAnalyze.size) for (model in modelsToAnalyze) { inflate(model).handleAsync({ result, _ -> @@ -165,17 +173,30 @@ class VisualLintService(project: Project) { baseConfigIssues: VisualLintBaseConfigIssues, tracker: VisualLintUsageTracker, runningInBackground: Boolean = false) { - basicAnalyzers.filter { !ignoredTypes.contains(it.type) }.forEach { - val issues = it.analyze(result, model, tracker, runningInBackground) - issueProvider.addAllIssues(it.type, issues) - } - if (VisualLintErrorType.LOCALE_TEXT !in ignoredTypes) { - LocaleAnalyzer(baseConfigIssues).let { - issueProvider.addAllIssues(it.type, it.analyze(result, model, tracker, runningInBackground)) + runAnalyzers(basicAnalyzers, result, model, tracker, runningInBackground) + if (HardwareConfigHelper.isWear(model.configuration.device)) { + runAnalyzers(wearAnalyzers, result, model, tracker, runningInBackground) + } else { + runAnalyzers(adaptiveAnalyzers, result, model, tracker, runningInBackground) + if (VisualLintErrorType.LOCALE_TEXT !in ignoredTypes) { + LocaleAnalyzer(baseConfigIssues).let { + issueProvider.addAllIssues(it.type, it.analyze(result, model, tracker, runningInBackground)) + } + } + if (StudioFlags.NELE_ATF_IN_VISUAL_LINT.get() && VisualLintErrorType.ATF !in ignoredTypes) { + AtfAnalyzer.analyze(result, model, issueProvider, runningInBackground) } } - if (StudioFlags.NELE_ATF_IN_VISUAL_LINT.get() && VisualLintErrorType.ATF !in ignoredTypes) { - AtfAnalyzer.analyze(result, model, issueProvider, runningInBackground) + } + + private fun runAnalyzers(analyzers: List<VisualLintAnalyzer>, + result: RenderResult, + model: NlModel, + tracker: VisualLintUsageTracker, + runningInBackground: Boolean) { + analyzers.filter { !ignoredTypes.contains(it.type) }.forEach { + val issues = it.analyze(result, model, tracker, runningInBackground) + issueProvider.addAllIssues(it.type, issues) } } } diff --git a/designer/testSrc/com/android/tools/idea/common/error/VisualLintIssueNodeTest.kt b/designer/testSrc/com/android/tools/idea/common/error/VisualLintIssueNodeTest.kt index 519112c9d47..91451a733ba 100644 --- a/designer/testSrc/com/android/tools/idea/common/error/VisualLintIssueNodeTest.kt +++ b/designer/testSrc/com/android/tools/idea/common/error/VisualLintIssueNodeTest.kt @@ -18,6 +18,8 @@ package com.android.tools.idea.common.error import com.android.SdkConstants import com.android.tools.idea.common.fixtures.ComponentDescriptor import com.android.tools.idea.common.model.NlComponent +import com.android.tools.idea.configurations.ConfigurationManager +import com.android.tools.idea.rendering.RenderTestUtil import com.android.tools.idea.testing.AndroidProjectRule import com.android.tools.idea.testing.onEdt import com.android.tools.idea.uibuilder.NlModelBuilderUtil @@ -36,12 +38,11 @@ import org.junit.Rule import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -import kotlin.test.assertNull class VisualLintIssueNodeTest { @JvmField @Rule - val rule = AndroidProjectRule.inMemory().onEdt() + val rule = AndroidProjectRule.withSdk().onEdt() @RunsInEdt @Test @@ -107,6 +108,68 @@ class VisualLintIssueNodeTest { val node = VisualLintIssueNode(issue, CommonIssueTestParentNode(rule.projectRule.project)) assertInstanceOf<SelectWindowSizeDevicesNavigatable>(node.getNavigatable()) } + + @RunsInEdt + @Test + fun testNavigatableForWear() { + val configurationManager = ConfigurationManager.getOrCreateInstance(rule.projectRule.module) + val model = NlModelBuilderUtil.model( + rule.projectRule, + "layout", + "layout.xml", + ComponentDescriptor(SdkConstants.FRAME_LAYOUT) + .withBounds(0, 0, 1000, 1000) + .matchParentWidth() + .matchParentHeight() + .children(ComponentDescriptor(SdkConstants.TEXT_VIEW) + .width("100dp") + .height("20dp") + ) + ).setDevice(RenderTestUtil.findDeviceById(configurationManager, "wearos_rect")).build() + + val issue = createTestVisualLintRenderIssue(VisualLintErrorType.WEAR_MARGIN, model.components.first().children) + val node = VisualLintIssueNode(issue, CommonIssueTestParentNode(rule.projectRule.project)) + val navigation = node.getNavigatable() + assertNotNull(navigation) + + // This navigation should open Validation Tool and set configuration set to ConfigurationSet.WearDevices + val toolManager = VisualizationTestToolWindowManager(rule.project, rule.fixture.testRootDisposable) + rule.projectRule.replaceProjectService(ToolWindowManager::class.java, toolManager) + val toolWindow = ToolWindowManager.getInstance(rule.project).getToolWindow(VisualizationToolWindowFactory.TOOL_WINDOW_ID)!! + TestVisualizationContentProvider.createVisualizationForm(rule.project, toolWindow) + toolWindow.isAvailable = true + + val content = VisualizationToolWindowFactory.getVisualizationContent(rule.project)!! + content.setConfigurationSet(ConfigurationSet.LargeFont) + + navigation.navigate(false) + assertEquals(ConfigurationSet.WearDevices, content.getConfigurationSet()) + } + + @RunsInEdt + @Test + fun testNotNavigateToComponentWhenSuppressedForWear() { + val configurationManager = ConfigurationManager.getOrCreateInstance(rule.projectRule.module) + val errorType = VisualLintErrorType.WEAR_MARGIN + val model = NlModelBuilderUtil.model( + rule.projectRule, + "layout", + "layout.xml", + ComponentDescriptor(SdkConstants.FRAME_LAYOUT) + .withBounds(0, 0, 1000, 1000) + .matchParentWidth() + .matchParentHeight() + .children(ComponentDescriptor(SdkConstants.TEXT_VIEW) + .width("100dp") + .height("20dp") + .withAttribute(SdkConstants.TOOLS_URI, SdkConstants.ATTR_IGNORE, errorType.ignoredAttributeValue) + ) + ).setDevice(RenderTestUtil.findDeviceById(configurationManager, "wearos_rect")).build() + + val issue = createTestVisualLintRenderIssue(errorType, model.components.first().children) + val node = VisualLintIssueNode(issue, CommonIssueTestParentNode(rule.projectRule.project)) + assertInstanceOf<SelectWearDevicesNavigatable>(node.getNavigatable()) + } } private fun createTestVisualLintRenderIssue(type: VisualLintErrorType, components: MutableList<NlComponent>) : VisualLintRenderIssue { |