com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationStateEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationStateEditor.java

Source

/*
 * Copyright 2016 The Bazel Authors. All rights reserved.
 *
 * 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.google.idea.blaze.android.run.binary;

import com.android.tools.idea.run.activity.ActivityLocatorUtils;
import com.google.idea.blaze.android.run.binary.instantrun.InstantRunExperiment;
import com.google.idea.blaze.base.run.state.RunConfigurationState;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.google.idea.blaze.base.ui.IntegerTextField;
import com.google.idea.blaze.base.ui.UiUtil;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.LanguageTextField;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ResourceBundle;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.TitledBorder;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;

/**
 * The part of the Blaze Android Binary handler editor that allows the user to pick an activity to
 * launch. Patterned after {@link org.jetbrains.android.run.ApplicationRunParameters}.
 */
class BlazeAndroidBinaryRunConfigurationStateEditor implements RunConfigurationStateEditor {
    public static final Key<BlazeAndroidBinaryRunConfigurationStateEditor> ACTIVITY_CLASS_TEXT_FIELD_KEY = Key
            .create("BlazeActivityClassTextField");

    private final RunConfigurationStateEditor commonStateEditor;

    private JPanel panel;
    private ComponentWithBrowseButton<EditorTextField> activityField;
    private JRadioButton launchNothingButton;
    private JRadioButton launchDefaultButton;
    private JRadioButton launchCustomButton;
    private JCheckBox mobileInstallCheckBox;
    private JCheckBox splitApksCheckBox;
    private JCheckBox instantRunCheckBox;
    private JCheckBox useWorkProfileIfPresentCheckBox;
    private JLabel userIdLabel;
    private IntegerTextField userIdField;

    BlazeAndroidBinaryRunConfigurationStateEditor(RunConfigurationStateEditor commonStateEditor, Project project) {
        this.commonStateEditor = commonStateEditor;
        setupUI(project);
        userIdField.setMinValue(0);

        activityField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!project.isInitialized()) {
                    return;
                }
                // We find all Activity classes in the module for the selected variant
                // (or any of its deps).
                final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
                PsiClass activityBaseClass = facade.findClass(AndroidUtils.ACTIVITY_BASE_CLASS_NAME,
                        ProjectScope.getAllScope(project));
                if (activityBaseClass == null) {
                    Messages.showErrorDialog(panel, AndroidBundle.message("cant.find.activity.class.error"));
                    return;
                }
                GlobalSearchScope searchScope = GlobalSearchScope.projectScope(project);
                PsiClass initialSelection = facade.findClass(activityField.getChildComponent().getText(),
                        searchScope);
                TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project)
                        .createInheritanceClassChooser("Select Activity Class", searchScope, activityBaseClass,
                                initialSelection, null);
                chooser.showDialog();
                PsiClass selClass = chooser.getSelected();
                if (selClass != null) {
                    // This must be done because Android represents
                    // inner static class paths differently than java.
                    String qualifiedActivityName = ActivityLocatorUtils.getQualifiedActivityName(selClass);
                    activityField.getChildComponent().setText(qualifiedActivityName);
                }
            }
        });
        ActionListener listener = e -> activityField.setEnabled(launchCustomButton.isSelected());
        launchCustomButton.addActionListener(listener);
        launchDefaultButton.addActionListener(listener);
        launchNothingButton.addActionListener(listener);

        instantRunCheckBox.setVisible(InstantRunExperiment.INSTANT_RUN_ENABLED.getValue());

        /* Only one of mobile-install and instant run can be selected at any one time */
        mobileInstallCheckBox.addActionListener(e -> {
            if (mobileInstallCheckBox.isSelected()) {
                instantRunCheckBox.setSelected(false);
            }
        });
        instantRunCheckBox.addActionListener(e -> {
            if (instantRunCheckBox.isSelected()) {
                mobileInstallCheckBox.setSelected(false);
            }
        });

        mobileInstallCheckBox
                .addActionListener(e -> splitApksCheckBox.setVisible(mobileInstallCheckBox.isSelected()));

        useWorkProfileIfPresentCheckBox.addActionListener(e -> {
            setUserIdEnabled(!useWorkProfileIfPresentCheckBox.isSelected());
        });
    }

    @Override
    public void resetEditorFrom(RunConfigurationState genericState) {
        BlazeAndroidBinaryRunConfigurationState state = (BlazeAndroidBinaryRunConfigurationState) genericState;
        commonStateEditor.resetEditorFrom(state.getCommonState());
        boolean launchSpecificActivity = state.getMode()
                .equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
        if (state.getMode().equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY)) {
            launchDefaultButton.setSelected(true);
        } else if (launchSpecificActivity) {
            launchCustomButton.setSelected(true);
        } else {
            launchNothingButton.setSelected(true);
        }
        activityField.setEnabled(launchSpecificActivity);
        if (launchSpecificActivity) {
            activityField.getChildComponent().setText(state.getActivityClass());
        }

        mobileInstallCheckBox.setSelected(state.mobileInstall());
        splitApksCheckBox.setSelected(state.useSplitApksIfPossible());
        instantRunCheckBox.setSelected(state.instantRun());
        useWorkProfileIfPresentCheckBox.setSelected(state.useWorkProfileIfPresent());

        userIdField.setValue(state.getUserId());
        setUserIdEnabled(!state.useWorkProfileIfPresent());
        splitApksCheckBox.setVisible(state.mobileInstall());
    }

    private void setUserIdEnabled(boolean enabled) {
        userIdLabel.setEnabled(enabled);
        userIdField.setEnabled(enabled);
    }

    @Override
    public void applyEditorTo(RunConfigurationState genericState) {
        BlazeAndroidBinaryRunConfigurationState state = (BlazeAndroidBinaryRunConfigurationState) genericState;
        commonStateEditor.applyEditorTo(state.getCommonState());

        state.setUserId((Integer) userIdField.getValue());
        if (launchDefaultButton.isSelected()) {
            state.setMode(BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY);
        } else if (launchCustomButton.isSelected()) {
            state.setMode(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
            state.setActivityClass(activityField.getChildComponent().getText());
        } else {
            state.setMode(BlazeAndroidBinaryRunConfigurationState.DO_NOTHING);
        }
        state.setMobileInstall(mobileInstallCheckBox.isSelected());
        state.setUseSplitApksIfPossible(splitApksCheckBox.isSelected());
        state.setInstantRun(instantRunCheckBox.isSelected());
        state.setUseWorkProfileIfPresent(useWorkProfileIfPresentCheckBox.isSelected());
    }

    @Override
    public JComponent createComponent() {
        return UiUtil.createBox(commonStateEditor.createComponent(), panel);
    }

    private void createUIComponents(Project project) {
        final EditorTextField editorTextField = new LanguageTextField(PlainTextLanguage.INSTANCE, project, "") {
            @Override
            protected EditorEx createEditor() {
                final EditorEx editor = super.createEditor();
                final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());

                if (file != null) {
                    DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file, false);
                }
                editor.putUserData(ACTIVITY_CLASS_TEXT_FIELD_KEY,
                        BlazeAndroidBinaryRunConfigurationStateEditor.this);
                return editor;
            }
        };
        activityField = new ComponentWithBrowseButton<EditorTextField>(editorTextField, null);
    }

    /** Initially generated by IntelliJ from a .form file, then checked in as source. */
    private void setupUI(Project project) {
        createUIComponents(project);
        panel = new JPanel();
        panel.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1));
        final JPanel activityPanel = new JPanel();
        activityPanel.setLayout(new GridLayoutManager(4, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel.add(activityPanel,
                new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null,
                        null, 0, false));
        activityPanel.setBorder(BorderFactory.createTitledBorder(
                BorderFactory.createEtchedBorder(), "Activity", TitledBorder.DEFAULT_JUSTIFICATION,
                TitledBorder.DEFAULT_POSITION, new Font(activityPanel.getFont().getName(),
                        activityPanel.getFont().getStyle(), activityPanel.getFont().getSize()),
                new Color(-16777216)));
        final JPanel userPanel = new JPanel();
        userPanel.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel.add(userPanel,
                new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null,
                        null, 0, false));
        userPanel.setBorder(BorderFactory
                .createTitledBorder(BorderFactory.createEtchedBorder(), "User", TitledBorder.DEFAULT_JUSTIFICATION,
                        TitledBorder.DEFAULT_POSITION, new Font(userPanel.getFont().getName(),
                                userPanel.getFont().getStyle(), userPanel.getFont().getSize()),
                        new Color(-16777216)));
        launchNothingButton = new JRadioButton();
        this.loadButtonText(launchNothingButton, ResourceBundle.getBundle("messages/AndroidBundle")
                .getString("android.run.configuration.do.nothing.label"));
        activityPanel.add(launchNothingButton,
                new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        launchDefaultButton = new JRadioButton();
        launchDefaultButton.setText("Launch default Activity");
        launchDefaultButton.setMnemonic('L');
        launchDefaultButton.setDisplayedMnemonicIndex(0);
        activityPanel.add(launchDefaultButton,
                new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        launchCustomButton = new JRadioButton();
        launchCustomButton.setText("Launch:");
        launchCustomButton.setMnemonic('A');
        launchCustomButton.setDisplayedMnemonicIndex(1);
        activityPanel.add(launchCustomButton,
                new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        activityPanel.add(activityField,
                new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        useWorkProfileIfPresentCheckBox = new JCheckBox();
        useWorkProfileIfPresentCheckBox.setText(" Use work profile if present");
        userPanel.add(useWorkProfileIfPresentCheckBox,
                new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        userIdLabel = new JLabel();
        userIdLabel.setText("User ID");
        userPanel.add(userIdLabel,
                new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1,
                        false));
        userIdField = new IntegerTextField();
        userPanel.add(userIdField,
                new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
                        GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
                        false));
        mobileInstallCheckBox = new JCheckBox();
        mobileInstallCheckBox.setText(" Use mobile-install");
        panel.add(mobileInstallCheckBox,
                new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        splitApksCheckBox = new JCheckBox();
        splitApksCheckBox.setText(" Use --split_apks where possible");
        panel.add(splitApksCheckBox,
                new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        instantRunCheckBox = new JCheckBox();
        instantRunCheckBox.setText(" Use InstantRun");
        panel.add(instantRunCheckBox,
                new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                        GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                        GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ButtonGroup buttonGroup;
        buttonGroup = new ButtonGroup();
        buttonGroup.add(launchDefaultButton);
        buttonGroup.add(launchCustomButton);
        buttonGroup.add(launchNothingButton);
    }

    /** Initially generated by IntelliJ from a .form file. */
    private void loadButtonText(AbstractButton component, String text) {
        StringBuffer result = new StringBuffer();
        boolean haveMnemonic = false;
        char mnemonic = '\0';
        int mnemonicIndex = -1;
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) == '&') {
                i++;
                if (i == text.length()) {
                    break;
                }
                if (!haveMnemonic && text.charAt(i) != '&') {
                    haveMnemonic = true;
                    mnemonic = text.charAt(i);
                    mnemonicIndex = result.length();
                }
            }
            result.append(text.charAt(i));
        }
        component.setText(result.toString());
        if (haveMnemonic) {
            component.setMnemonic(mnemonic);
            component.setDisplayedMnemonicIndex(mnemonicIndex);
        }
    }
}