Java tutorial
/* * Copyright (C) 2015 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.startup; import com.android.tools.analytics.UsageTracker; import com.android.tools.idea.actions.CreateClassAction; import com.android.tools.idea.actions.MakeIdeaModuleAction; import com.android.tools.idea.monitor.tool.AndroidMonitorToolWindowFactory; import com.android.tools.idea.run.editor.ProfilerState; import com.android.tools.idea.stats.AndroidStudioUsageTracker; import com.android.tools.idea.testartifacts.junit.*; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.intellij.concurrency.JobScheduler; import com.intellij.execution.actions.RunConfigurationProducer; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.junit.JUnitConfigurationProducer; import com.intellij.execution.junit.JUnitConfigurationType; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.lang.injection.MultiHostInjector; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.HighlighterColors; import com.intellij.openapi.editor.XmlHighlighterColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurableEP; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; import com.intellij.openapi.roots.OrderEnumerationHandler; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; import icons.AndroidIcons; import org.intellij.plugins.intelliLang.inject.groovy.GrConcatenationInjector; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.execution.GradleOrderEnumeratorHandler; import java.io.File; import java.util.List; import static com.android.SdkConstants.EXT_JAR; import static com.android.tools.idea.gradle.util.AndroidStudioPreferences.cleanUpPreferences; import static com.android.tools.idea.startup.Actions.hideAction; import static com.android.tools.idea.startup.Actions.replaceAction; import static com.intellij.openapi.actionSystem.IdeActions.*; import static com.intellij.openapi.options.Configurable.APPLICATION_CONFIGURABLE; import static com.intellij.openapi.util.io.FileUtil.*; import static com.intellij.openapi.util.io.FileUtilRt.getExtension; import static com.intellij.openapi.util.text.StringUtil.isEmpty; /** * Performs Android Studio specific initialization tasks that are build-system-independent. * <p> * <strong>Note:</strong> Do not add any additional tasks unless it is proven that the tasks are common to all IDEs. Use * {@link GradleSpecificInitializer} instead. * </p> */ public class AndroidStudioInitializer implements Runnable { private static final Logger LOG = Logger.getInstance(AndroidStudioInitializer.class); private static final List<String> IDE_SETTINGS_TO_REMOVE = Lists.newArrayList( "org.jetbrains.plugins.javaFX.JavaFxSettingsConfigurable", "org.intellij.plugins.xpathView.XPathConfigurable", "org.intellij.lang.xpath.xslt.impl.XsltConfigImpl$UIImpl"); @Override public void run() { checkInstallation(); removeIdeSettings(); setUpNewFilePopupActions(); setUpMakeActions(); disableGroovyLanguageInjection(); setUpNewProjectActions(); setUpExperimentalFeatures(); setupAnalytics(); disableGradleOrderEnumeratorHandler(); disableIdeaJUnitConfigurations(); // Modify built-in "Default" color scheme to remove background from XML tags. // "Darcula" and user schemes will not be touched. EditorColorsScheme colorsScheme = EditorColorsManager.getInstance() .getScheme(EditorColorsScheme.DEFAULT_SCHEME_NAME); TextAttributes textAttributes = colorsScheme.getAttributes(HighlighterColors.TEXT); TextAttributes xmlTagAttributes = colorsScheme.getAttributes(XmlHighlighterColors.XML_TAG); xmlTagAttributes.setBackgroundColor(textAttributes.getBackgroundColor()); /* Causes IDE startup failure (from the command line) Caused by: java.lang.IllegalAccessError: tried to access class com.intellij.ui.tabs.FileColorConfiguration from class com.intellij.ui.tabs.FileColorConfigurationUtil at com.intellij.ui.tabs.FileColorConfigurationUtil.createFileColorConfigurationIfNotExist(FileColorConfigurationUtil.java:37) at com.intellij.ui.tabs.FileColorConfigurationUtil.createAndroidTestFileColorConfigurationIfNotExist(FileColorConfigurationUtil.java:28) at com.android.tools.idea.startup.AndroidStudioInitializer.run(AndroidStudioInitializer.java:90) FileColorConfigurationUtil.createAndroidTestFileColorConfigurationIfNotExist(ProjectManager.getInstance().getDefaultProject()); */ } /* * sets up collection of Android Studio specific analytics. */ private static void setupAnalytics() { AndroidStudioUsageTracker.setup(JobScheduler.getScheduler()); ApplicationInfo application = ApplicationInfo.getInstance(); UsageTracker.getInstance().setVersion(application.getStrictVersion()); } private static void setUpExperimentalFeatures() { if (System.getProperty(ProfilerState.ENABLE_EXPERIMENTAL_PROFILING) != null) { ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerAdapter() { @Override public void projectOpened(final Project project) { StartupManager.getInstance(project).runWhenProjectIsInitialized(() -> { ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); ToolWindow toolWindow = toolWindowManager.registerToolWindow( AndroidMonitorToolWindowFactory.ID, false, ToolWindowAnchor.BOTTOM, project, true); toolWindow.setIcon(AndroidIcons.AndroidToolWindow); new AndroidMonitorToolWindowFactory().createToolWindowContent(project, toolWindow); toolWindow.show(null); }); } }); } } private static void checkInstallation() { String studioHome = PathManager.getHomePath(); if (isEmpty(studioHome)) { LOG.info("Unable to find Studio home directory"); return; } File studioHomePath = new File(toSystemDependentName(studioHome)); if (!studioHomePath.isDirectory()) { LOG.info(String.format("The path '%1$s' does not belong to an existing directory", studioHomePath.getPath())); return; } File androidPluginLibFolderPath = new File(studioHomePath, join("plugins", "android", "lib")); if (!androidPluginLibFolderPath.isDirectory()) { LOG.info(String.format("The path '%1$s' does not belong to an existing directory", androidPluginLibFolderPath.getPath())); return; } // Look for signs that the installation is corrupt due to improper updates (typically unzipping on top of previous install) // which doesn't delete files that have been removed or renamed String cause = null; File[] children = notNullize(androidPluginLibFolderPath.listFiles()); if (hasMoreThanOneBuilderModelFile(children)) { cause = "(Found multiple versions of builder-model-*.jar in plugins/android/lib.)"; } else if (new File(studioHomePath, join("plugins", "android-designer")).exists()) { cause = "(Found plugins/android-designer which should not be present.)"; } if (cause != null) { String msg = "Your Android Studio installation is corrupt and will not work properly.\n" + cause + "\n" + "This usually happens if Android Studio is extracted into an existing older version.\n\n" + "Please reinstall (and make sure the new installation directory is empty first.)"; String title = "Corrupt Installation"; int option = Messages.showDialog(msg, title, new String[] { "Quit", "Proceed Anyway" }, 0, Messages.getErrorIcon()); if (option == 0) { ApplicationManagerEx.getApplicationEx().exit(); } } } @VisibleForTesting static boolean hasMoreThanOneBuilderModelFile(@NotNull File[] libraryFiles) { int builderModelFileCount = 0; for (File file : libraryFiles) { String fileName = file.getName(); if (fileName.startsWith("builder-model-") && EXT_JAR.equals(getExtension(fileName))) { if (++builderModelFileCount > 1) { return true; } } } return false; } private static void removeIdeSettings() { try { ExtensionPoint<ConfigurableEP<Configurable>> ideConfigurable = Extensions.getRootArea() .getExtensionPoint(APPLICATION_CONFIGURABLE); cleanUpPreferences(ideConfigurable, IDE_SETTINGS_TO_REMOVE); } catch (Throwable e) { LOG.info("Failed to clean up IDE preferences", e); } } // Remove popup actions that we don't use private static void setUpNewFilePopupActions() { hideAction("NewHtmlFile"); hideAction("NewPackageInfo"); // Hide designer actions hideAction("NewForm"); hideAction("NewDialog"); hideAction("NewFormSnapshot"); // Hide individual actions that aren't part of a group hideAction("Groovy.NewClass"); hideAction("Groovy.NewScript"); } // The original actions will be visible only on plain IDEA projects. private static void setUpMakeActions() { // 'Build' > 'Make Project' action hideAction("CompileDirty"); // 'Build' > 'Make Modules' action // We cannot simply hide this action, because of a NPE. replaceAction(ACTION_MAKE_MODULE, new MakeIdeaModuleAction()); // 'Build' > 'Rebuild' action hideAction(ACTION_COMPILE_PROJECT); // 'Build' > 'Compile Modules' action hideAction(ACTION_COMPILE); } // Fix https://code.google.com/p/android/issues/detail?id=201624 private static void disableGroovyLanguageInjection() { ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerAdapter() { @Override public void projectOpened(@NotNull Project project) { ExtensionPoint<MultiHostInjector> extensionPoint = Extensions.getArea(project) .getExtensionPoint(MultiHostInjector.MULTIHOST_INJECTOR_EP_NAME); for (MultiHostInjector injector : extensionPoint.getExtensions()) { if (injector instanceof GrConcatenationInjector) { extensionPoint.unregisterExtension(injector); return; } } LOG.info( "Failed to disable 'org.intellij.plugins.intelliLang.inject.groovy.GrConcatenationInjector'"); } }); } private static void setUpNewProjectActions() { replaceAction("NewClass", new CreateClassAction()); // Update the text for the file creation templates. FileTemplateManager fileTemplateManager = FileTemplateManager.getDefaultInstance(); fileTemplateManager.getTemplate("Singleton") .setText(fileTemplateManager.getJ2eeTemplate("Singleton").getText()); for (String templateName : new String[] { "Class", "Interface", "Enum", "AnnotationType" }) { FileTemplate template = fileTemplateManager.getInternalTemplate(templateName); template.setText(fileTemplateManager.getJ2eeTemplate(templateName).getText()); } } // GradleOrderEnumeratorHandler turns off the "exported" dependency mechanism in IDE for Gradle projects. private static void disableGradleOrderEnumeratorHandler() { ExtensionPoint<OrderEnumerationHandler.Factory> extensionPoint = Extensions.getRootArea() .getExtensionPoint(OrderEnumerationHandler.EP_NAME); for (OrderEnumerationHandler.Factory factory : extensionPoint.getExtensions()) { if (factory instanceof GradleOrderEnumeratorHandler.FactoryImpl) { extensionPoint.unregisterExtension(factory); return; } } } // JUnit original Extension JUnitConfigurationType is disabled so it can be replaced by its child class AndroidJUnitConfigurationType private static void disableIdeaJUnitConfigurations() { // First we unregister the ConfigurationProducers, and after the ConfigurationType ExtensionPoint<RunConfigurationProducer> configurationProducerExtensionPoint = Extensions.getRootArea() .getExtensionPoint(RunConfigurationProducer.EP_NAME); for (RunConfigurationProducer runConfigurationProducer : configurationProducerExtensionPoint .getExtensions()) { if (runConfigurationProducer instanceof JUnitConfigurationProducer && !(runConfigurationProducer instanceof AndroidJUnitConfigurationProducer)) { // In AndroidStudio these ConfigurationProducer s are replaced configurationProducerExtensionPoint.unregisterExtension(runConfigurationProducer); } } ExtensionPoint<ConfigurationType> configurationTypeExtensionPoint = Extensions.getRootArea() .getExtensionPoint(ConfigurationType.CONFIGURATION_TYPE_EP); for (ConfigurationType configurationType : configurationTypeExtensionPoint.getExtensions()) { if (configurationType instanceof JUnitConfigurationType && !(configurationType instanceof AndroidJUnitConfigurationType)) { // In Android Studio the user is forced to use AndroidJUnitConfigurationType instead of JUnitConfigurationType configurationTypeExtensionPoint.unregisterExtension(configurationType); } } // We hide actions registered by the JUnit plugin and instead we use those registered in android-junit.xml hideAction("excludeFromSuite"); hideAction("AddToISuite"); } }