Show a warning for projects with kts build files
Android Studio is able to open projects with kts Gradle build files but
some functionality is not available for them. This CL causes a warning
to appear every time a project with kts build files is opened or the
first time it is synced and it contains a kts file.
Test: New tests added to confirm warning is shown when appropriate.
Bug: 130226195
Change-Id: Id2e3bd6103364499e8351ca083a623b36fb384f5
diff --git a/android/src/META-INF/android-plugin.xml b/android/src/META-INF/android-plugin.xml
index 567a2db..a782204 100644
--- a/android/src/META-INF/android-plugin.xml
+++ b/android/src/META-INF/android-plugin.xml
@@ -576,6 +576,7 @@
<projectService serviceImplementation="com.android.tools.idea.gradle.project.sync.GradleFiles"/>
<projectService serviceImplementation="com.android.tools.idea.gradle.project.build.GradleBuildState"/>
<projectService serviceImplementation="com.android.tools.idea.project.AndroidNotification"/>
+ <projectService serviceImplementation="com.android.tools.idea.project.AndroidKtsSupportNotification"/>
<projectService serviceImplementation="com.android.tools.idea.project.IndexingSuspender"/>
<projectService serviceImplementation="com.android.tools.idea.gradle.project.sync.setup.module.common.DependencySetupIssues"/>
<projectService serviceImplementation="com.android.tools.idea.gradle.project.sync.messages.GradleSyncMessages"/>
@@ -856,6 +857,7 @@
<postSyncProjectSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.project.SdkToolsVersionSetupStep"/>
<postSyncProjectSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.project.ExpiredPreviewBuildSetupStep"/>
<postSyncProjectSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.project.IgnoredBuildScriptSetupStep"/>
+ <postSyncProjectSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.project.GradleKtsBuildFilesWarningStep"/>
<postSyncModuleSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.module.TestArtifactSearchScopeSetupStep"/>
<postSyncModuleSetupStep implementation="com.android.tools.idea.gradle.project.sync.setup.post.module.AndroidRunConfigurationSetupStep"/>
diff --git a/android/src/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStep.java b/android/src/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStep.java
new file mode 100644
index 0000000..9da01a4
--- /dev/null
+++ b/android/src/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStep.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.gradle.project.sync.setup.post.project;
+
+import com.android.tools.idea.gradle.project.sync.setup.post.ProjectSetupStep;
+import com.android.tools.idea.gradle.util.GradleUtil;
+import com.android.tools.idea.project.AndroidKtsSupportNotification;
+import com.google.common.annotations.VisibleForTesting;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class GradleKtsBuildFilesWarningStep extends ProjectSetupStep {
+ @Override
+ public void setUpProject(@NotNull Project project, @Nullable ProgressIndicator indicator) {
+ doSetUpProject(project, GradleUtil.hasKtsBuildFiles(project));
+ }
+
+ @VisibleForTesting
+ void doSetUpProject(@NotNull Project project, boolean hasKts) {
+ if (hasKts) {
+ AndroidKtsSupportNotification.getInstance(project).showWarningIfNotShown();
+ }
+ }
+}
diff --git a/android/src/com/android/tools/idea/gradle/util/GradleUtil.java b/android/src/com/android/tools/idea/gradle/util/GradleUtil.java
index 87a40bb..f57fdfd 100644
--- a/android/src/com/android/tools/idea/gradle/util/GradleUtil.java
+++ b/android/src/com/android/tools/idea/gradle/util/GradleUtil.java
@@ -1030,6 +1030,10 @@
return result;
}
+ public static boolean hasKtsBuildFiles(@NotNull Project project) {
+ return projectBuildFilesTypes(project).contains(DOT_KTS);
+ }
+
private static void addBuildFileType(@NotNull HashSet<String> result, @Nullable VirtualFile buildFile) {
if (buildFile != null) {
String buildFileExtension = buildFile.getExtension();
diff --git a/android/src/com/android/tools/idea/project/AndroidKtsSupportNotification.java b/android/src/com/android/tools/idea/project/AndroidKtsSupportNotification.java
new file mode 100644
index 0000000..1fdd0f0
--- /dev/null
+++ b/android/src/com/android/tools/idea/project/AndroidKtsSupportNotification.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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.project;
+
+import static com.intellij.notification.NotificationDisplayType.NONE;
+import static com.intellij.notification.NotificationType.WARNING;
+
+import com.android.tools.idea.project.hyperlink.NotificationHyperlink;
+import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationsConfiguration;
+import com.intellij.notification.impl.NotificationSettings;
+import com.intellij.notification.impl.NotificationsConfigurationImpl;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class AndroidKtsSupportNotification {
+ public static final String KTS_WARNING_MSG = "This project uses Gradle KTS build files which are not fully supported. Some functions may be affected.";
+ public static final String KTS_WARNING_TITLE = "Gradle KTS Build Files";
+ public static final NotificationGroup KTS_NOTIFICATION_GROUP = NotificationGroup.balloonGroup("Gradle KTS build files");
+
+ @NotNull private final Project myProject;
+ private boolean alreadyShown;
+
+ @NotNull
+ public static AndroidKtsSupportNotification getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, AndroidKtsSupportNotification.class);
+ }
+
+ public AndroidKtsSupportNotification(@NotNull Project project) {
+ myProject = project;
+ alreadyShown = false;
+ }
+
+ public void showWarningIfNotShown() {
+ if (!alreadyShown) {
+ AndroidNotification.getInstance(myProject).showBalloon(KTS_WARNING_TITLE, KTS_WARNING_MSG, WARNING, KTS_NOTIFICATION_GROUP,
+ new DisableAndroidKtsNotificationHyperlink());
+ // Make sure that it was displayed, otherwise notification will not show until project is reopened.
+ NotificationSettings settings = NotificationsConfigurationImpl.getSettings(KTS_NOTIFICATION_GROUP.getDisplayId());
+ alreadyShown = settings.getDisplayType() != NONE || settings.isShouldLog();
+ }
+ }
+
+ public static class DisableAndroidKtsNotificationHyperlink extends NotificationHyperlink {
+
+ protected DisableAndroidKtsNotificationHyperlink() {
+ super("disableKtsNotification", "Disable this warning");
+ }
+
+ @Override
+ protected void execute(@NotNull Project project) {
+ NotificationsConfiguration.getNotificationsConfiguration().changeSettings(KTS_NOTIFICATION_GROUP.getDisplayId(), NONE, false, false);
+ }
+ }
+}
diff --git a/android/testSrc/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStepTest.java b/android/testSrc/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStepTest.java
new file mode 100644
index 0000000..8841a04
--- /dev/null
+++ b/android/testSrc/com/android/tools/idea/gradle/project/sync/setup/post/project/GradleKtsBuildFilesWarningStepTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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.gradle.project.sync.setup.post.project;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.android.tools.idea.project.AndroidKtsSupportNotification;
+import com.android.tools.idea.testing.IdeComponents;
+import com.intellij.testFramework.IdeaTestCase;
+import org.jetbrains.annotations.NotNull;
+import org.mockito.Mock;
+
+/**
+ * Tests for {@link GradleKtsBuildFilesWarningStep}
+ */
+public class GradleKtsBuildFilesWarningStepTest extends IdeaTestCase {
+
+ @Mock private AndroidKtsSupportNotification myNotification;
+ @NotNull private GradleKtsBuildFilesWarningStep myWarningStep = new GradleKtsBuildFilesWarningStep();
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ initMocks(this);
+ new IdeComponents(myProject).replaceProjectService(AndroidKtsSupportNotification.class, myNotification);
+ }
+
+ /**
+ * Check that a warning is created when the project uses kts build files
+ */
+ public void testDoSetUpProjectWithKts() {
+ myWarningStep.doSetUpProject(myProject, true);
+ verify(myNotification).showWarningIfNotShown();
+ }
+
+ /**
+ * Check that a warning is *NOT* created when the project does not use kts build files
+ */
+ public void testDoSetUpProjectWithoutKts() {
+ myWarningStep.doSetUpProject(myProject, false);
+ verify(myNotification, never()).showWarningIfNotShown();
+ }
+}
diff --git a/android/testSrc/com/android/tools/idea/project/AndroidKtsSupportNotificationTest.java b/android/testSrc/com/android/tools/idea/project/AndroidKtsSupportNotificationTest.java
new file mode 100644
index 0000000..a44f3db
--- /dev/null
+++ b/android/testSrc/com/android/tools/idea/project/AndroidKtsSupportNotificationTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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.project;
+
+import static com.android.tools.idea.project.AndroidKtsSupportNotification.KTS_NOTIFICATION_GROUP;
+import static com.android.tools.idea.project.AndroidKtsSupportNotification.KTS_WARNING_MSG;
+import static com.android.tools.idea.project.AndroidKtsSupportNotification.KTS_WARNING_TITLE;
+import static com.google.common.truth.Truth.assertThat;
+import static com.intellij.notification.NotificationType.WARNING;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.android.tools.idea.project.AndroidKtsSupportNotification.DisableAndroidKtsNotificationHyperlink;
+import com.android.tools.idea.project.hyperlink.NotificationHyperlink;
+import com.android.tools.idea.testing.IdeComponents;
+import com.intellij.testFramework.IdeaTestCase;
+import java.util.List;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+/**
+ * Tests for {@link AndroidKtsSupportNotification}
+ */
+public class AndroidKtsSupportNotificationTest extends IdeaTestCase {
+ @Mock private AndroidNotification myAndroidNotification;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ initMocks(this);
+ new IdeComponents(myProject).replaceProjectService(AndroidNotification.class, myAndroidNotification);
+ }
+
+ /**
+ * Verify an AndroidNotification is created with the expected parameters
+ */
+ public void testShowWarningIfNotShown() {
+ AndroidKtsSupportNotification myKtsNotification = new AndroidKtsSupportNotification(myProject);
+ myKtsNotification.showWarningIfNotShown();
+ verifyBalloon();
+ }
+
+ /**
+ * Verify that warning is generated only once even when called multiple times
+ */
+ public void testShowWarningIfNotShownTwice() {
+ AndroidKtsSupportNotification myKtsNotification = new AndroidKtsSupportNotification(myProject);
+ myKtsNotification.showWarningIfNotShown();
+ myKtsNotification.showWarningIfNotShown();
+ verifyBalloon();
+ }
+
+ private void verifyBalloon() {
+ ArgumentCaptor<NotificationHyperlink> hyperlinkCaptor = ArgumentCaptor.forClass(NotificationHyperlink.class);
+ verify(myAndroidNotification, times(1)).showBalloon(same(KTS_WARNING_TITLE), same(KTS_WARNING_MSG), same(WARNING), same(KTS_NOTIFICATION_GROUP), hyperlinkCaptor.capture());
+ List<NotificationHyperlink> hyperlinks = hyperlinkCaptor.getAllValues();
+ assertThat(hyperlinks).hasSize(1);
+ assertThat(hyperlinks.get(0)).isInstanceOf(DisableAndroidKtsNotificationHyperlink.class);
+ }
+}