├── Plugin
├── .idea
│ ├── .name
│ ├── copyright
│ │ ├── profiles_settings.xml
│ │ └── Apache2.xml
│ ├── vcs.xml
│ ├── modules.xml
│ ├── compiler.xml
│ └── misc.xml
├── android_device_controller.jar
├── resources
│ └── de
│ │ └── mobilej
│ │ └── plugin
│ │ └── adc
│ │ ├── plus.png
│ │ ├── Plugin.properties
│ │ └── locales.txt
├── android_device_controller.iml
├── META-INF
│ └── plugin.xml
└── src
│ └── de
│ └── mobilej
│ └── plugin
│ └── adc
│ ├── Storage.java
│ ├── Configuration.java
│ └── ToolWindowFactory.java
├── Enabler
├── app
│ ├── .gitignore
│ ├── config
│ │ └── debug.keystore
│ ├── src
│ │ └── main
│ │ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ └── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── mobilej
│ │ │ └── de
│ │ │ └── systemproppoker
│ │ │ ├── SetLocaleActivity.java
│ │ │ └── SystemPropPokerActivity.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── build.gradle
├── gradlew.bat
└── gradlew
├── .gitignore
├── README.md
└── LICENSE.txt
/Plugin/.idea/.name:
--------------------------------------------------------------------------------
1 | ADC
--------------------------------------------------------------------------------
/Enabler/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Enabler/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/Enabler/app/config/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/config/debug.keystore
--------------------------------------------------------------------------------
/Plugin/android_device_controller.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Plugin/android_device_controller.jar
--------------------------------------------------------------------------------
/Enabler/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Plugin/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Plugin/resources/de/mobilej/plugin/adc/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Plugin/resources/de/mobilej/plugin/adc/plus.png
--------------------------------------------------------------------------------
/Enabler/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/Enabler/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Enabler/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Enabler/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Enabler/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Enabler/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Enabler/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Plugin/resources/de/mobilej/plugin/adc/Plugin.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bjoernQ/adc/HEAD/Plugin/resources/de/mobilej/plugin/adc/Plugin.properties
--------------------------------------------------------------------------------
/Plugin/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Enabler/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 08 01:27:26 CET 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
7 |
--------------------------------------------------------------------------------
/Plugin/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Windows thumbnail db
19 | Thumbs.db
20 |
21 | # OSX files
22 | .DS_Store
23 |
24 | # Eclipse project files
25 | .classpath
26 | .project
27 |
28 | .gradle/
29 | build/
30 |
31 | out/
32 |
--------------------------------------------------------------------------------
/Enabler/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/bjoernquentin/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/Plugin/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Plugin/.idea/copyright/Apache2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Plugin/android_device_controller.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Enabler/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/Enabler/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
15 |
16 | buildscript {
17 | repositories {
18 | jcenter()
19 | }
20 | dependencies {
21 | classpath 'com.android.tools.build:gradle:1.3.0'
22 |
23 | // NOTE: Do not place your application dependencies here; they belong
24 | // in the individual module build.gradle files
25 | }
26 | }
27 |
28 | allprojects {
29 | repositories {
30 | jcenter()
31 | }
32 | }
33 |
34 | task clean(type: Delete) {
35 | delete rootProject.buildDir
36 | }
37 |
--------------------------------------------------------------------------------
/Enabler/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | apply plugin: 'com.android.application'
15 |
16 | android {
17 | compileSdkVersion 23
18 | buildToolsVersion "23.0.2"
19 |
20 | defaultConfig {
21 | applicationId "mobilej.de.systemproppoker"
22 | minSdkVersion 14
23 | targetSdkVersion 23
24 | versionCode 1
25 | versionName "1.0"
26 | }
27 |
28 | signingConfigs {
29 | debug {
30 | storeFile file('config/debug.keystore')
31 | storePassword 'android'
32 | keyAlias 'AndroidDebugKey'
33 | keyPassword 'android'
34 | }
35 | }
36 |
37 | buildTypes {
38 | release {
39 | minifyEnabled false
40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
41 | }
42 | }
43 | }
44 |
45 | dependencies {
46 | compile fileTree(dir: 'libs', include: ['*.jar'])
47 | testCompile 'junit:junit:4.12'
48 | }
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ADC Android Device Controller
2 |
3 | An Android Studio plugin to control your development devices and emulators. Currently you can do the following from within your IDE:
4 |
5 | - Toggle the "Show Layout Bounds"
6 | - Change the locale of the device
7 | - Open the currently active activity in your IDE (if the project contains that class)
8 | - Send text to the device (simulate keyboard input)
9 | - Clear Data (for all apps contained in current project)
10 | - Kill process of running app (great for testing "app killed in background" scenarios)
11 |
12 | More features to come.
13 |
14 | It has been used on devices running Lollipop and better. On older devices not all features might work as expected.
15 |
16 | # Installation
17 |
18 | The plugin is available from the plugins repository at https://plugins.jetbrains.com/plugin/8377?pr=androidstudio
19 |
20 | Just open _Settings_ and choose _Plugins_, _Browse repositories_ and search for _Android Device Controller_
21 |
22 | ## License
23 |
24 | ```
25 | Copyright 2016 Björn Quentin
26 |
27 | Licensed under the Apache License, Version 2.0 (the "License");
28 | you may not use this file except in compliance with the License.
29 | You may obtain a copy of the License at
30 |
31 | http://www.apache.org/licenses/LICENSE-2.0
32 |
33 | Unless required by applicable law or agreed to in writing, software
34 | distributed under the License is distributed on an "AS IS" BASIS,
35 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36 | See the License for the specific language governing permissions and
37 | limitations under the License.
38 | ```
39 |
--------------------------------------------------------------------------------
/Enabler/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Plugin/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | de.mobilej.adc.plugin.id
3 | Android Device Controller
4 | 1.0.8
5 | http://github.com/bjoernQ/adc
6 |
7 | com.intellij.modules.androidstudio
8 | org.jetbrains.android
9 |
10 |
11 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 | com.intellij.modules.platform
24 | org.jetbrains.android
25 |
26 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Plugin/src/de/mobilej/plugin/adc/Storage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | package de.mobilej.plugin.adc;
15 |
16 | import com.intellij.openapi.components.PersistentStateComponent;
17 | import com.intellij.openapi.components.State;
18 | import com.intellij.openapi.components.StoragePathMacros;
19 | import com.intellij.util.xmlb.XmlSerializerUtil;
20 | import org.jetbrains.annotations.Nullable;
21 |
22 | /**
23 | * Storage for the plugin
24 | *
25 | * Created by bjoern on 01.06.2016.
26 | */
27 | @State(name = "ADCSettings",
28 | storages = {@com.intellij.openapi.components.Storage(
29 | file = StoragePathMacros.APP_CONFIG + "/adc_settings.xml")})
30 | public class Storage implements PersistentStateComponent {
31 |
32 | private String lastSentText = "";
33 | private String installedOnDevices;
34 |
35 | @Nullable
36 | @Override
37 | public Storage getState() {
38 | return this;
39 | }
40 |
41 | @Override
42 | public void loadState(Storage storage) {
43 | XmlSerializerUtil.copyBean(storage, this);
44 | }
45 |
46 | public void setLastSentText(String lastSentText) {
47 | this.lastSentText = lastSentText;
48 | }
49 |
50 | public String getLastSentText() {
51 | return lastSentText;
52 | }
53 |
54 | public String getInstalledOnDevices() {
55 | return installedOnDevices;
56 | }
57 |
58 | public void setInstalledOnDevices(String installedOnDevices) {
59 | this.installedOnDevices = installedOnDevices;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Plugin/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Plugin/src/de/mobilej/plugin/adc/Configuration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | package de.mobilej.plugin.adc;
15 |
16 | import com.intellij.openapi.components.ServiceManager;
17 | import com.intellij.openapi.options.Configurable;
18 | import com.intellij.openapi.options.ConfigurationException;
19 | import com.intellij.openapi.project.Project;
20 | import org.jetbrains.annotations.Nls;
21 | import org.jetbrains.annotations.Nullable;
22 |
23 | import javax.swing.*;
24 | import java.awt.event.ActionEvent;
25 | import java.awt.event.ActionListener;
26 |
27 | /**
28 | * Configuration for the plugin
29 | *
30 | * Created by bjoern on 24.07.2017.
31 | */
32 | public class Configuration implements Configurable {
33 |
34 | private Storage storage;
35 |
36 | private boolean modified = false;
37 | private boolean clearDevicesClicked = false;
38 |
39 | public Configuration(Project project){
40 | this.storage = ServiceManager.getService(project, Storage.class);
41 | }
42 |
43 | @Nls
44 | @Override
45 | public String getDisplayName() {
46 | return "ADC";
47 | }
48 |
49 | @Nullable
50 | @Override
51 | public JComponent createComponent() {
52 | JComponent panel = new JPanel();
53 | BoxLayout layout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
54 | panel.setLayout(layout);
55 |
56 | JButton clearDevices = new JButton("Clear known devices");
57 | panel.add(clearDevices);
58 |
59 | clearDevices.addActionListener(actionEvent -> {
60 | modified = true;
61 | clearDevicesClicked = true;
62 | });
63 |
64 | return panel;
65 | }
66 |
67 | @Override
68 | public boolean isModified() {
69 | return modified;
70 | }
71 |
72 | @Override
73 | public void apply() throws ConfigurationException {
74 | if(clearDevicesClicked) {
75 | storage.setInstalledOnDevices("");
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Enabler/app/src/main/java/mobilej/de/systemproppoker/SetLocaleActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package mobilej.de.systemproppoker;
14 |
15 | import android.app.Activity;
16 | import android.content.res.Configuration;
17 | import android.os.Bundle;
18 |
19 | import java.lang.reflect.Field;
20 | import java.lang.reflect.Method;
21 | import java.util.Locale;
22 |
23 | /**
24 | * Created by bjoernquentin on 08.11.15.
25 | */
26 | public class SetLocaleActivity extends Activity {
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | String lang = getIntent().getStringExtra("language");
32 | String country = getIntent().getStringExtra("country");
33 | SetLocaleActivity.updateLocale(new Locale(lang, country));
34 | finish();
35 | }
36 |
37 |
38 | public static void updateLocale(Locale locale) {
39 | try {
40 | System.out.println("in");
41 | Method activityManagerNativegetDefaultMethod = Class.forName("android.app.ActivityManagerNative").getDeclaredMethod("getDefault");
42 | Object am = activityManagerNativegetDefaultMethod.invoke(null);
43 |
44 | Configuration config = (Configuration) am.getClass().getDeclaredMethod("getConfiguration").invoke(am);
45 |
46 | config.locale = locale;
47 |
48 | // indicate this isn't some passing default - the user wants this remembered
49 | Field userSetLocaleField = Configuration.class.getDeclaredField("userSetLocale");
50 | userSetLocaleField.set(config, true);
51 |
52 | am.getClass().getDeclaredMethod("updateConfiguration", Configuration.class).invoke(am, config);
53 | // Trigger the dirty bit for the Settings Provider.
54 | // BackupManager.dataChanged("com.android.providers.settings");
55 |
56 | } catch (Exception e) {
57 | e.printStackTrace();
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Enabler/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/Enabler/app/src/main/java/mobilej/de/systemproppoker/SystemPropPokerActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package mobilej.de.systemproppoker;
14 |
15 | import android.app.Activity;
16 | import android.os.AsyncTask;
17 | import android.os.Bundle;
18 | import android.os.IBinder;
19 | import android.os.Parcel;
20 | import android.os.RemoteException;
21 | import android.util.Log;
22 |
23 | import java.lang.reflect.Method;
24 |
25 | /**
26 | * Created by bjoernquentin on 08.11.15.
27 | */
28 | public class SystemPropPokerActivity extends Activity {
29 |
30 | private static int SYSPROPS_TRANSACTION = ('_' << 24) | ('S' << 16) | ('P' << 8) | 'R';
31 | private static final String TAG = "poker";
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | new SystemPropPoker().execute();
37 | finish();
38 | }
39 |
40 | static class SystemPropPoker extends AsyncTask {
41 |
42 | @Override
43 | protected Void doInBackground(Void... params) {
44 | try {
45 | String[] services;
46 | try {
47 | Method listServicesMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("listServices");
48 | services = (String[]) listServicesMethod.invoke(null);
49 | } catch (Exception e) {
50 | return null;
51 | }
52 |
53 | if (services == null || services.length == 0) {
54 | services = new String[]{"phone", "iphonesubinfo", "simphonebook", "isms", "media_router", "print", "assetatlas", "dreams", "commontime_management", "samplingprofiler", "diskstats", "appwidget", "backup", "uimode", "serial", "usb", "audio", "wallpaper", "dropbox", "search", "country_detector", "location", "notification", "updatelock", "servicediscovery", "connectivity", "wifi", "wifip2p", "netpolicy", "netstats", "textservices", "network_management", "clipboard", "statusbar", "device_policy", "lock_settings", "mount", "accessibility", "input_method", "input", "window", "alarm", "consumer_ir", "vibrator", "battery", "hardware", "content", "account", "user", "entropy", "permission", "cpuinfo", "dbinfo", "gfxinfo", "meminfo", "procstats", "activity", "package", "scheduling_policy", "telephony.registry", "display", "appops", "usagestats", "batterystats", "power", "sensorservice", "batterypropreg", "media.audio_policy", "media.camera", "media.player", "media.audio_flinger", "drm.drmManager", "SurfaceFlinger", "android.security.keystore"}; // TODO find the right services ...
55 | }
56 |
57 | for (String service : services) {
58 | Method checkServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("checkService", String.class);
59 | IBinder obj = (IBinder) checkServiceMethod.invoke(null, service);
60 | if (obj != null) {
61 | Parcel data = Parcel.obtain();
62 | try {
63 | obj.transact(SYSPROPS_TRANSACTION, data, null, 0);
64 | } catch (RemoteException e) {
65 | } catch (Exception e) {
66 | Log.i(TAG, "Someone wrote a bad service '" + service
67 | + "' that doesn't like to be poked: " + e);
68 | }
69 | data.recycle();
70 | }
71 | }
72 |
73 | } catch (Exception e) {
74 | return null;
75 | }
76 |
77 | return null;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Enabler/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2018 Björn Quentin
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/Plugin/resources/de/mobilej/plugin/adc/locales.txt:
--------------------------------------------------------------------------------
1 | de_DE [German (Germany)]
2 | en_US [English (United States)]
3 | en_XA [English (Pseudo Localisation ltr)]
4 | ar_XB [Arabic (Pseudo Localisation rtl)]
5 | af_NA [Afrikaans (Namibia)]
6 | af_ZA [Afrikaans (South Africa)]
7 | agq_CM [Aghem (Cameroon)]
8 | ak_GH [Akan (Ghana)]
9 | am_ET [Amharic (Ethiopia)]
10 | ar_001 [Arabic (World)]
11 | ar_AE [Arabic (United Arab Emirates)]
12 | ar_BH [Arabic (Bahrain)]
13 | ar_DJ [Arabic (Djibouti)]
14 | ar_DZ [Arabic (Algeria)]
15 | ar_EG [Arabic (Egypt)]
16 | ar_EH [Arabic (Western Sahara)]
17 | ar_ER [Arabic (Eritrea)]
18 | ar_IL [Arabic (Israel)]
19 | ar_IQ [Arabic (Iraq)]
20 | ar_JO [Arabic (Jordan)]
21 | ar_KM [Arabic (Comoros)]
22 | ar_KW [Arabic (Kuwait)]
23 | ar_LB [Arabic (Lebanon)]
24 | ar_LY [Arabic (Libya)]
25 | ar_MA [Arabic (Morocco)]
26 | ar_MR [Arabic (Mauritania)]
27 | ar_OM [Arabic (Oman)]
28 | ar_PS [Arabic (Palestine)]
29 | ar_QA [Arabic (Qatar)]
30 | ar_SA [Arabic (Saudi Arabia)]
31 | ar_SD [Arabic (Sudan)]
32 | ar_SO [Arabic (Somalia)]
33 | ar_SS [Arabic (South Sudan)]
34 | ar_SY [Arabic (Syria)]
35 | ar_TD [Arabic (Chad)]
36 | ar_TN [Arabic (Tunisia)]
37 | ar_YE [Arabic (Yemen)]
38 | as_IN [Assamese (India)]
39 | asa_TZ [Asu (Tanzania)]
40 | az_AZ [Azerbaijani (Cyrillic,Azerbaijan)]
41 | az_AZ [Azerbaijani (Latin,Azerbaijan)]
42 | bas_CM [Basaa (Cameroon)]
43 | be_BY [Belarusian (Belarus)]
44 | bem_ZM [Bemba (Zambia)]
45 | bez_TZ [Bena (Tanzania)]
46 | bg_BG [Bulgarian (Bulgaria)]
47 | bm_ML [Bambara (Mali)]
48 | bn_BD [Bengali (Bangladesh)]
49 | bn_IN [Bengali (India)]
50 | bo_CN [Tibetan (China)]
51 | bo_IN [Tibetan (India)]
52 | br_FR [Breton (France)]
53 | brx_IN [Bodo (India)]
54 | bs_BA [Bosnian (Cyrillic,Bosnia and Herzegovina)]
55 | bs_BA [Bosnian (Latin,Bosnia and Herzegovina)]
56 | ca_AD [Catalan (Andorra)]
57 | ca_ES [Catalan (Spain)]
58 | ca_FR [Catalan (France)]
59 | ca_IT [Catalan (Italy)]
60 | cgg_UG [Chiga (Uganda)]
61 | chr_US [Cherokee (United States)]
62 | cs_CZ [Czech (Czech Republic)]
63 | cy_GB [Welsh (United Kingdom)]
64 | da_DK [Danish (Denmark)]
65 | da_GL [Danish (Greenland)]
66 | dav_KE [Taita (Kenya)]
67 | de_AT [German (Austria)]
68 | de_BE [German (Belgium)]
69 | de_CH [German (Switzerland)]
70 | de_DE [German (Germany)]
71 | de_LI [German (Liechtenstein)]
72 | de_LU [German (Luxembourg)]
73 | dje_NE [Zarma (Niger)]
74 | dua_CM [Duala (Cameroon)]
75 | dyo_SN [Jola-Fonyi (Senegal)]
76 | dz_BT [Dzongkha (Bhutan)]
77 | ebu_KE [Embu (Kenya)]
78 | ee_GH [Ewe (Ghana)]
79 | ee_TG [Ewe (Togo)]
80 | el_CY [Greek (Cyprus)]
81 | el_GR [Greek (Greece)]
82 | en_001 [English (World)]
83 | en_150 [English (Europe)]
84 | en_AG [English (Antigua and Barbuda)]
85 | en_AI [English (Anguilla)]
86 | en_AS [English (American Samoa)]
87 | en_AU [English (Australia)]
88 | en_BB [English (Barbados)]
89 | en_BE [English (Belgium)]
90 | en_BM [English (Bermuda)]
91 | en_BS [English (Bahamas)]
92 | en_BW [English (Botswana)]
93 | en_BZ [English (Belize)]
94 | en_CA [English (Canada)]
95 | en_CC [English (Cocos (Keeling) Islands)]
96 | en_CK [English (Cook Islands)]
97 | en_CM [English (Cameroon)]
98 | en_CX [English (Christmas Island)]
99 | en_DG [English (Diego Garcia)]
100 | en_DM [English (Dominica)]
101 | en_ER [English (Eritrea)]
102 | en_FJ [English (Fiji)]
103 | en_FK [English (Falkland Islands (Islas Malvinas))]
104 | en_FM [English (Micronesia)]
105 | en_GB [English (United Kingdom)]
106 | en_GD [English (Grenada)]
107 | en_GG [English (Guernsey)]
108 | en_GH [English (Ghana)]
109 | en_GI [English (Gibraltar)]
110 | en_GM [English (Gambia)]
111 | en_GU [English (Guam)]
112 | en_GY [English (Guyana)]
113 | en_HK [English (Hong Kong)]
114 | en_IE [English (Ireland)]
115 | en_IM [English (Isle of Man)]
116 | en_IN [English (India)]
117 | en_IO [English (British Indian Ocean Territory)]
118 | en_JE [English (Jersey)]
119 | en_JM [English (Jamaica)]
120 | en_KE [English (Kenya)]
121 | en_KI [English (Kiribati)]
122 | en_KN [English (Saint Kitts and Nevis)]
123 | en_KY [English (Cayman Islands)]
124 | en_LC [English (Saint Lucia)]
125 | en_LR [English (Liberia)]
126 | en_LS [English (Lesotho)]
127 | en_MG [English (Madagascar)]
128 | en_MH [English (Marshall Islands)]
129 | en_MO [English (Macau)]
130 | en_MP [English (Northern Mariana Islands)]
131 | en_MS [English (Montserrat)]
132 | en_MT [English (Malta)]
133 | en_MU [English (Mauritius)]
134 | en_MW [English (Malawi)]
135 | en_NA [English (Namibia)]
136 | en_NF [English (Norfolk Island)]
137 | en_NG [English (Nigeria)]
138 | en_NR [English (Nauru)]
139 | en_NU [English (Niue)]
140 | en_NZ [English (New Zealand)]
141 | en_PG [English (Papua New Guinea)]
142 | en_PH [English (Philippines)]
143 | en_PK [English (Pakistan)]
144 | en_PN [English (Pitcairn Islands)]
145 | en_PR [English (Puerto Rico)]
146 | en_PW [English (Palau)]
147 | en_RW [English (Rwanda)]
148 | en_SB [English (Solomon Islands)]
149 | en_SC [English (Seychelles)]
150 | en_SD [English (Sudan)]
151 | en_SG [English (Singapore)]
152 | en_SH [English (Saint Helena)]
153 | en_SL [English (Sierra Leone)]
154 | en_SS [English (South Sudan)]
155 | en_SX [English (Sint Maarten)]
156 | en_SZ [English (Swaziland)]
157 | en_TC [English (Turks and Caicos Islands)]
158 | en_TK [English (Tokelau)]
159 | en_TO [English (Tonga)]
160 | en_TT [English (Trinidad and Tobago)]
161 | en_TV [English (Tuvalu)]
162 | en_TZ [English (Tanzania)]
163 | en_UG [English (Uganda)]
164 | en_UM [English (U.S. Outlying Islands)]
165 | en_US [English (United States)]
166 | en_US [English (United States,Computer)]
167 | en_VC [English (St. Vincent & Grenadines)]
168 | en_VG [English (British Virgin Islands)]
169 | en_VI [English (U.S. Virgin Islands)]
170 | en_VU [English (Vanuatu)]
171 | en_WS [English (Samoa)]
172 | en_ZA [English (South Africa)]
173 | en_ZM [English (Zambia)]
174 | en_ZW [English (Zimbabwe)]
175 | es_419 [Spanish (Latin America)]
176 | es_AR [Spanish (Argentina)]
177 | es_BO [Spanish (Bolivia)]
178 | es_CL [Spanish (Chile)]
179 | es_CO [Spanish (Colombia)]
180 | es_CR [Spanish (Costa Rica)]
181 | es_CU [Spanish (Cuba)]
182 | es_DO [Spanish (Dominican Republic)]
183 | es_EA [Spanish (Ceuta and Melilla)]
184 | es_EC [Spanish (Ecuador)]
185 | es_ES [Spanish (Spain)]
186 | es_GQ [Spanish (Equatorial Guinea)]
187 | es_GT [Spanish (Guatemala)]
188 | es_HN [Spanish (Honduras)]
189 | es_IC [Spanish (Canary Islands)]
190 | es_MX [Spanish (Mexico)]
191 | es_NI [Spanish (Nicaragua)]
192 | es_PA [Spanish (Panama)]
193 | es_PE [Spanish (Peru)]
194 | es_PH [Spanish (Philippines)]
195 | es_PR [Spanish (Puerto Rico)]
196 | es_PY [Spanish (Paraguay)]
197 | es_SV [Spanish (El Salvador)]
198 | es_US [Spanish (United States)]
199 | es_UY [Spanish (Uruguay)]
200 | es_VE [Spanish (Venezuela)]
201 | et_EE [Estonian (Estonia)]
202 | eu_ES [Basque (Spain)]
203 | ewo_CM [Ewondo (Cameroon)]
204 | fa_AF [Persian (Afghanistan)]
205 | fa_IR [Persian (Iran)]
206 | ff_SN [Fulah (Senegal)]
207 | fi_FI [Finnish (Finland)]
208 | fil_PH [Filipino (Philippines)]
209 | fo_FO [Faroese (Faroe Islands)]
210 | fr_BE [French (Belgium)]
211 | fr_BF [French (Burkina Faso)]
212 | fr_BI [French (Burundi)]
213 | fr_BJ [French (Benin)]
214 | fr_BL [French (Saint Barthélemy)]
215 | fr_CA [French (Canada)]
216 | fr_CD [French (Congo (DRC))]
217 | fr_CF [French (Central African Republic)]
218 | fr_CG [French (Congo (Republic))]
219 | fr_CH [French (Switzerland)]
220 | fr_CI [French (Côte d’Ivoire)]
221 | fr_CM [French (Cameroon)]
222 | fr_DJ [French (Djibouti)]
223 | fr_DZ [French (Algeria)]
224 | fr_FR [French (France)]
225 | fr_GA [French (Gabon)]
226 | fr_GF [French (French Guiana)]
227 | fr_GN [French (Guinea)]
228 | fr_GP [French (Guadeloupe)]
229 | fr_GQ [French (Equatorial Guinea)]
230 | fr_HT [French (Haiti)]
231 | fr_KM [French (Comoros)]
232 | fr_LU [French (Luxembourg)]
233 | fr_MA [French (Morocco)]
234 | fr_MC [French (Monaco)]
235 | fr_MF [French (Saint Martin)]
236 | fr_MG [French (Madagascar)]
237 | fr_ML [French (Mali)]
238 | fr_MQ [French (Martinique)]
239 | fr_MR [French (Mauritania)]
240 | fr_MU [French (Mauritius)]
241 | fr_NC [French (New Caledonia)]
242 | fr_NE [French (Niger)]
243 | fr_PF [French (French Polynesia)]
244 | fr_PM [French (Saint Pierre and Miquelon)]
245 | fr_RE [French (Réunion)]
246 | fr_RW [French (Rwanda)]
247 | fr_SC [French (Seychelles)]
248 | fr_SN [French (Senegal)]
249 | fr_SY [French (Syria)]
250 | fr_TD [French (Chad)]
251 | fr_TG [French (Togo)]
252 | fr_TN [French (Tunisia)]
253 | fr_VU [French (Vanuatu)]
254 | fr_WF [French (Wallis and Futuna)]
255 | fr_YT [French (Mayotte)]
256 | ga_IE [Irish (Ireland)]
257 | gl_ES [Galician (Spain)]
258 | gsw_CH [Swiss German (Switzerland)]
259 | gsw_LI [Swiss German (Liechtenstein)]
260 | gu_IN [Gujarati (India)]
261 | guz_KE [Gusii (Kenya)]
262 | gv_IM [Manx (Isle of Man)]
263 | ha_GH [Hausa (Latin,Ghana)]
264 | ha_NE [Hausa (Latin,Niger)]
265 | ha_NG [Hausa (Latin,Nigeria)]
266 | haw_US [Hawaiian (United States)]
267 | iw_IL [Hebrew (Israel)]
268 | hi_IN [Hindi (India)]
269 | hr_BA [Croatian (Bosnia and Herzegovina)]
270 | hr_HR [Croatian (Croatia)]
271 | hu_HU [Hungarian (Hungary)]
272 | hy_AM [Armenian (Armenia)]
273 | in_ID [Indonesian (Indonesia)]
274 | ig_NG [Igbo (Nigeria)]
275 | ii_CN [Sichuan Yi (China)]
276 | is_IS [Icelandic (Iceland)]
277 | it_CH [Italian (Switzerland)]
278 | it_IT [Italian (Italy)]
279 | it_SM [Italian (San Marino)]
280 | ja_JP [Japanese (Japan)]
281 | jgo_CM [Ngomba (Cameroon)]
282 | jmc_TZ [Machame (Tanzania)]
283 | ka_GE [Georgian (Georgia)]
284 | kab_DZ [Kabyle (Algeria)]
285 | kam_KE [Kamba (Kenya)]
286 | kde_TZ [Makonde (Tanzania)]
287 | kea_CV [Kabuverdianu (Cape Verde)]
288 | khq_ML [Koyra Chiini (Mali)]
289 | ki_KE [Kikuyu (Kenya)]
290 | kk_KZ [Kazakh (Cyrillic,Kazakhstan)]
291 | kkj_CM [Kako (Cameroon)]
292 | kl_GL [Kalaallisut (Greenland)]
293 | kln_KE [Kalenjin (Kenya)]
294 | km_KH [Khmer (Cambodia)]
295 | kn_IN [Kannada (India)]
296 | ko_KP [Korean (North Korea)]
297 | ko_KR [Korean (South Korea)]
298 | kok_IN [Konkani (India)]
299 | ks_IN [Kashmiri (Arabic,India)]
300 | ksb_TZ [Shambala (Tanzania)]
301 | ksf_CM [Bafia (Cameroon)]
302 | kw_GB [Cornish (United Kingdom)]
303 | ky_KG [Kyrgyz (Cyrillic,Kyrgyzstan)]
304 | lag_TZ [Langi (Tanzania)]
305 | lg_UG [Ganda (Uganda)]
306 | lkt_US [Lakota (United States)]
307 | ln_AO [Lingala (Angola)]
308 | ln_CD [Lingala (Congo (DRC))]
309 | ln_CF [Lingala (Central African Republic)]
310 | ln_CG [Lingala (Congo (Republic))]
311 | lo_LA [Lao (Laos)]
312 | lt_LT [Lithuanian (Lithuania)]
313 | lu_CD [Luba-Katanga (Congo (DRC))]
314 | luo_KE [Luo (Kenya)]
315 | luy_KE [Luyia (Kenya)]
316 | lv_LV [Latvian (Latvia)]
317 | mas_KE [Masai (Kenya)]
318 | mas_TZ [Masai (Tanzania)]
319 | mer_KE [Meru (Kenya)]
320 | mfe_MU [Morisyen (Mauritius)]
321 | mg_MG [Malagasy (Madagascar)]
322 | mgh_MZ [Makhuwa-Meetto (Mozambique)]
323 | mgo_CM [Meta' (Cameroon)]
324 | mk_MK [Macedonian (Macedonia (FYROM))]
325 | ml_IN [Malayalam (India)]
326 | mn_MN [Mongolian (Cyrillic,Mongolia)]
327 | mr_IN [Marathi (India)]
328 | ms_BN [Malay (Latin,Brunei)]
329 | ms_MY [Malay (Latin,Malaysia)]
330 | ms_SG [Malay (Latin,Singapore)]
331 | mt_MT [Maltese (Malta)]
332 | mua_CM [Mundang (Cameroon)]
333 | my_MM [Burmese (Myanmar (Burma))]
334 | naq_NA [Nama (Namibia)]
335 | nb_NO [Norwegian Bokmål (Norway)]
336 | nb_SJ [Norwegian Bokmål (Svalbard and Jan Mayen)]
337 | nd_ZW [North Ndebele (Zimbabwe)]
338 | ne_IN [Nepali (India)]
339 | ne_NP [Nepali (Nepal)]
340 | nl_AW [Dutch (Aruba)]
341 | nl_BE [Dutch (Belgium)]
342 | nl_BQ [Dutch (Caribbean Netherlands)]
343 | nl_CW [Dutch (Curaçao)]
344 | nl_NL [Dutch (Netherlands)]
345 | nl_SR [Dutch (Suriname)]
346 | nl_SX [Dutch (Sint Maarten)]
347 | nmg_CM [Kwasio (Cameroon)]
348 | nn_NO [Norwegian Nynorsk (Norway)]
349 | nnh_CM [Ngiemboon (Cameroon)]
350 | nus_SD [Nuer (Sudan)]
351 | nyn_UG [Nyankole (Uganda)]
352 | om_ET [Oromo (Ethiopia)]
353 | om_KE [Oromo (Kenya)]
354 | or_IN [Oriya (India)]
355 | pa_PK [Punjabi (Arabic,Pakistan)]
356 | pa_IN [Punjabi (Gurmukhi,India)]
357 | pl_PL [Polish (Poland)]
358 | ps_AF [Pashto (Afghanistan)]
359 | pt_AO [Portuguese (Angola)]
360 | pt_BR [Portuguese (Brazil)]
361 | pt_CV [Portuguese (Cape Verde)]
362 | pt_GW [Portuguese (Guinea-Bissau)]
363 | pt_MO [Portuguese (Macau)]
364 | pt_MZ [Portuguese (Mozambique)]
365 | pt_PT [Portuguese (Portugal)]
366 | pt_ST [Portuguese (São Tomé and Príncipe)]
367 | pt_TL [Portuguese (Timor-Leste)]
368 | rm_CH [Romansh (Switzerland)]
369 | rn_BI [Rundi (Burundi)]
370 | ro_MD [Romanian (Moldova)]
371 | ro_RO [Romanian (Romania)]
372 | rof_TZ [Rombo (Tanzania)]
373 | ru_BY [Russian (Belarus)]
374 | ru_KG [Russian (Kyrgyzstan)]
375 | ru_KZ [Russian (Kazakhstan)]
376 | ru_MD [Russian (Moldova)]
377 | ru_RU [Russian (Russia)]
378 | ru_UA [Russian (Ukraine)]
379 | rw_RW [Kinyarwanda (Rwanda)]
380 | rwk_TZ [Rwa (Tanzania)]
381 | saq_KE [Samburu (Kenya)]
382 | sbp_TZ [Sangu (Tanzania)]
383 | seh_MZ [Sena (Mozambique)]
384 | ses_ML [Koyraboro Senni (Mali)]
385 | sg_CF [Sango (Central African Republic)]
386 | shi_MA [Tachelhit (Latin,Morocco)]
387 | shi_MA [Tachelhit (Tifinagh,Morocco)]
388 | si_LK [Sinhala (Sri Lanka)]
389 | sk_SK [Slovak (Slovakia)]
390 | sl_SI [Slovenian (Slovenia)]
391 | sn_ZW [Shona (Zimbabwe)]
392 | so_DJ [Somali (Djibouti)]
393 | so_ET [Somali (Ethiopia)]
394 | so_KE [Somali (Kenya)]
395 | so_SO [Somali (Somalia)]
396 | sq_AL [Albanian (Albania)]
397 | sq_MK [Albanian (Macedonia (FYROM))]
398 | sq_XK [Albanian (Kosovo)]
399 | sr_BA [Serbian (Cyrillic,Bosnia and Herzegovina)]
400 | sr_ME [Serbian (Cyrillic,Montenegro)]
401 | sr_RS [Serbian (Cyrillic,Serbia)]
402 | sr_XK [Serbian (Cyrillic,Kosovo)]
403 | sr_BA [Serbian (Latin,Bosnia and Herzegovina)]
404 | sr_ME [Serbian (Latin,Montenegro)]
405 | sr_RS [Serbian (Latin,Serbia)]
406 | sr_XK [Serbian (Latin,Kosovo)]
407 | sv_AX [Swedish (Åland Islands)]
408 | sv_FI [Swedish (Finland)]
409 | sv_SE [Swedish (Sweden)]
410 | sw_KE [Swahili (Kenya)]
411 | sw_TZ [Swahili (Tanzania)]
412 | sw_UG [Swahili (Uganda)]
413 | swc_CD [Congo Swahili (Congo (DRC))]
414 | ta_IN [Tamil (India)]
415 | ta_LK [Tamil (Sri Lanka)]
416 | ta_MY [Tamil (Malaysia)]
417 | ta_SG [Tamil (Singapore)]
418 | te_IN [Telugu (India)]
419 | teo_KE [Teso (Kenya)]
420 | teo_UG [Teso (Uganda)]
421 | th_TH [Thai (Thailand)]
422 | ti_ER [Tigrinya (Eritrea)]
423 | ti_ET [Tigrinya (Ethiopia)]
424 | to_TO [Tongan (Tonga)]
425 | tr_CY [Turkish (Cyprus)]
426 | tr_TR [Turkish (Turkey)]
427 | twq_NE [Tasawaq (Niger)]
428 | tzm_MA [Central Atlas Tamazight (Latin,Morocco)]
429 | ug_CN [Uyghur (Arabic,China)]
430 | uk_UA [Ukrainian (Ukraine)]
431 | ur_IN [Urdu (India)]
432 | ur_PK [Urdu (Pakistan)]
433 | uz_AF [Uzbek (Arabic,Afghanistan)]
434 | uz_UZ [Uzbek (Cyrillic,Uzbekistan)]
435 | uz_UZ [Uzbek (Latin,Uzbekistan)]
436 | vai_LR [Vai (Latin,Liberia)]
437 | vai_LR [Vai (Vai,Liberia)]
438 | vi_VN [Vietnamese (Vietnam)]
439 | vun_TZ [Vunjo (Tanzania)]
440 | xog_UG [Soga (Uganda)]
441 | yav_CM [Yangben (Cameroon)]
442 | yo_BJ [Yoruba (Benin)]
443 | yo_NG [Yoruba (Nigeria)]
444 | zgh_MA [Standard Moroccan Tamazight (Morocco)]
445 | zh_CN [Chinese (Simplified Han,China)]
446 | zh_HK [Chinese (Simplified Han,Hong Kong)]
447 | zh_MO [Chinese (Simplified Han,Macau)]
448 | zh_SG [Chinese (Simplified Han,Singapore)]
449 | zh_HK [Chinese (Traditional Han,Hong Kong)]
450 | zh_MO [Chinese (Traditional Han,Macau)]
451 | zh_TW [Chinese (Traditional Han,Taiwan)]
452 | zu_ZA [Zulu (South Africa)]
453 |
--------------------------------------------------------------------------------
/Plugin/src/de/mobilej/plugin/adc/ToolWindowFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Björn Quentin
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | package de.mobilej.plugin.adc;
15 |
16 | import com.android.ddmlib.*;
17 | import com.android.tools.idea.model.AndroidModel;
18 | import com.intellij.facet.ProjectFacetManager;
19 | import com.intellij.openapi.application.ApplicationManager;
20 | import com.intellij.openapi.components.ServiceManager;
21 | import com.intellij.openapi.diagnostic.Logger;
22 | import com.intellij.openapi.fileEditor.FileEditorManager;
23 | import com.intellij.openapi.fileEditor.OpenFileDescriptor;
24 | import com.intellij.openapi.progress.ProgressManager;
25 | import com.intellij.openapi.project.Project;
26 | import com.intellij.openapi.ui.ComboBox;
27 | import com.intellij.openapi.ui.Messages;
28 | import com.intellij.openapi.vfs.VirtualFile;
29 | import com.intellij.openapi.wm.ToolWindow;
30 | import com.intellij.psi.JavaPsiFacade;
31 | import com.intellij.psi.PsiClass;
32 | import com.intellij.psi.search.GlobalSearchScope;
33 | import com.intellij.ui.components.JBCheckBox;
34 | import com.intellij.ui.content.Content;
35 | import com.intellij.ui.content.ContentFactory;
36 | import org.jetbrains.android.facet.AndroidFacet;
37 | import org.jetbrains.android.facet.AndroidFacetConfiguration;
38 | import org.jetbrains.android.sdk.AndroidSdkUtils;
39 | import org.jetbrains.annotations.NotNull;
40 | import org.xmlpull.v1.XmlPullParser;
41 | import org.xmlpull.v1.XmlPullParserException;
42 | import org.xmlpull.v1.XmlPullParserFactory;
43 | import org.xmlpull.v1.util.XmlPullUtil;
44 |
45 | import javax.swing.*;
46 | import java.awt.*;
47 | import java.awt.event.ActionListener;
48 | import java.io.*;
49 | import java.text.MessageFormat;
50 | import java.util.*;
51 | import java.util.List;
52 | import java.util.concurrent.ExecutionException;
53 | import java.util.regex.Pattern;
54 |
55 | /**
56 | * Android Device Controller Plugin for Android Studio
57 | */
58 | public class ToolWindowFactory implements com.intellij.openapi.wm.ToolWindowFactory {
59 |
60 | private static ResourceBundle resourceBundle = ResourceBundle.getBundle("de.mobilej.plugin.adc.Plugin");
61 |
62 | private static LocaleData[] LOCALES;
63 |
64 | static {
65 | ArrayList data = new ArrayList<>();
66 | BufferedReader lr = null;
67 | try {
68 | InputStream is = ToolWindowFactory.class.getResourceAsStream("/de/mobilej/plugin/adc/locales.txt");
69 | lr = new BufferedReader(new InputStreamReader(is, "UTF-8"));
70 | String line = null;
71 | while ((line = lr.readLine()) != null) {
72 | if (line.indexOf("_") > 0 && line.indexOf("[") > 0) {
73 | String lang = line.substring(0, line.indexOf("_"));
74 | String cntry = line.substring(line.indexOf("_") + 1, line.indexOf(" "));
75 | String desc = line.substring(line.indexOf("[") + 1, line.length() - 1);
76 | LocaleData ld = new LocaleData(desc, lang, cntry);
77 | data.add(ld);
78 | }
79 | }
80 | } catch (IOException ioe) {
81 | // ignored
82 | }
83 | LOCALES = data.toArray(new LocaleData[data.size()]);
84 | }
85 |
86 | private ComboBox devices;
87 | private AndroidDebugBridge adBridge;
88 | private JButton inputOnDeviceButton;
89 | private JButton clearDataButton;
90 | private JButton killProcessButton;
91 |
92 |
93 | private static class StringShellOutputReceiver implements IShellOutputReceiver {
94 | private StringBuffer result = new StringBuffer();
95 |
96 | void reset() {
97 | result.delete(0, result.length());
98 | }
99 |
100 | String getResult() {
101 | return result.toString();
102 | }
103 |
104 | @Override
105 | public void addOutput(byte[] bytes, int i, int i1) {
106 | try {
107 | result.append(new String(bytes, i, i1, "UTF-8"));
108 | } catch (UnsupportedEncodingException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 |
113 | @Override
114 | public void flush() {
115 | }
116 |
117 | @Override
118 | public boolean isCancelled() {
119 | return false;
120 | }
121 | }
122 |
123 | private StringShellOutputReceiver rcv = new StringShellOutputReceiver();
124 |
125 | private AndroidDebugBridge.IDeviceChangeListener deviceChangeListener = new AndroidDebugBridge.IDeviceChangeListener() {
126 | @Override
127 | public void deviceConnected(IDevice iDevice) {
128 | updateDeviceComboBox();
129 | }
130 |
131 | @Override
132 | public void deviceDisconnected(IDevice iDevice) {
133 | updateDeviceComboBox();
134 | }
135 |
136 | @Override
137 | public void deviceChanged(IDevice iDevice, int i) {
138 | }
139 | };
140 |
141 | private ActionListener deviceSelectedListener = e -> updateFromDevice();
142 |
143 | private JBCheckBox showLayoutBounds;
144 | private ComboBox localeChooser;
145 | private boolean userAction = false;
146 | private JButton goToActivityButton;
147 |
148 | private final Storage storage = ServiceManager.getService(Storage.class);
149 |
150 | public ToolWindowFactory() {
151 | }
152 |
153 | // Create the tool window content.
154 | public void createToolWindowContent(@NotNull final Project project, @NotNull final ToolWindow toolWindow) {
155 | ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
156 | JPanel framePanel = createPanel(project);
157 | disableAll();
158 |
159 | AndroidDebugBridge adb = AndroidSdkUtils.getDebugBridge(project);
160 | if (adb == null) {
161 | return;
162 | }
163 |
164 | if(adb.isConnected()){
165 | ToolWindowFactory.this.adBridge = adb;
166 | Logger.getInstance(ToolWindowFactory.class).info("Successfully obtained debug bridge");
167 | AndroidDebugBridge.addDeviceChangeListener(deviceChangeListener);
168 | updateDeviceComboBox();
169 | } else {
170 | Logger.getInstance(ToolWindowFactory.class).info("Unable to obtain debug bridge");
171 | String msg = MessageFormat.format(resourceBundle.getString("error.message.adb"), "");
172 | Messages.showErrorDialog(msg, resourceBundle.getString("error.title.adb"));
173 | }
174 |
175 | Content content = contentFactory.createContent(framePanel, "", false);
176 | toolWindow.getContentManager().addContent(content);
177 | }
178 |
179 | @NotNull
180 | private JPanel createPanel(@NotNull Project project) {
181 | // Create Panel and Content
182 | JPanel panel = new JPanel(new GridBagLayout());
183 | GridBagConstraints c = new GridBagConstraints();
184 | c.fill = GridBagConstraints.NONE;
185 | c.anchor = GridBagConstraints.LINE_START;
186 | c.insets = new Insets(6,0,0,0);
187 |
188 | devices = new ComboBox(new String[]{resourceBundle.getString("device.none")});
189 |
190 | c.gridx = 0;
191 | c.gridy = 0;
192 | panel.add(new JLabel("Device"), c);
193 | c.gridx = 1;
194 | c.gridy = 0;
195 | panel.add(devices, c);
196 |
197 |
198 | showLayoutBounds = new JBCheckBox(resourceBundle.getString("show.layout.bounds"));
199 | c.gridx = 0;
200 | c.gridy = 1;
201 | c.gridwidth = 2;
202 | panel.add(showLayoutBounds, c);
203 |
204 | showLayoutBounds.addActionListener(e -> {
205 | final String what = showLayoutBounds.isSelected() ? "true" : "\"\"";
206 | final String cmd = "setprop debug.layout " + what;
207 |
208 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
209 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
210 | userAction = true;
211 | executeShellCommand(cmd, true);
212 | userAction = false;
213 | }, resourceBundle.getString("setting.values.title"), false, null);
214 | });
215 |
216 |
217 | localeChooser = new ComboBox(LOCALES);
218 | c.gridx = 0;
219 | c.gridy = 2;
220 | c.gridwidth = 2;
221 | panel.add(localeChooser, c);
222 |
223 | localeChooser.addActionListener(e -> {
224 | final LocaleData ld = (LocaleData) localeChooser.getSelectedItem();
225 | if (ld == null) {
226 | return;
227 | }
228 |
229 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
230 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
231 | userAction = true;
232 | executeShellCommand("am start -a SETMYLOCALE --es language " + ld.language + " --es country " + ld.county, false);
233 | userAction = false;
234 | }, resourceBundle.getString("setting.values.title"), false, null);
235 | });
236 |
237 |
238 | goToActivityButton = new JButton(resourceBundle.getString("button.goto_activity"));
239 | c.gridx = 0;
240 | c.gridy = 3;
241 | c.gridwidth = 2;
242 | c.fill = GridBagConstraints.HORIZONTAL;
243 | panel.add(goToActivityButton, c);
244 |
245 | goToActivityButton.addActionListener(e -> ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
246 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
247 | userAction = true;
248 | final String result = executeShellCommand("dumpsys activity top", false);
249 | userAction = false;
250 |
251 | if (result == null) {
252 | return;
253 | }
254 |
255 | ApplicationManager.getApplication().invokeLater(() -> {
256 |
257 | String activity = result.substring(result.lastIndexOf("ACTIVITY ") + 9);
258 | activity = activity.substring(0, activity.indexOf(" "));
259 | String pkg = activity.substring(0, activity.indexOf("/"));
260 | String clz = activity.substring(activity.indexOf("/") + 1);
261 | if (clz.startsWith(".")) {
262 | clz = pkg + clz;
263 | }
264 |
265 | GlobalSearchScope scope = GlobalSearchScope.allScope(project);
266 | PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(clz, scope);
267 |
268 | if (psiClass != null) {
269 | FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
270 | //Open the file containing the class
271 | VirtualFile vf = psiClass.getContainingFile().getVirtualFile();
272 | //Jump there
273 | new OpenFileDescriptor(project, vf, 1, 0).navigateInEditor(project, false);
274 | } else {
275 | Messages.showMessageDialog(project, clz, resourceBundle.getString("error.class_not_found"), Messages.getWarningIcon());
276 | return;
277 | }
278 |
279 | });
280 |
281 | }, resourceBundle.getString("setting.values.title"), false, null));
282 |
283 |
284 | inputOnDeviceButton = new JButton(resourceBundle.getString("button.input_on_device"));
285 | c.gridx = 0;
286 | c.gridy = 4;
287 | c.gridwidth = 2;
288 | c.fill = GridBagConstraints.HORIZONTAL;
289 | panel.add(inputOnDeviceButton, c);
290 |
291 | inputOnDeviceButton.addActionListener(e -> {
292 | final String text2send = Messages.showMultilineInputDialog(project, resourceBundle.getString("send_text.message"), resourceBundle.getString("send_text.title"), storage.getLastSentText(), Messages.getQuestionIcon(), null);
293 |
294 | if (text2send != null) {
295 | storage.setLastSentText(text2send);
296 |
297 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
298 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
299 | userAction = true;
300 | doInputOnDevice(text2send);
301 | userAction = false;
302 | }, resourceBundle.getString("processing.title"), false, null);
303 | }
304 | });
305 |
306 | clearDataButton = new JButton(resourceBundle.getString("button.clear_data"));
307 | c.gridx = 0;
308 | c.gridy = 5;
309 | c.gridwidth = 2;
310 | c.fill = GridBagConstraints.HORIZONTAL;
311 | panel.add(clearDataButton, c);
312 | clearDataButton.addActionListener(actionEvent -> {
313 | ArrayList appIds = new ArrayList();
314 | List androidFacets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
315 | if (androidFacets != null) {
316 | for (AndroidFacet facet : androidFacets) {
317 | AndroidFacetConfiguration facetConfig = facet.getConfiguration();
318 | if (!facetConfig.isLibraryProject()) {
319 | String appId = facetConfig.getModel().getApplicationId();
320 | appIds.add(appId);
321 | }
322 | }
323 | }
324 |
325 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
326 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
327 | userAction = true;
328 | for (String appId : appIds) {
329 | executeShellCommand("pm clear " + appId, false);
330 | }
331 | userAction = false;
332 | }, resourceBundle.getString("processing.title"), false, null);
333 | });
334 |
335 | killProcessButton = new JButton(resourceBundle.getString("button.kill_process"));
336 | c.gridx = 0;
337 | c.gridy = 6;
338 | c.gridwidth = 2;
339 | c.fill = GridBagConstraints.HORIZONTAL;
340 | panel.add(killProcessButton, c);
341 | killProcessButton.addActionListener(actionEvent -> {
342 | ArrayList appIds = new ArrayList();
343 | List androidFacets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID);
344 | if (androidFacets != null) {
345 | for (AndroidFacet facet : androidFacets) {
346 | AndroidFacetConfiguration facetConfig = facet.getConfiguration();
347 | if (!facetConfig.isLibraryProject()) {
348 | AndroidModel androidModel = facetConfig.getModel();
349 | if (androidModel != null) {
350 | String appId = androidModel.getApplicationId();
351 | appIds.add(appId);
352 | }
353 | }
354 | }
355 | }
356 |
357 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
358 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
359 | userAction = true;
360 | for (String appId : appIds) {
361 | String res = executeShellCommand("run-as "+appId+" ps -A", false);
362 | if(res!=null) {
363 | LineNumberReader lnr = new LineNumberReader(new StringReader(res));
364 | try {
365 | String pid = null;
366 | String line = lnr.readLine();
367 | while(line!=null){
368 | line = lnr.readLine();
369 | if(line!=null){
370 | if(line.contains(appId)){
371 | StringTokenizer toker = new StringTokenizer(line, " \t");
372 | if(toker.hasMoreTokens()){
373 | toker.nextToken();
374 | if(toker.hasMoreTokens()) {
375 | pid = toker.nextToken();
376 | break;
377 | }
378 | }
379 | }
380 | }
381 | }
382 |
383 | if(pid!=null){
384 | res = executeShellCommand("run-as "+appId+" kill "+pid, false);
385 | }
386 | } catch (IOException e) {
387 | e.printStackTrace();
388 | }
389 | }
390 | }
391 | userAction = false;
392 | }, resourceBundle.getString("processing.title"), false, null);
393 | });
394 |
395 | JPanel framePanel = new JPanel(new BorderLayout());
396 | framePanel.add(panel, BorderLayout.NORTH);
397 | return framePanel;
398 | }
399 |
400 | private void doInputOnDevice(String text2send) {
401 | /*
402 | Syntax:
403 | `tap 130 150` -> sends "input tap 130 150" .... really just "input " and append the command
404 | `tap @my.package:id/text` -> first find the center of the given res-id (uiautomator dump /dev/tty)
405 | `tap @*:id/text` -> support wildcards
406 | `swipe 10 20 30 40` -> simple swipe (px)
407 | `swipe @*:id/my_id[10,20] @*:id/my_id[50,60]` -> swipe from 10% of x of given view, 20% of y of given view to 50% of x of the view to 60% of y of the view
408 | `tap @*:id/button[20,30]` syntax also works in general for @id things
409 | ``` -> escapes `
410 | `
411 | ` -> new line which is not sent
412 | `#500` -> wait 500 milliseconds
413 | */
414 |
415 | text2send = text2send.replace("```", "\u2764");
416 | text2send = text2send + "`";
417 | StringTokenizer tokenizer = new StringTokenizer(text2send, "`", true);
418 | boolean inCommand = false;
419 | String plainText = null;
420 | String commandText = null;
421 | while (tokenizer.hasMoreElements()) {
422 | String next = tokenizer.nextToken();
423 |
424 | if ("`".equals(next)) {
425 | if (!inCommand) {
426 | inCommand = true;
427 |
428 | if (plainText != null) {
429 |
430 | StringTokenizer tokenizer2 = new StringTokenizer(plainText," \t\r\n", true);
431 | while(tokenizer2.hasMoreElements()) {
432 | String part = tokenizer2.nextToken();
433 | String escaped = part.replace("\"", "\\\"").replace("\u2764", "\\`");
434 | executeShellCommand("input text \"" + escaped + "\"", false);
435 |
436 | try {
437 | Thread.sleep(400); // wait a bit - give the device some time to process
438 | } catch (InterruptedException e) {
439 | //ignored
440 | }
441 | }
442 | plainText = null;
443 | commandText = null;
444 | }
445 | } else {
446 | inCommand = false;
447 | if (commandText != null) {
448 | commandText = commandText.replace("\r", "").replace("\n", "");
449 | if (commandText.length() > 0) {
450 | if (commandText.startsWith("#")) {
451 | long timeToWait = Long.parseLong(commandText.substring(1));
452 | try {
453 | Thread.sleep(timeToWait);
454 | } catch (InterruptedException e) {
455 | // do nothing
456 | }
457 | } else {
458 | if (commandText.contains("@")) {
459 | commandText = processViewIds(commandText);
460 | }
461 |
462 | executeShellCommand("input " + commandText, false);
463 | }
464 | }
465 | commandText = null;
466 | plainText = null;
467 | }
468 | }
469 | } else {
470 | if (inCommand) {
471 | commandText = next;
472 | plainText = null;
473 | } else {
474 | plainText = next;
475 | commandText = null;
476 | }
477 | }
478 | }
479 |
480 | try {
481 | Thread.sleep(800); // wait a bit - give the device some time to process
482 | } catch (InterruptedException e) {
483 | //ignored
484 | }
485 | }
486 |
487 | private String processViewIds(String commandText) {
488 | /*
489 | @ defaults to center of view
490 | @[percentX,percentY] percentX/Y in view bounds
491 | */
492 | String views = executeShellCommand("uiautomator dump /dev/tty", false);
493 | views = views.substring(0, views.lastIndexOf(">") + 1);
494 | HashMap resIdToBoundsMap = new HashMap<>();
495 | try {
496 | XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
497 | xpp.setInput(new StringReader(views));
498 |
499 | int eventType;
500 | while ((eventType = xpp.getEventType()) != XmlPullParser.END_DOCUMENT) {
501 | if (eventType == XmlPullParser.START_TAG) {
502 | if ("node".equals(xpp.getName())) {
503 | String bounds = XmlPullUtil.getAttributeValue(xpp, "bounds");
504 | String resId = XmlPullUtil.getAttributeValue(xpp, "resource-id");
505 |
506 | if (resId != null && resId.length() > 0) {
507 | bounds = bounds.replace("][", ",");
508 | bounds = bounds.replace("[", "");
509 | bounds = bounds.replace("]", "");
510 | String[] coords = bounds.split(",");
511 | int x1 = Integer.parseInt(coords[0]);
512 | int y1 = Integer.parseInt(coords[1]);
513 | int x2 = Integer.parseInt(coords[2]);
514 | int y2 = Integer.parseInt(coords[3]);
515 |
516 | Rectangle rect = new Rectangle(x1, y1, x2 - x1, y2 - y1);
517 | resIdToBoundsMap.put(resId, rect);
518 | }
519 | }
520 | }
521 | xpp.next();
522 |
523 | }
524 |
525 | } catch (XmlPullParserException | IOException e) {
526 | e.printStackTrace();
527 | }
528 |
529 | while (commandText.contains("@")) {
530 | int idx = commandText.indexOf("@");
531 | StringBuilder sb = new StringBuilder();
532 | int i = idx;
533 | while (i < commandText.length() && commandText.charAt(i) > ' ') {
534 | sb.append(commandText.charAt(i));
535 | i++;
536 | }
537 |
538 | String calculatedCoords = "0 0";
539 | String resIdToMatch = sb.substring(1);
540 | double percentX = 0.5;
541 | double percentY = 0.5;
542 |
543 | if (resIdToMatch.contains("[") && resIdToMatch.contains("]")) {
544 | String percentPart = resIdToMatch.substring(resIdToMatch.indexOf("[") + 1, resIdToMatch.indexOf("]"));
545 | resIdToMatch = resIdToMatch.substring(0, resIdToMatch.indexOf("["));
546 | String[] percentParts = percentPart.split(",");
547 | try {
548 | percentX = Double.parseDouble(percentParts[0]) / 100;
549 | percentY = Double.parseDouble(percentParts[1]) / 100;
550 | } catch (NumberFormatException nfe) {
551 | nfe.printStackTrace();
552 | }
553 | }
554 |
555 | Rectangle rect = new Rectangle(0, 0, 0, 0);
556 | if (resIdToBoundsMap.containsKey(resIdToMatch)) {
557 | rect = resIdToBoundsMap.get(resIdToMatch);
558 | } else {
559 | if (!resIdToMatch.contains(":")) {
560 | resIdToMatch = "*:" + resIdToMatch;
561 | }
562 |
563 | for (Map.Entry entry : resIdToBoundsMap.entrySet()) {
564 | if (wildcardMatch(resIdToMatch, entry.getKey())) {
565 | rect = entry.getValue();
566 | break;
567 | }
568 | }
569 | }
570 | calculatedCoords = "" + (int) (rect.x + rect.width * percentX) + " " + (int) (rect.y + rect.height * percentY);
571 |
572 | commandText = commandText.substring(0, idx) + calculatedCoords + commandText.substring(idx + sb.length());
573 | }
574 |
575 | return commandText;
576 | }
577 |
578 | public static boolean wildcardMatch(final String toMatch, final String value) {
579 | StringBuilder patternStringBuilder = new StringBuilder();
580 | for (final char c : toMatch.toCharArray()) {
581 | switch (c) {
582 | case '?':
583 | patternStringBuilder.append(".?");
584 | break;
585 | case '*':
586 | patternStringBuilder.append(".*");
587 | break;
588 | default:
589 | patternStringBuilder.append(Pattern.quote(String.valueOf(c)));
590 | break;
591 | }
592 | }
593 | Pattern pattern = Pattern.compile(patternStringBuilder.toString());
594 | return pattern.matcher(value).matches();
595 | }
596 |
597 | private void updateFromDevice() {
598 | ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
599 | ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true);
600 | IDevice selectedDevice = getSelectedDevice();
601 | if (selectedDevice != null) {
602 |
603 | setupDevice(selectedDevice);
604 |
605 | String debugLayoutProperty = getSysPropFromDevice("debug.layout", selectedDevice);
606 | if ("true".equals(debugLayoutProperty)) {
607 | showLayoutBounds.setSelected(true);
608 | } else {
609 | showLayoutBounds.setSelected(false);
610 | }
611 |
612 | String deviceLocale = getSysPropFromDevice("persist.sys.locale", selectedDevice);
613 | int i = 0;
614 | for (LocaleData ld : LOCALES) {
615 | if (deviceLocale != null && deviceLocale.startsWith(ld.language) && deviceLocale.endsWith(ld.county)) {
616 | final int toSelect = i;
617 | SwingUtilities.invokeLater(() -> localeChooser.setSelectedIndex(toSelect));
618 |
619 | break;
620 | }
621 | i++;
622 | }
623 |
624 | SwingUtilities.invokeLater(() -> enableAll());
625 | } else {
626 | SwingUtilities.invokeLater(() -> disableAll());
627 | }
628 | }, resourceBundle.getString("initializing.device.message"), false, null);
629 | }
630 |
631 | private String getSysPropFromDevice(String propName, IDevice selectedDevice) {
632 | try {
633 | return selectedDevice.getSystemProperty(propName).get();
634 | } catch (InterruptedException | ExecutionException e) {
635 | e.printStackTrace();
636 | }
637 | return null;
638 | }
639 |
640 | private void disableAll() {
641 | showLayoutBounds.setEnabled(false);
642 | localeChooser.setEnabled(false);
643 | goToActivityButton.setEnabled(false);
644 | inputOnDeviceButton.setEnabled(false);
645 | clearDataButton.setEnabled(false);
646 | killProcessButton.setEnabled(false);
647 | }
648 |
649 | private void enableAll() {
650 | showLayoutBounds.setEnabled(true);
651 | localeChooser.setEnabled(true);
652 | goToActivityButton.setEnabled(true);
653 | inputOnDeviceButton.setEnabled(true);
654 | clearDataButton.setEnabled(true);
655 | killProcessButton.setEnabled(true);
656 | }
657 |
658 | private void setupDevice(final IDevice selectedDevice) {
659 | try {
660 | installEnablerApk(selectedDevice);
661 | } catch (IOException e) {
662 | e.printStackTrace();
663 | }
664 | }
665 |
666 | @SuppressWarnings("unchecked")
667 | private void updateDeviceComboBox() {
668 | devices.removeActionListener(deviceSelectedListener);
669 | String selectedDevice = (String) devices.getSelectedItem();
670 |
671 | IDevice[] devs = adBridge.getDevices();
672 | Vector devicesList = new Vector();
673 | devicesList.add("-- none --");
674 | for (IDevice device : devs) {
675 | devicesList.add(device.toString());
676 | }
677 | devices.setModel(new DefaultComboBoxModel<>(devicesList));
678 |
679 | if (devicesList.size() == 1) {
680 | disableAll();
681 | } else {
682 | devices.setSelectedItem(selectedDevice);
683 |
684 | devices.setSelectedItem(devices.getSelectedItem());
685 | if (devices.getSelectedIndex() == 0) {
686 | disableAll();
687 | } else {
688 | enableAll();
689 | }
690 | }
691 |
692 | devices.addActionListener(deviceSelectedListener);
693 | }
694 |
695 | private String executeShellCommand(String cmd, boolean doPoke) {
696 | if (!userAction) {
697 | return null;
698 | }
699 |
700 | if (devices.getSelectedIndex() == 0) {
701 | return null;
702 | }
703 |
704 | String res = null;
705 | String selDevice = (String) devices.getSelectedItem();
706 | for (IDevice device : adBridge.getDevices()) {
707 | if (selDevice.equals(device.toString())) {
708 |
709 | try {
710 | rcv.reset();
711 | device.executeShellCommand(cmd, rcv);
712 | res = rcv.getResult();
713 | if (doPoke) {
714 | device.executeShellCommand("am start -a POKESYSPROPS", rcv);
715 | }
716 | } catch (TimeoutException | AdbCommandRejectedException | ShellCommandUnresponsiveException | IOException e1) {
717 | e1.printStackTrace();
718 | }
719 |
720 | }
721 | }
722 | return res;
723 | }
724 |
725 | private void installEnablerApk(IDevice device) throws IOException {
726 | String serial = "<"+device.getSerialNumber()+">";
727 | String alreadyInstalledOn = storage.getInstalledOnDevices();
728 | if(alreadyInstalledOn==null){
729 | alreadyInstalledOn = "";
730 | }
731 | if(alreadyInstalledOn.contains(serial)){
732 | return;
733 | }
734 | storage.setInstalledOnDevices(alreadyInstalledOn+serial);
735 |
736 | // TODO no need to create the tmp file over and over again
737 | File tmpfile = File.createTempFile("enabler", "apk");
738 | FileOutputStream fos = null;
739 | InputStream is = null;
740 | try {
741 | is = getClass().getResourceAsStream("/de/mobilej/plugin/adc/enabler.apk");
742 | fos = new FileOutputStream(tmpfile);
743 | byte[] buffer = new byte[4096];
744 | int len = 0;
745 | while ((len = is.read(buffer)) > 0) {
746 | fos.write(buffer, 0, len);
747 | }
748 | } finally {
749 | if (fos != null) {
750 | fos.flush();
751 | fos.close();
752 | }
753 | if (is != null) {
754 | is.close();
755 | }
756 | }
757 |
758 | try {
759 | device.installPackage(tmpfile.getAbsolutePath(), true);
760 | } catch (InstallException ie) {
761 | ie.printStackTrace();
762 | }
763 |
764 | try {
765 | device.executeShellCommand("pm grant mobilej.de.systemproppoker android.permission.CHANGE_CONFIGURATION", rcv);
766 | } catch (Exception e) {
767 | e.printStackTrace();
768 | }
769 | }
770 |
771 | private IDevice getSelectedDevice() {
772 | String selDevice = (String) devices.getSelectedItem();
773 | for (IDevice device : adBridge.getDevices()) {
774 | if (selDevice.equals(device.toString())) {
775 | return device;
776 | }
777 | }
778 | return null;
779 | }
780 |
781 | /**
782 | * Holder for Locale Data
783 | */
784 | private static class LocaleData {
785 | final String name;
786 | final String language;
787 | final String county;
788 |
789 | LocaleData(String name, String language, String county) {
790 | this.name = name;
791 | this.language = language;
792 | this.county = county;
793 | }
794 |
795 | @Override
796 | public String toString() {
797 | return name;
798 | }
799 | }
800 |
801 | }
--------------------------------------------------------------------------------