From ee35fd1ab0da414873d8234e31fd3075894e6d20 Mon Sep 17 00:00:00 2001 From: Void Young Date: Mon, 19 Oct 2020 11:35:35 +0800 Subject: [PATCH] Merge branch 'master' of https://github.com/pbreault/adb-idea into pbreault-master # Conflicts: # build.gradle # src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt # src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt # src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.kt # src/main/kotlin/com/developerphil/adbidea/ui/NotificationHelper.kt # src/main/resources/META-INF/plugin.xml --- DEVELOP.md | 27 +-- build.gradle | 2 +- .../ui/ApplicationManagementFrame.java | 2 +- .../adbidea/ui/DeviceChooserDialog.java | 154 ------------------ .../com/developerphil/adbidea/Application.kt | 29 ++++ .../com/developerphil/adbidea/ObjectGraph.kt | 10 +- .../adbidea/PluginPreferences.kt | 28 ---- .../preference/ProjectPreferenceAccessor.kt | 15 -- .../ClearDataAndRestartWithDebuggerAction.kt | 14 ++ .../adbidea/action/DisableMobileAction.kt | 9 + .../adbidea/action/DisableWifiAction.kt | 9 + .../adbidea/action/EnableMobileAction.kt | 9 + .../adbidea/action/EnableWifiAction.kt | 9 + .../action/extend/ScreenRecordAction.kt | 10 +- .../developerphil/adbidea/adb/AdbFacade.kt | 83 ++++------ .../adbidea/adb/UseSameDevicesHelper.kt | 7 +- .../adb/command/ActivityServiceCommand.kt | 3 - .../adb/command/ClearDataAndRestartCommand.kt | 2 +- .../ClearDataAndRestartWithDebuggerCommand.kt | 3 + .../adbidea/adb/command/ClearDataCommand.kt | 12 +- .../adb/command/CommonStringResultCommand.kt | 2 - .../adbidea/adb/command/ForceStopCommand.kt | 2 - .../adb/command/ForegroundActivityCommand.kt | 1 - .../adbidea/adb/command/MonkeyTestCommand.kt | 1 - .../adb/command/PackageDetailCommand.kt | 1 - .../adbidea/adb/command/PackagePathCommand.kt | 2 - .../adbidea/adb/command/ToggleSvcCommand.kt | 34 ++++ .../adb/command/receiver/GenericReceiver.kt | 3 +- .../adb/command/receiver/PrintReceiver.kt | 41 ++--- .../adbidea/debugger/Debugger.kt | 4 +- .../preference/ApplicationPreferences.kt | 20 +++ .../adbidea/preference/ProjectPreferences.kt | 23 +++ .../accessor}/PreferenceAccessor.kt | 2 +- .../accessor/PreferenceAccessorImpl.kt | 14 ++ .../adbidea/ui/DeviceChooserDialog.kt | 76 +++++++++ .../adbidea/ui/MyChooseModulesDialog.kt | 2 +- .../adbidea/ui/MyDeviceChooser.kt | 2 + src/main/resources/META-INF/plugin.xml | 94 ++++++++++- .../adbidea/PluginPreferencesTests.kt | 66 -------- .../adbidea/adb/UseSameDevicesHelperTest.kt | 19 +-- .../preference/ApplicationPreferencesTests.kt | 34 ++++ .../preference/ProjectPreferencesTests.kt | 38 +++++ .../accessor/InMemoryPreferenceAccessor.kt | 15 ++ 43 files changed, 521 insertions(+), 412 deletions(-) delete mode 100644 src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.java create mode 100644 src/main/kotlin/com/developerphil/adbidea/Application.kt delete mode 100644 src/main/kotlin/com/developerphil/adbidea/PluginPreferences.kt delete mode 100644 src/main/kotlin/com/developerphil/adbidea/accessor/preference/ProjectPreferenceAccessor.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/ClearDataAndRestartWithDebuggerAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/DisableMobileAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/DisableWifiAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/EnableMobileAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/action/EnableWifiAction.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartWithDebuggerCommand.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/adb/command/ToggleSvcCommand.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/preference/ApplicationPreferences.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/preference/ProjectPreferences.kt rename src/main/kotlin/com/developerphil/adbidea/{accessor/preference => preference/accessor}/PreferenceAccessor.kt (72%) create mode 100644 src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessorImpl.kt create mode 100644 src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.kt delete mode 100644 src/test/kotlin/com/developerphil/adbidea/PluginPreferencesTests.kt create mode 100644 src/test/kotlin/com/developerphil/adbidea/preference/ApplicationPreferencesTests.kt create mode 100644 src/test/kotlin/com/developerphil/adbidea/preference/ProjectPreferencesTests.kt create mode 100644 src/test/kotlin/com/developerphil/adbidea/preference/accessor/InMemoryPreferenceAccessor.kt diff --git a/DEVELOP.md b/DEVELOP.md index 99402dc4..02d3b3ef 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -2,34 +2,35 @@ Run/Debug ========= * Open project in intellij +* Create gradle.properties file, use [instruction](gradle.properties.change_me) * Open _edit configurations_ to create a new run/debug configuration -* Choose a new gradle configuration and name it `build and run` that runs ./gradlew buildPlugin runIdea +* Choose a new gradle configuration and name it `build and run` that runs `./gradlew buildPlugin runIde` ![Create debug configuration](website/debug_howto.png) * hit debug button as usual Running from command line ------------------------- - - ./gradlew buildPlugin runIdea - +* Create gradle.properties file, use [instruction](gradle.properties.change_me) +* Execute command +```shell script + ./gradlew buildPlugin runIde +``` Create new menu item ==================== -* Add entry to plugin.xml (below line 100) - - +* Add entry to plugin.xml inside actions tab (below line 100) +```xml - +``` * Create and implement a new `NewAction` class that extends from `AdbAction` (you can create that from the plugin view, right click on the class name and choose `create class` * implement its abstract methods -* add new entry in `QuickListAction.java` like this - - - addAction("com.developerphil.adbidea.action.NewAction", group); - \ No newline at end of file +* add new entry in `QuickListAction.kt` like this +```kotlin + addAction("com.developerphil.adbidea.action.NewAction", group) +``` \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6f34b37a..38a38d92 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { - ext.kotlin_version = '1.3.41' + ext.kotlin_version = '1.3.61' repositories { mavenCentral() diff --git a/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java index aa535213..4e7ecb5c 100644 --- a/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java +++ b/src/main/java/com/developerphil/adbidea/ui/ApplicationManagementFrame.java @@ -239,7 +239,7 @@ public void mouseClicked(MouseEvent e) { Utils.Companion.append2TextPane("Monkey test of " + name + " :\n", JBColor.BLUE,tp); } String countStr = JOptionPane.showInputDialog("Enter test count(only integers):"); - if (countStr.isEmpty()) { + if (countStr==null||countStr.isEmpty()) { HelperMethodsKt.showErrorMsg("count can not empty"); return; } diff --git a/src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.java b/src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.java deleted file mode 100644 index 5098b536..00000000 --- a/src/main/java/com/developerphil/adbidea/ui/DeviceChooserDialog.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.developerphil.adbidea.ui; - -import com.android.ddmlib.IDevice; -import com.developerphil.adbidea.ObjectGraph; -import com.developerphil.adbidea.PluginPreferences; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.Disposer; -import com.intellij.uiDesigner.core.GridConstraints; -import com.intellij.uiDesigner.core.GridLayoutManager; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Insets; -import java.util.stream.Collectors; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JPanel; -import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.annotations.NotNull; -import org.joor.Reflect; - -import static java.util.Arrays.stream; - -public class DeviceChooserDialog extends DialogWrapper { - private final Project myProject; - private final MyDeviceChooser myDeviceChooser; - - private JPanel myPanel; - private JPanel myDeviceChooserWrapper; - private JCheckBox useSameDeviceSCheckBox; - - PluginPreferences pluginPreferences; - - public DeviceChooserDialog(@NotNull final AndroidFacet facet) { - super(facet.getModule().getProject(), true); - setTitle(AndroidBundle.message("choose.device.dialog.title")); - - myProject = facet.getModule().getProject(); - pluginPreferences = myProject.getComponent(ObjectGraph.class).getPluginPreferences(); - - getOKAction().setEnabled(false); - - myDeviceChooser = new MyDeviceChooser(true, getOKAction(), facet, null); - Disposer.register(myDisposable, myDeviceChooser); - myDeviceChooser.addListener(this :: updateOkButton); - - myDeviceChooserWrapper.add(myDeviceChooser.getPanel()); - - myDeviceChooser.init(pluginPreferences.getSelectedDeviceSerials()); - - init(); - - updateEnabled(); - } - - private void persistSelectedSerialsToPreferences() { - pluginPreferences.saveSelectedDeviceSerials(stream(myDeviceChooser.getSelectedDevices()).map(IDevice :: getSerialNumber).collect(Collectors.toList())); - } - - private void updateOkButton() { - getOKAction().setEnabled(getSelectedDevices().length > 0); - } - - private void updateEnabled() { - updateOkButton(); - } - - @Override - public JComponent getPreferredFocusedComponent() { - try { - return myDeviceChooser.getPreferredFocusComponent(); - } catch (NoSuchMethodError e) { - // that means that we are probably on a preview version of android studio or in intellij 13 - return Reflect.on(myDeviceChooser).call("getDeviceTable").get(); - } - } - - @Override - protected void doOKAction() { - myDeviceChooser.finish(); - persistSelectedSerialsToPreferences(); - super.doOKAction(); - } - - @Override - protected String getDimensionServiceKey() { - return getClass().getCanonicalName(); - } - - @Override - protected JComponent createCenterPanel() { - return myPanel; - } - - @NotNull - public IDevice[] getSelectedDevices() { - return myDeviceChooser.getSelectedDevices(); - } - - public boolean useSameDevices() { - return useSameDeviceSCheckBox.isSelected(); - } - - @NotNull - public static String toString(@NotNull IDevice[] devices) { - StringBuilder builder = new StringBuilder(); - for (int i = 0, n = devices.length; i < n; i++) { - builder.append(devices[i].getSerialNumber()); - if (i < n - 1) { - builder.append(' '); - } - } - return builder.toString(); - } - - { - // GUI initializer generated by IntelliJ IDEA GUI Designer - // >>> IMPORTANT!! <<< - // DO NOT EDIT OR ADD ANY CODE HERE! - $$$setupUI$$$(); - } - - /** - * Method generated by IntelliJ IDEA GUI Designer - * >>> IMPORTANT!! <<< - * DO NOT edit this method OR call it in your code! - * - * @noinspection ALL - */ - private void $$$setupUI$$$() { - myPanel = new JPanel(); - myPanel.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1)); - myDeviceChooserWrapper = new JPanel(); - myDeviceChooserWrapper.setLayout(new BorderLayout(0, 0)); - myPanel.add(myDeviceChooserWrapper, - new GridConstraints(0, 0, 1, 3, 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)); - useSameDeviceSCheckBox = new JCheckBox(); - useSameDeviceSCheckBox.setBorderPainted(true); - useSameDeviceSCheckBox.setMargin(new Insets(1, 1, 1, 1)); - useSameDeviceSCheckBox.setMaximumSize(new Dimension(280, 25)); - useSameDeviceSCheckBox.setMinimumSize(new Dimension(280, 25)); - useSameDeviceSCheckBox.setPreferredSize(new Dimension(280, 25)); - useSameDeviceSCheckBox.setText("Use same device(s) for future commands"); - useSameDeviceSCheckBox.setVerticalAlignment(3); - myDeviceChooserWrapper.add(useSameDeviceSCheckBox, BorderLayout.SOUTH); - } - - /** @noinspection ALL */ - public JComponent $$$getRootComponent$$$() { - return myPanel; - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/Application.kt b/src/main/kotlin/com/developerphil/adbidea/Application.kt new file mode 100644 index 00000000..c905bbed --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/Application.kt @@ -0,0 +1,29 @@ +package com.developerphil.adbidea + +import com.developerphil.adbidea.preference.ApplicationPreferences +import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl +import com.developerphil.adbidea.ui.NotificationHelper +import com.intellij.ide.plugins.PluginManager +import com.intellij.ide.util.PropertiesComponent +import com.intellij.openapi.components.ApplicationComponent +import com.intellij.openapi.extensions.PluginId +import com.intellij.util.text.SemVer + + +private val pluginPackage = "com.developerphil.adbidea" + +// This is more of a service locator than a proper DI framework. +// It's not used often enough in the codebase to warrant the complexity of a DI solution like dagger. +class Application : ApplicationComponent { + private val applicationPreferencesAccessor = PreferenceAccessorImpl(PropertiesComponent.getInstance()) + private val applicationPreferences = ApplicationPreferences(applicationPreferencesAccessor) + + override fun initComponent() { + try { + val version = PluginManager.getPlugin(PluginId.getId(pluginPackage))!!.version!! + applicationPreferences.savePreviousPluginVersion(SemVer.parseFromText(version)!!) + } catch (e: Exception) { + NotificationHelper.error("Couldn't initialize ADB Idea: ${e.message}") + } + } +} diff --git a/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt b/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt index d9482bc1..c794f997 100644 --- a/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ObjectGraph.kt @@ -1,9 +1,11 @@ package com.developerphil.adbidea -import com.developerphil.adbidea.accessor.preference.ProjectPreferenceAccessor import com.developerphil.adbidea.adb.BridgeImpl import com.developerphil.adbidea.adb.DeviceResultFetcher import com.developerphil.adbidea.adb.UseSameDevicesHelper +import com.developerphil.adbidea.preference.ProjectPreferences +import com.developerphil.adbidea.preference.accessor.PreferenceAccessorImpl +import com.intellij.ide.util.PropertiesComponent import com.intellij.openapi.components.ProjectComponent import com.intellij.openapi.project.Project @@ -12,10 +14,10 @@ import com.intellij.openapi.project.Project class ObjectGraph(private val project: Project) : ProjectComponent { val deviceResultFetcher by lazy { DeviceResultFetcher(project, useSameDevicesHelper, bridge) } - val pluginPreferences: PluginPreferences by lazy { PluginPreferencesImpl(preferenceAccessor) } + val projectPreferences: ProjectPreferences by lazy { ProjectPreferences(projectPreferenceAccessor) } - private val useSameDevicesHelper by lazy { UseSameDevicesHelper(pluginPreferences, bridge) } - private val preferenceAccessor by lazy { ProjectPreferenceAccessor(project) } + private val useSameDevicesHelper by lazy { UseSameDevicesHelper(projectPreferences, bridge) } + private val projectPreferenceAccessor by lazy { PreferenceAccessorImpl(PropertiesComponent.getInstance(project)) } private val bridge by lazy { BridgeImpl(project) } diff --git a/src/main/kotlin/com/developerphil/adbidea/PluginPreferences.kt b/src/main/kotlin/com/developerphil/adbidea/PluginPreferences.kt deleted file mode 100644 index c673af2f..00000000 --- a/src/main/kotlin/com/developerphil/adbidea/PluginPreferences.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.developerphil.adbidea - -import com.developerphil.adbidea.accessor.preference.PreferenceAccessor - -interface PluginPreferences { - fun saveSelectedDeviceSerials(serials: List) - fun getSelectedDeviceSerials(): List -} - -class PluginPreferencesImpl(val preferenceAccessor: PreferenceAccessor) : PluginPreferences { - - private val SELECTED_SERIALS_PROPERTY = "com.developerphil.adbidea.selecteddevices" - - - override fun saveSelectedDeviceSerials(serials: List) { - preferenceAccessor.saveString(SELECTED_SERIALS_PROPERTY, serials.joinToString(separator = " ")) - } - - override fun getSelectedDeviceSerials(): List { - return with(preferenceAccessor.getString(SELECTED_SERIALS_PROPERTY, "")) { - if (isEmpty()) { - emptyList() - } else { - split(" ") - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/accessor/preference/ProjectPreferenceAccessor.kt b/src/main/kotlin/com/developerphil/adbidea/accessor/preference/ProjectPreferenceAccessor.kt deleted file mode 100644 index 0684b574..00000000 --- a/src/main/kotlin/com/developerphil/adbidea/accessor/preference/ProjectPreferenceAccessor.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.developerphil.adbidea.accessor.preference - -import com.intellij.ide.util.PropertiesComponent -import com.intellij.openapi.project.Project - -class ProjectPreferenceAccessor(project: Project) : PreferenceAccessor { - - private val properties = PropertiesComponent.getInstance(project) - - override fun saveString(key: String, value: String) { - properties.setValue(key, value) - } - - override fun getString(key: String, defaultValue: String) = properties.getValue(key) ?: defaultValue -} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/action/ClearDataAndRestartWithDebuggerAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/ClearDataAndRestartWithDebuggerAction.kt new file mode 100644 index 00000000..77b32776 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/ClearDataAndRestartWithDebuggerAction.kt @@ -0,0 +1,14 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.developerphil.adbidea.adb.AdbUtil +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class ClearDataAndRestartWithDebuggerAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.clearDataAndRestartWithDebugger(project) + + override fun update(e: AnActionEvent) { + e.presentation.isEnabled = AdbUtil.isDebuggingAvailable + } +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/DisableMobileAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/DisableMobileAction.kt new file mode 100644 index 00000000..e4b4491b --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/DisableMobileAction.kt @@ -0,0 +1,9 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class DisableMobileAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.disableMobile(project) +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/DisableWifiAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/DisableWifiAction.kt new file mode 100644 index 00000000..3f7a6a22 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/DisableWifiAction.kt @@ -0,0 +1,9 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class DisableWifiAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.disableWifi(project) +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/EnableMobileAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/EnableMobileAction.kt new file mode 100644 index 00000000..da2104c9 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/EnableMobileAction.kt @@ -0,0 +1,9 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class EnableMobileAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.enableMobile(project) +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/EnableWifiAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/EnableWifiAction.kt new file mode 100644 index 00000000..a4ed477c --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/action/EnableWifiAction.kt @@ -0,0 +1,9 @@ +package com.developerphil.adbidea.action + +import com.developerphil.adbidea.adb.AdbFacade +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project + +class EnableWifiAction : AdbAction() { + override fun actionPerformed(e: AnActionEvent, project: Project) = AdbFacade.enableWifi(project) +} diff --git a/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt index 13edec06..dad8d522 100644 --- a/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt +++ b/src/main/kotlin/com/developerphil/adbidea/action/extend/ScreenRecordAction.kt @@ -33,8 +33,14 @@ class ScreenRecordAction : AdbAction() { } val dialog = RecordOptionDialog { deleteRemoteFile -> saveDirChooserDescriptor.title = "Select $videoName save to..." - val choose = FileChooserDialogImpl(saveDirChooserDescriptor, project) - .choose(project, selectedFile) + val chooserDialogImpl = FileChooserDialogImpl(saveDirChooserDescriptor, project) + val choose = if (selectedFile != null) { + chooserDialogImpl + .choose(project, selectedFile!!) + } else { + chooserDialogImpl + .choose(project) + } if (choose.isNotEmpty()) { selectedFile = choose[0] AdbFacade.pullFile(project, remotePath, File(selectedFile?.canonicalPath, videoName), deleteRemoteFile) diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt index 10eaa303..e9ceb4d7 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/AdbFacade.kt @@ -12,55 +12,30 @@ import java.util.concurrent.Executors object AdbFacade { private val EXECUTOR = Executors.newCachedThreadPool(ThreadFactoryBuilder().setNameFormat("AdbIdea-%d").build()) - - + fun uninstall(project: Project) = executeOnDevice(project, UninstallCommand()) fun uninstall(project: Project, packageName: String) { executeOnDevice(project, UninstallCommand(packageName)) } - fun uninstall(project: Project) { - executeOnDevice(project, UninstallCommand()) - } + fun kill(project: Project) = executeOnDevice(project, KillCommand()) + fun grantPermissions(project: Project) = executeOnDevice(project, GrantPermissionsCommand()) + fun revokePermissions(project: Project) = executeOnDevice(project, RevokePermissionsCommand()) + fun revokePermissionsAndRestart(project: Project) = executeOnDevice(project, RevokePermissionsAndRestartCommand()) + fun startDefaultActivity(project: Project) = executeOnDevice(project, StartDefaultActivityCommand(false)) + fun startDefaultActivityWithDebugger(project: Project) = executeOnDevice(project, StartDefaultActivityCommand(true)) + fun restartDefaultActivity(project: Project) = executeOnDevice(project, RestartPackageCommand()) + fun restartDefaultActivityWithDebugger(project: Project) = executeOnDevice(project, CommandList(KillCommand(), StartDefaultActivityCommand(true))) + fun clearData(project: Project) = executeOnDevice(project, ClearDataCommand()) + fun clearDataAndRestart(project: Project) = executeOnDevice(project, ClearDataAndRestartCommand()) - fun installApk(project: Project, apks: List) { - executeOnDevice(project, InstallApkCommand(apks)) - } - fun kill(project: Project) { - executeOnDevice(project, KillCommand()) - } - fun grantPermissions(project: Project) { - executeOnDevice(project, GrantPermissionsCommand()) - } - - fun revokePermissions(project: Project) { - executeOnDevice(project, RevokePermissionsCommand()) - } - fun revokePermissionsAndRestart(project: Project) { - executeOnDevice(project, RevokePermissionsAndRestartCommand()) - } - - fun startDefaultActivity(project: Project) { - executeOnDevice(project, StartDefaultActivityCommand(false)) - } - - fun startDefaultActivityWithDebugger(project: Project) { - executeOnDevice(project, StartDefaultActivityCommand(true)) - } - - fun restartDefaultActivity(project: Project) { - executeOnDevice(project, RestartPackageCommand()) + fun installApk(project: Project, apks: List) { + executeOnDevice(project, InstallApkCommand(apks)) } - fun restartDefaultActivityWithDebugger(project: Project) { - executeOnDevice(project, CommandList(KillCommand(), StartDefaultActivityCommand(true))) - } - fun clearData(project: Project) { - executeOnDevice(project, ClearDataCommand()) - } fun getPackageDetail(project: Project, packageName: String, callback: Function1) { executeOnDevice(project, PackageDetailCommand(packageName, callback)) @@ -78,26 +53,34 @@ object AdbFacade { executeOnDevice(project, ActivityServiceCommand(packageName, callback)) } - fun clearDataAndRestart(project: Project) { - executeOnDevice(project, ClearDataAndRestartCommand()) - } + fun getAllApplicationList(project: Project, parameter: String, callback: Function1, Unit>) { executeOnDevice(project, GetApplicationListCommand(parameter, callback)) } - private fun executeOnDevice(project: Project?, runnable: Command) { - if (AdbUtil.isGradleSyncInProgress(project!!)) { + fun clearDataAndRestartWithDebugger(project: Project) = executeOnDevice(project, ClearDataAndRestartWithDebuggerCommand()) + fun enableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.WIFI, true)) + fun disableWifi(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.WIFI, false)) + fun enableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.MOBILE, true)) + fun disableMobile(project: Project) = executeOnDevice(project, ToggleSvcCommand(SvcCommand.MOBILE, false)) + + + + private fun executeOnDevice(project: Project, runnable: Command) { + if (AdbUtil.isGradleSyncInProgress(project)) { NotificationHelper.error("Gradle sync is in progress") return } - val result = project!!.getComponent(ObjectGraph::class.java).deviceResultFetcher.fetch() + val result = project.getComponent(ObjectGraph::class.java) + .deviceResultFetcher + .fetch() if (result != null) { for (device in result.devices) { - EXECUTOR.submit({ runnable.run(project, device, result.facet, result.packageName) } as Runnable) + EXECUTOR.submit { runnable.run(project, device, result.facet, result.packageName) } } } else { NotificationHelper.error("No Device found") @@ -117,7 +100,7 @@ object AdbFacade { } fun putStringToDevice(project: Project?, str: String) { - executeOnDevice(project, PutStringToDeviceCommand(str)) + executeOnDevice(project!!, PutStringToDeviceCommand(str)) } fun interacting(project: Project, type: Int, action: String, category: String, name: String, boundData: MutableList) { @@ -125,11 +108,11 @@ object AdbFacade { } fun getSimpleInfo(project: Project?, command: String, desc: String, callback: Function1) { - executeOnDevice(project, CommonStringResultCommand(command, desc, callback)) + executeOnDevice(project!!, CommonStringResultCommand(command, desc, callback)) } fun captureScreen(project: Project?, localDir: File, fileName: String) { - executeOnDevice(project, CaptureScreenCommand(localDir, fileName)) + executeOnDevice(project!!, CaptureScreenCommand(localDir, fileName)) } /** @@ -142,11 +125,11 @@ object AdbFacade { */ @Deprecated("") fun recordScreen(project: Project?, localFile: File, videoName: String, length: Int, showTouches: Boolean) { - executeOnDevice(project, ScreenRecordCommand(localFile, videoName, length, showTouches)) + executeOnDevice(project!!, ScreenRecordCommand(localFile, videoName, length, showTouches)) } fun pullFile(project: Project?, remotePath: String, localFile: File, deleteRemoteFile: Boolean) { - executeOnDevice(project, PullFileCommand(remotePath, localFile, deleteRemoteFile)) + executeOnDevice(project!!, PullFileCommand(remotePath, localFile, deleteRemoteFile)) } fun getDeviceModel(project: Project?, function: Function1) { diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt b/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt index 0b61b509..279e9293 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelper.kt @@ -1,15 +1,14 @@ package com.developerphil.adbidea.adb import com.android.ddmlib.IDevice -import com.developerphil.adbidea.PluginPreferences -import javax.inject.Inject +import com.developerphil.adbidea.preference.ProjectPreferences -class UseSameDevicesHelper @Inject constructor(private val pluginPreferences: PluginPreferences, private val bridge: Bridge) { +class UseSameDevicesHelper constructor(private val projectPreferences: ProjectPreferences, private val bridge: Bridge) { var previouslyConnectedDevices: List? = null fun getRememberedDevices(): List { - val selectedDeviceSerials = pluginPreferences.getSelectedDeviceSerials() + val selectedDeviceSerials = projectPreferences.getSelectedDeviceSerials() val currentlyConnectedDevices = bridge.connectedDevices() if (currentlyConnectedDevices == previouslyConnectedDevices) { diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt index f1d88951..65b610ed 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ActivityServiceCommand.kt @@ -21,7 +21,6 @@ class ActivityServiceCommand(private val mPackageName: String,private val callba try { if (mPackageName.isNotEmpty()&&!isAppInstalled(device, mPackageName)) { error(String.format("%s is not installed on %s", mPackageName, device.name)) - return false } val receiver = PrintReceiver() device.executeShellCommand("dumpsys activity services $mPackageName", receiver, 15L, TimeUnit.SECONDS) @@ -34,8 +33,6 @@ class ActivityServiceCommand(private val mPackageName: String,private val callba } catch (e1: Exception) { error("get activity service... " + e1.message) } - - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartCommand.kt index 20b92b3e..00bfce04 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartCommand.kt @@ -1,3 +1,3 @@ package com.developerphil.adbidea.adb.command -class ClearDataAndRestartCommand : CommandList(ClearDataCommand(), StartDefaultActivityCommand(false)) \ No newline at end of file +class ClearDataAndRestartCommand : CommandList(ClearDataCommand(), StartDefaultActivityCommand(false)) diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartWithDebuggerCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartWithDebuggerCommand.kt new file mode 100644 index 00000000..f3321e30 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataAndRestartWithDebuggerCommand.kt @@ -0,0 +1,3 @@ +package com.developerphil.adbidea.adb.command + +class ClearDataAndRestartWithDebuggerCommand : CommandList(ClearDataCommand(), StartDefaultActivityCommand(true)) diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt index 815cf0cc..5e8fb7c7 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ClearDataCommand.kt @@ -10,17 +10,17 @@ import java.util.concurrent.TimeUnit class ClearDataCommand(val realPackageName:String = "") : Command { override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { - var packageName = packageName + var pn = packageName if (realPackageName.isNotEmpty()) { - packageName = realPackageName + pn = realPackageName } try { - if (AdbUtil.isAppInstalled(device, packageName)) { - device.executeShellCommand("pm clear $packageName", GenericReceiver(), 15L, TimeUnit.SECONDS) - NotificationHelper.info(String.format("%s cleared data for app on %s", packageName, device.name)) + if (AdbUtil.isAppInstalled(device, pn)) { + device.executeShellCommand("pm clear $pn", GenericReceiver(), 15L, TimeUnit.SECONDS) + NotificationHelper.info(String.format("%s cleared data for app on %s", pn, device.name)) return true } else { - NotificationHelper.error(String.format("%s is not installed on %s", packageName, device.name)) + NotificationHelper.error(String.format("%s is not installed on %s", pn, device.name)) } } catch (e1: Exception) { NotificationHelper.error("Clear data failed... " + e1.message) diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt index 61e54bb8..de9a03cc 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/CommonStringResultCommand.kt @@ -32,8 +32,6 @@ class CommonStringResultCommand(private val commandStr:String,private val operat } catch (e1: Exception) { error("$operationDesc... " + e1.message) } - - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt index 9ff53403..a3e10ddc 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForceStopCommand.kt @@ -33,8 +33,6 @@ class ForceStopCommand(private val mPackageName: String) : Command { } catch (e1: Exception) { error("Force Stop... " + e1.message) } - - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt index 100ba883..adad2ad4 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ForegroundActivityCommand.kt @@ -29,7 +29,6 @@ class ForegroundActivityCommand(private val callback:(String)->Unit) : Command { } catch (e1: Exception) { error("Get foreground Activity... " + e1.message) } - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt index eda9085b..4cf94bda 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/MonkeyTestCommand.kt @@ -31,7 +31,6 @@ class MonkeyTestCommand(private val mPackageName: String, private val count: Int } catch (e1: Exception) { error("Start monkey test... " + e1.message) } - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt index 9af46a0d..cd8f85f9 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackageDetailCommand.kt @@ -36,7 +36,6 @@ class PackageDetailCommand(private val mPackageName: String,private val callback error("Get package detail... " + e1.message) } - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt index 65b21f7a..062d6a16 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/PackagePathCommand.kt @@ -35,8 +35,6 @@ class PackagePathCommand(private val mPackageName: String,private val callback:( } catch (e1: Exception) { error("Get package path... " + e1.message) } - - return false } } diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/ToggleSvcCommand.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/ToggleSvcCommand.kt new file mode 100644 index 00000000..a6d49468 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/ToggleSvcCommand.kt @@ -0,0 +1,34 @@ +package com.developerphil.adbidea.adb.command + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.adb.command.receiver.GenericReceiver +import com.developerphil.adbidea.ui.NotificationHelper.error +import com.developerphil.adbidea.ui.NotificationHelper.info +import com.intellij.openapi.project.Project +import org.jetbrains.android.facet.AndroidFacet +import java.util.concurrent.TimeUnit + +enum class SvcCommand(val parameter: String, val description: String) { + WIFI("wifi", "Wi-Fi"), + MOBILE("data", "Mobile data") +} + +class ToggleSvcCommand( + private val command: SvcCommand, + private val enable: Boolean) : Command { + + private val shellCommand = "svc ${command.parameter} ${enable.toState()}" + + override fun run(project: Project, device: IDevice, facet: AndroidFacet, packageName: String): Boolean { + try { + device.executeShellCommand(shellCommand, GenericReceiver(), 30L, TimeUnit.SECONDS) + info(String.format("%s %s%s on %s", command.description, enable.toState(), "d", device.name)) + return true + } catch (e: Exception) { + error("Failure while attempting to ${enable.toState()} ${command.description} on ${device.name}: " + e.message) + } + return false + } + + private fun Boolean.toState() = if (this) "enable" else "disable" +} diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt index c0f06632..cdd1eb12 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/GenericReceiver.kt @@ -1,12 +1,11 @@ package com.developerphil.adbidea.adb.command.receiver import com.android.ddmlib.MultiLineReceiver -import java.util.* import java.util.regex.Pattern class GenericReceiver : MultiLineReceiver() { - val adbOutputLines: MutableList = ArrayList() + val adbOutputLines= arrayListOf() private var errorMessage: String? = null override fun processNewLines(lines: Array) { diff --git a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt index c7b965b5..5bcb32e6 100644 --- a/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt +++ b/src/main/kotlin/com/developerphil/adbidea/adb/command/receiver/PrintReceiver.kt @@ -1,34 +1,23 @@ -package com.developerphil.adbidea.adb.command.receiver; +package com.developerphil.adbidea.adb.command.receiver -import com.android.ddmlib.IShellOutputReceiver; -import com.developerphil.adbidea.ui.Utils; -import com.google.common.base.Charsets; +import com.android.ddmlib.IShellOutputReceiver +import com.developerphil.adbidea.ui.Utils.Companion.isEmpty +import com.google.common.base.Charsets -public class PrintReceiver implements IShellOutputReceiver { - - private String mString; - - public final void addOutput(byte[] data, int offset, int length) { - if (!this.isCancelled()) { - mString = new String(data, offset, length, Charsets.UTF_8) + "\r\n"; +class PrintReceiver : IShellOutputReceiver { + private var mString: String? = null + override fun addOutput(data: ByteArray, offset: Int, length: Int) { + if (!this.isCancelled) { + mString = String(data, offset, length, Charsets.UTF_8) + "\r\n" } } - @Override - public void flush() { - - } - - public void done() { - } - - @Override - public boolean isCancelled() { - return false; + override fun flush() {} + override fun isCancelled(): Boolean { + return false } - @Override - public String toString() { - return Utils.Companion.isEmpty(mString) ? "" : mString; + override fun toString(): String { + return if (isEmpty(mString)) "" else mString!! } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt b/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt index dfb64ce5..3bf4ac58 100644 --- a/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt +++ b/src/main/kotlin/com/developerphil/adbidea/debugger/Debugger.kt @@ -26,7 +26,7 @@ class Debugger(private val project: Project, private val device: IDevice, privat private fun closeOldSessionAndRun(androidDebugger: AndroidDebugger<*>, client: Client) { terminateRunSessions(client) - androidDebugger.attachToClient(project, client) + androidDebugger.attachToClient(project, client,null) } // Disconnect any active run sessions to the same client @@ -34,7 +34,7 @@ class Debugger(private val project: Project, private val device: IDevice, privat val pid = selectedClient.clientData.pid // find if there are any active run sessions to the same client, and terminate them if so - for (handler in ExecutionManager.getInstance(project).runningProcesses) { + for (handler in ExecutionManager.getInstance(project).getRunningProcesses()) { if (handler is AndroidProcessHandler) { val client = handler.getClient(selectedClient.device) if (client != null && client.clientData.pid == pid) { diff --git a/src/main/kotlin/com/developerphil/adbidea/preference/ApplicationPreferences.kt b/src/main/kotlin/com/developerphil/adbidea/preference/ApplicationPreferences.kt new file mode 100644 index 00000000..c6154dd5 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/preference/ApplicationPreferences.kt @@ -0,0 +1,20 @@ +package com.developerphil.adbidea.preference + +import com.developerphil.adbidea.preference.accessor.PreferenceAccessor +import com.intellij.util.text.SemVer +import java.util.* + +private const val PREVIOUS_VERSION_PROPERTY = "com.developerphil.adbidea.previousversion" + +class ApplicationPreferences(private val preferenceAccessor: PreferenceAccessor) { + + fun savePreviousPluginVersion(semVer: SemVer) { + preferenceAccessor.saveString(PREVIOUS_VERSION_PROPERTY, semVer.toString()) + } + + fun getPreviousPluginVersion(): Optional { + val version = preferenceAccessor.getString(PREVIOUS_VERSION_PROPERTY, defaultValue = "") + return SemVer.parseFromText(version)?.let { Optional.of(it) } ?: Optional.empty() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/preference/ProjectPreferences.kt b/src/main/kotlin/com/developerphil/adbidea/preference/ProjectPreferences.kt new file mode 100644 index 00000000..24146dcb --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/preference/ProjectPreferences.kt @@ -0,0 +1,23 @@ +package com.developerphil.adbidea.preference + +import com.developerphil.adbidea.preference.accessor.PreferenceAccessor + +private const val SELECTED_SERIALS_PROPERTY = "com.developerphil.adbidea.selecteddevices" + +class ProjectPreferences(private val preferenceAccessor: PreferenceAccessor) { + + fun saveSelectedDeviceSerials(serials: List) { + preferenceAccessor.saveString(SELECTED_SERIALS_PROPERTY, serials.joinToString(separator = " ")) + } + + fun getSelectedDeviceSerials(): List { + return with(preferenceAccessor.getString(SELECTED_SERIALS_PROPERTY, "")) { + if (isEmpty()) { + emptyList() + } else { + split(" ") + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/accessor/preference/PreferenceAccessor.kt b/src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessor.kt similarity index 72% rename from src/main/kotlin/com/developerphil/adbidea/accessor/preference/PreferenceAccessor.kt rename to src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessor.kt index 88f4400d..a648c038 100644 --- a/src/main/kotlin/com/developerphil/adbidea/accessor/preference/PreferenceAccessor.kt +++ b/src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessor.kt @@ -1,4 +1,4 @@ -package com.developerphil.adbidea.accessor.preference +package com.developerphil.adbidea.preference.accessor interface PreferenceAccessor { fun saveString(key: String, value: String) diff --git a/src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessorImpl.kt b/src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessorImpl.kt new file mode 100644 index 00000000..e324fea7 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/preference/accessor/PreferenceAccessorImpl.kt @@ -0,0 +1,14 @@ +package com.developerphil.adbidea.preference.accessor + +import com.intellij.ide.util.PropertiesComponent + +class PreferenceAccessorImpl(private val propertiesComponent: PropertiesComponent) : PreferenceAccessor { + + override fun saveString(key: String, value: String) { + propertiesComponent.setValue(key, value) + } + + override fun getString(key: String, defaultValue: String): String { + return propertiesComponent.getValue(key) ?: defaultValue + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.kt b/src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.kt new file mode 100644 index 00000000..5d3817c8 --- /dev/null +++ b/src/main/kotlin/com/developerphil/adbidea/ui/DeviceChooserDialog.kt @@ -0,0 +1,76 @@ +package com.developerphil.adbidea.ui + +import com.android.ddmlib.IDevice +import com.developerphil.adbidea.ObjectGraph +import com.developerphil.adbidea.preference.ProjectPreferences +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.util.Disposer +import org.jetbrains.android.facet.AndroidFacet +import org.jetbrains.android.util.AndroidBundle +import org.joor.Reflect +import javax.swing.JCheckBox +import javax.swing.JComponent +import javax.swing.JPanel + +/** + * https://android.googlesource.com/platform/tools/adt/idea/+/refs/heads/mirror-goog-studio-master-dev/android/src/com/android/tools/idea/run/DeviceChooserDialog.java + */ +class DeviceChooserDialog(facet: AndroidFacet) : DialogWrapper(facet.module.project, true) { + + lateinit var myPanel: JPanel + lateinit var myDeviceChooserWrapper: JPanel + lateinit var useSameDeviceSCheckBox: JCheckBox + + private val myProject: Project + private val myDeviceChooser: MyDeviceChooser + private val projectPreferences: ProjectPreferences + + val selectedDevices: Array + get() = myDeviceChooser.selectedDevices + + init { + title = AndroidBundle.message("choose.device.dialog.title") + myProject = facet.module.project + projectPreferences = myProject.getComponent(ObjectGraph::class.java).projectPreferences + okAction.isEnabled = false + myDeviceChooser = MyDeviceChooser(true, okAction, facet, null) + Disposer.register(myDisposable, myDeviceChooser) + myDeviceChooser.addListener(object : DeviceChooserListener { + override fun selectedDevicesChanged() { + updateOkButton() + } + }) + myDeviceChooserWrapper.add(myDeviceChooser.panel) + myDeviceChooser.init(projectPreferences.getSelectedDeviceSerials()) + init() + updateOkButton() + } + + private fun persistSelectedSerialsToPreferences() { + projectPreferences.saveSelectedDeviceSerials(myDeviceChooser.selectedDevices.map { it.serialNumber }.toList()) + } + + private fun updateOkButton() { + okAction.isEnabled = selectedDevices.isNotEmpty() + } + + override fun getPreferredFocusedComponent(): JComponent? { + return try { + myDeviceChooser.preferredFocusComponent + } catch (e: NoSuchMethodError) { // that means that we are probably on a preview version of android studio or in intellij 13 + Reflect.on(myDeviceChooser).call("getDeviceTable").get() + } + } + + override fun doOKAction() { + myDeviceChooser.finish() + persistSelectedSerialsToPreferences() + super.doOKAction() + } + + override fun getDimensionServiceKey() = javaClass.canonicalName + override fun createCenterPanel(): JComponent = myPanel + + fun useSameDevices() = useSameDeviceSCheckBox.isSelected +} \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt b/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt index 7b42f9c4..edf2ad3d 100644 --- a/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ui/MyChooseModulesDialog.kt @@ -17,6 +17,6 @@ class MyChooseModulesDialog(project: Project, items: List, title: String } override fun getItemIcon(s: String): Icon? { - return if (s == ModuleChooserDialogHelper.DO_NOT_SELECT_THE_DEFAULT_MODULE) AllIcons.Actions.Clear else mIcon + return if (s == ModuleChooserDialogHelper.DO_NOT_SELECT_THE_DEFAULT_MODULE) AllIcons.Actions.Close else mIcon } } \ No newline at end of file diff --git a/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt b/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt index facbc6e6..9a4b5624 100755 --- a/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt +++ b/src/main/kotlin/com/developerphil/adbidea/ui/MyDeviceChooser.kt @@ -52,6 +52,8 @@ import javax.swing.table.AbstractTableModel /** * @author Eugene.Kudelevsky + * + * https://android.googlesource.com/platform/tools/adt/idea/+/refs/heads/mirror-goog-studio-master-dev/android/src/com/android/tools/idea/run/DeviceChooser.java */ class MyDeviceChooser(multipleSelection: Boolean, okAction: Action, diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index e18fb808..b19019f1 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,7 +1,7 @@ com.developerphil.adbidea - ADB Idea - 1.6.4 + ADB Idea + + 1.6.6 Philippe Breault and Void Young ADB Restart App
  • ADB Clear App Data
  • ADB Clear App Data and Restart
  • -
  • ADB Revoke Permissions
  • ADB Start App With Debugger
  • ADB Restart App With Debugger
  • +
  • ADB Grant/Revoke Permissions
  • +
  • ADB Enable/Disable Wi-Fi
  • +
  • ADB Enable/Disable Mobile Data
  • ADB Application management
  • ADB Application Interacting
  • ADB Device information
  • @@ -34,10 +36,18 @@ 1.6.4 + 1.6.6
      +
    • Update to origin repertory:
    • +
    • BUGFIX: Notifications don't show up on Studio 4.0
    • +
    • BUGFIX: Debugger sometime fails to attach on Studio 4.0
    • 1.6.4 +
    • BUGFIX: Can't attach a debugger on Android Studio 3.6
    • +
    • FEATURE: Enable/Disable Wi-Fi
    • +
    • FEATURE: Enable/Disable Mobile Data
    • +
    • BUGFIX: Compatibility with Android Studio 4.1-alpha07+
    • BUGFIX: The result of multi-module selection is inconsistent with the actual selection
    • -
    1.6.3 + + 1.6.3
    • update to origin : BUGFIX: Show all connected devices on Android Studio 3.4+
    @@ -149,9 +159,9 @@ ]]>
    - + - + com.intellij.modules.platform org.jetbrains.android @@ -165,6 +175,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -236,4 +308,10 @@ com.developerphil.adbidea.ObjectGraph -
    \ No newline at end of file + + + + com.developerphil.adbidea.Application + + + diff --git a/src/test/kotlin/com/developerphil/adbidea/PluginPreferencesTests.kt b/src/test/kotlin/com/developerphil/adbidea/PluginPreferencesTests.kt deleted file mode 100644 index 0a382987..00000000 --- a/src/test/kotlin/com/developerphil/adbidea/PluginPreferencesTests.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.developerphil.adbidea - -import com.developerphil.adbidea.accessor.preference.PreferenceAccessor -import org.junit.Assert.assertEquals -import org.junit.Test -import org.mockito.Mockito -import org.mockito.Mockito.mock -import org.mockito.Mockito.verify - -class PluginPreferencesTests { - - val prefAccessor: PreferenceAccessor = mock(PreferenceAccessor::class.java) - val pluginPrefs: PluginPreferences = PluginPreferencesImpl(prefAccessor) - - @Test - fun saveSelectedDeviceSerials_canSaveASingleSerial() { - pluginPrefs.saveSelectedDeviceSerials(listOf("first")) - - verifySave("first") - } - - @Test - fun saveSelectedDeviceSerials_canSaveAMultipleSerials() { - pluginPrefs.saveSelectedDeviceSerials(listOf("first", "second", "third")) - - verifySave("first second third") - } - - @Test - fun saveSelectedDeviceSerials_canSaveAnEmptyList() { - pluginPrefs.saveSelectedDeviceSerials(emptyList()) - - verifySave("") - } - - @Test - fun getSelectedDeviceSerials_canReturnASingleSerial() { - givenPreference("first") - - assertEquals(listOf("first"), pluginPrefs.getSelectedDeviceSerials()) - } - - @Test - fun getSelectedDeviceSerials_canReturnAMultipleSerials() { - givenPreference("first second third") - - assertEquals(listOf("first", "second", "third"), pluginPrefs.getSelectedDeviceSerials()) - } - - @Test - fun getSelectedDeviceSerials_canReturnAnEmptyList() { - givenPreference("") - - assertEquals(emptyList(), pluginPrefs.getSelectedDeviceSerials()) - } - - fun verifySave(string: String) { - verify(prefAccessor).saveString("com.developerphil.adbidea.selecteddevices", string) - } - - fun givenPreference(prefs: String) { - Mockito.`when`(prefAccessor.getString("com.developerphil.adbidea.selecteddevices", "")).thenReturn(prefs) - } - - -} \ No newline at end of file diff --git a/src/test/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelperTest.kt b/src/test/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelperTest.kt index 39197135..19f68b4f 100644 --- a/src/test/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelperTest.kt +++ b/src/test/kotlin/com/developerphil/adbidea/adb/UseSameDevicesHelperTest.kt @@ -1,15 +1,17 @@ package com.developerphil.adbidea import com.android.ddmlib.IDevice +import com.developerphil.adbidea.preference.accessor.InMemoryPreferenceAccessor import com.developerphil.adbidea.adb.Bridge import com.developerphil.adbidea.adb.FakeDevice import com.developerphil.adbidea.adb.UseSameDevicesHelper +import com.developerphil.adbidea.preference.ProjectPreferences import com.google.common.truth.Truth.assertThat import org.junit.Test class UseSameDevicesHelperTest { - val pluginPrefs = FakePrefs() + val pluginPrefs = ProjectPreferences(InMemoryPreferenceAccessor()) val bridge = FakeBridge() val helper: UseSameDevicesHelper = UseSameDevicesHelper(pluginPrefs, bridge) @@ -85,18 +87,5 @@ class UseSameDevicesHelperTest { } } - class FakePrefs : PluginPreferences { - var serials = emptyList() - override fun saveSelectedDeviceSerials(serials: List) { - } - - override fun getSelectedDeviceSerials(): List { - return serials - } - - fun willReturn(vararg ids: String) { - serials = ids.asList() - } - } - + private fun ProjectPreferences.willReturn(vararg ids: String) = saveSelectedDeviceSerials(ids.asList()) } \ No newline at end of file diff --git a/src/test/kotlin/com/developerphil/adbidea/preference/ApplicationPreferencesTests.kt b/src/test/kotlin/com/developerphil/adbidea/preference/ApplicationPreferencesTests.kt new file mode 100644 index 00000000..eb2892d5 --- /dev/null +++ b/src/test/kotlin/com/developerphil/adbidea/preference/ApplicationPreferencesTests.kt @@ -0,0 +1,34 @@ +package com.developerphil.adbidea.preference + +import com.developerphil.adbidea.preference.accessor.InMemoryPreferenceAccessor +import com.google.common.truth.Truth.assertThat +import com.intellij.util.text.SemVer +import org.junit.Test +import java.util.* + +class ApplicationPreferencesTests { + + private val prefAccessor = InMemoryPreferenceAccessor() + private val prefs: ApplicationPreferences = ApplicationPreferences(prefAccessor) + + @Test + fun `If no previous version is saved, return an empty optional`() { + assertThat(prefs.getPreviousPluginVersion()).isEqualTo(Optional.empty()) + } + + @Test + fun `If a previous version is saved, return it`() { + verifySaveAndRetrieveVersion("0.0.0") + verifySaveAndRetrieveVersion("1.2.3") + verifySaveAndRetrieveVersion("1.5.4") + verifySaveAndRetrieveVersion("1.6.0-SNAPSHOT") + } + + private fun verifySaveAndRetrieveVersion(version: String) { + prefAccessor.clear() + val semVer = SemVer.parseFromText(version)!! + prefs.savePreviousPluginVersion(semVer) + assertThat(prefs.getPreviousPluginVersion()).isEqualTo(Optional.of(semVer)) + } + +} \ No newline at end of file diff --git a/src/test/kotlin/com/developerphil/adbidea/preference/ProjectPreferencesTests.kt b/src/test/kotlin/com/developerphil/adbidea/preference/ProjectPreferencesTests.kt new file mode 100644 index 00000000..03ae9af5 --- /dev/null +++ b/src/test/kotlin/com/developerphil/adbidea/preference/ProjectPreferencesTests.kt @@ -0,0 +1,38 @@ +package com.developerphil.adbidea.preference + +import com.developerphil.adbidea.preference.accessor.InMemoryPreferenceAccessor +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class ProjectPreferencesTests { + + private val prefAccessor = InMemoryPreferenceAccessor() + private val prefs: ProjectPreferences = ProjectPreferences(prefAccessor) + + @Test + fun `Can save a single selected device`() { + val serials = listOf("first") + prefs.saveSelectedDeviceSerials(serials) + assertThat(prefs.getSelectedDeviceSerials()).isEqualTo(serials) + } + + @Test + fun `Can save multiple selected devices`() { + val serials = listOf("first", "second", "third") + prefs.saveSelectedDeviceSerials(serials) + assertThat(prefs.getSelectedDeviceSerials()).isEqualTo(serials) + } + + @Test + fun `Can save an empty selected devices list`() { + val serials = emptyList() + prefs.saveSelectedDeviceSerials(serials) + assertThat(prefs.getSelectedDeviceSerials()).isEqualTo(serials) + } + + @Test + fun `When no selected serials are saved, return an empty list`() { + assertThat(prefs.getSelectedDeviceSerials()).isEqualTo(emptyList()) + } + +} \ No newline at end of file diff --git a/src/test/kotlin/com/developerphil/adbidea/preference/accessor/InMemoryPreferenceAccessor.kt b/src/test/kotlin/com/developerphil/adbidea/preference/accessor/InMemoryPreferenceAccessor.kt new file mode 100644 index 00000000..0f4b1162 --- /dev/null +++ b/src/test/kotlin/com/developerphil/adbidea/preference/accessor/InMemoryPreferenceAccessor.kt @@ -0,0 +1,15 @@ +package com.developerphil.adbidea.preference.accessor + +class InMemoryPreferenceAccessor : PreferenceAccessor { + private val prefs = mutableMapOf() + + override fun saveString(key: String, value: String) { + prefs[key] = value + } + + override fun getString(key: String, defaultValue: String): String { + return prefs.getOrDefault(key, defaultValue) + } + + fun clear() = prefs.clear() +} \ No newline at end of file