mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[androiddebugbridge] add start intent channel (#12438)
* [androiddebugbridge] add start intent channel Signed-off-by: Miguel Álvarez Díez <miguelwork92@gmail.com>
This commit is contained in:
parent
f94e2af673
commit
f4b888a8fd
@ -90,6 +90,7 @@ Please note that events could fail if the input method is removed, for example i
|
|||||||
| url | String | Open url in browser |
|
| url | String | Open url in browser |
|
||||||
| media-volume | Dimmer | Set or get media volume level on android device |
|
| media-volume | Dimmer | Set or get media volume level on android device |
|
||||||
| media-control | Player | Control media on android device |
|
| media-control | Player | Control media on android device |
|
||||||
|
| start-intent | String | Start application intent. Read bellow section |
|
||||||
| start-package | String | Run application by package name. The commands for this Channel are populated dynamically based on the `mediaStateJSONConfig`. |
|
| start-package | String | Run application by package name. The commands for this Channel are populated dynamically based on the `mediaStateJSONConfig`. |
|
||||||
| stop-package | String | Stop application by package name |
|
| stop-package | String | Stop application by package name |
|
||||||
| stop-current-package | String | Stop current application |
|
| stop-current-package | String | Stop current application |
|
||||||
@ -101,6 +102,16 @@ Please note that events could fail if the input method is removed, for example i
|
|||||||
| wake-lock | Number | Power wake lock value |
|
| wake-lock | Number | Power wake lock value |
|
||||||
| screen-state | Switch | Screen power state |
|
| screen-state | Switch | Screen power state |
|
||||||
|
|
||||||
|
#### Start Intent
|
||||||
|
|
||||||
|
This channel allows to invoke the 'am start' command, the syntax for it is:
|
||||||
|
<package/activity>||<<arg name>> <arg value>||...
|
||||||
|
|
||||||
|
This is a sample:
|
||||||
|
com.netflix.ninja/.MainActivity||<a>android.intent.action.VIEW||<d>netflix://title/80025384||<f>0x10000020||<es>amzn_deeplink_data 80025384
|
||||||
|
|
||||||
|
Not all the (arguments)[https://developer.android.com/studio/command-line/adb#IntentSpec] are supported. Please open an issue or pull request if you need more.
|
||||||
|
|
||||||
#### Available key-event values:
|
#### Available key-event values:
|
||||||
|
|
||||||
* KEYCODE_0
|
* KEYCODE_0
|
||||||
|
@ -33,6 +33,7 @@ public class AndroidDebugBridgeBindingConstants {
|
|||||||
public static final ThingTypeUID THING_TYPE_ANDROID_DEVICE = new ThingTypeUID(BINDING_ID, "android");
|
public static final ThingTypeUID THING_TYPE_ANDROID_DEVICE = new ThingTypeUID(BINDING_ID, "android");
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_ANDROID_DEVICE);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_ANDROID_DEVICE);
|
||||||
// List of all Channel ids
|
// List of all Channel ids
|
||||||
|
public static final String START_INTENT_CHANNEL = "start-intent";
|
||||||
public static final String KEY_EVENT_CHANNEL = "key-event";
|
public static final String KEY_EVENT_CHANNEL = "key-event";
|
||||||
public static final String TEXT_CHANNEL = "text";
|
public static final String TEXT_CHANNEL = "text";
|
||||||
public static final String TAP_CHANNEL = "tap";
|
public static final String TAP_CHANNEL = "tap";
|
||||||
|
@ -17,6 +17,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -25,6 +26,8 @@ import java.security.spec.InvalidKeySpecException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@ -65,6 +68,8 @@ public class AndroidDebugBridgeDevice {
|
|||||||
private static final Pattern INPUT_EVENT_PATTERN = Pattern
|
private static final Pattern INPUT_EVENT_PATTERN = Pattern
|
||||||
.compile("/(?<input>\\S+): (?<n1>\\S+) (?<n2>\\S+) (?<n3>\\S+)$", Pattern.MULTILINE);
|
.compile("/(?<input>\\S+): (?<n1>\\S+) (?<n2>\\S+) (?<n3>\\S+)$", Pattern.MULTILINE);
|
||||||
|
|
||||||
|
private static final Pattern SECURE_SHELL_INPUT_PATTERN = Pattern.compile("^[^\\|\\&;\\\"]+$");
|
||||||
|
|
||||||
private static @Nullable AdbCrypto adbCrypto;
|
private static @Nullable AdbCrypto adbCrypto;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -170,7 +175,7 @@ public class AndroidDebugBridgeDevice {
|
|||||||
logger.warn("{} is not a valid package name", packageName);
|
logger.warn("{} is not a valid package name", packageName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!PACKAGE_NAME_PATTERN.matcher(activityName).matches()) {
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(activityName).matches()) {
|
||||||
logger.warn("{} is not a valid activity name", activityName);
|
logger.warn("{} is not a valid activity name", activityName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -299,7 +304,7 @@ public class AndroidDebugBridgeDevice {
|
|||||||
|
|
||||||
public String getMacAddress() throws AndroidDebugBridgeDeviceException, InterruptedException,
|
public String getMacAddress() throws AndroidDebugBridgeDeviceException, InterruptedException,
|
||||||
AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException {
|
AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException {
|
||||||
return getDeviceProp("ro.boot.wifimacaddr").toLowerCase();
|
return runAdbShell("cat", "/sys/class/net/wlan0/address").replace("\n", "").replace("\r", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDeviceProp(String name) throws AndroidDebugBridgeDeviceException, InterruptedException,
|
private String getDeviceProp(String name) throws AndroidDebugBridgeDeviceException, InterruptedException,
|
||||||
@ -374,6 +379,265 @@ public class AndroidDebugBridgeDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startIntent(String command)
|
||||||
|
throws AndroidDebugBridgeDeviceException, ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
String[] commandParts = command.split("\\|\\|");
|
||||||
|
if (commandParts.length == 0) {
|
||||||
|
throw new AndroidDebugBridgeDeviceException("Empty command");
|
||||||
|
}
|
||||||
|
String targetPackage = commandParts[0];
|
||||||
|
var targetPackageParts = targetPackage.split("/");
|
||||||
|
if (targetPackageParts.length > 2) {
|
||||||
|
throw new AndroidDebugBridgeDeviceException("Invalid target package " + targetPackage);
|
||||||
|
}
|
||||||
|
if (!PACKAGE_NAME_PATTERN.matcher(targetPackageParts[0]).matches()) {
|
||||||
|
logger.warn("{} is not a valid package name", targetPackageParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (targetPackageParts.length == 2 && !SECURE_SHELL_INPUT_PATTERN.matcher(targetPackageParts[1]).matches()) {
|
||||||
|
logger.warn("{} is not a valid activity name", targetPackageParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@Nullable
|
||||||
|
String action = null;
|
||||||
|
@Nullable
|
||||||
|
String dataUri = null;
|
||||||
|
@Nullable
|
||||||
|
String mimeType = null;
|
||||||
|
@Nullable
|
||||||
|
String category = null;
|
||||||
|
@Nullable
|
||||||
|
String component = null;
|
||||||
|
@Nullable
|
||||||
|
String flags = null;
|
||||||
|
Map<String, Boolean> extraBooleans = new HashMap<>();
|
||||||
|
Map<String, String> extraStrings = new HashMap<>();
|
||||||
|
Map<String, Integer> extraIntegers = new HashMap<>();
|
||||||
|
Map<String, Float> extraFloats = new HashMap<>();
|
||||||
|
Map<String, Long> extraLongs = new HashMap<>();
|
||||||
|
Map<String, URI> extraUris = new HashMap<>();
|
||||||
|
for (var i = 1; i < commandParts.length - 1; i++) {
|
||||||
|
var commandPart = commandParts[i];
|
||||||
|
var endToken = commandPart.indexOf(">");
|
||||||
|
var argName = commandPart.substring(0, endToken + 1);
|
||||||
|
var argValue = commandPart.substring(endToken + 1);
|
||||||
|
|
||||||
|
String[] valueParts;
|
||||||
|
switch (argName) {
|
||||||
|
case "<a>":
|
||||||
|
case "<action>":
|
||||||
|
if (!PACKAGE_NAME_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{} is not a valid action name", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action = argValue;
|
||||||
|
break;
|
||||||
|
case "<d>":
|
||||||
|
case "":
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dataUri = argValue;
|
||||||
|
break;
|
||||||
|
case "<t>":
|
||||||
|
case "<mime_type>":
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mimeType = argValue;
|
||||||
|
break;
|
||||||
|
case "<c>":
|
||||||
|
case "<category>":
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
category = argValue;
|
||||||
|
break;
|
||||||
|
case "<n>":
|
||||||
|
case "<component>":
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
component = argValue;
|
||||||
|
break;
|
||||||
|
case "<f>":
|
||||||
|
case "<flags>":
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(argValue).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flags = argValue;
|
||||||
|
break;
|
||||||
|
case "<e>":
|
||||||
|
case "<es>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extraStrings.put(valueParts[0], valueParts[1]);
|
||||||
|
break;
|
||||||
|
case "<ez>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extraBooleans.put(valueParts[0], Boolean.parseBoolean(valueParts[1]));
|
||||||
|
break;
|
||||||
|
case "<ei>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
extraIntegers.put(valueParts[0], Integer.parseInt(valueParts[1]));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("Unable to parse {} as integer", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "<el>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
extraLongs.put(valueParts[0], Long.parseLong(valueParts[1]));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("Unable to parse {} as long", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "<ef>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
extraFloats.put(valueParts[0], Float.parseFloat(valueParts[1]));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("Unable to parse {} as float", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "<eu>":
|
||||||
|
valueParts = argValue.split(" ");
|
||||||
|
if (valueParts.length != 2) {
|
||||||
|
logger.warn("argument '{}' requires a key value pair separated by space, current value '{}'",
|
||||||
|
argName, argValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[0]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SECURE_SHELL_INPUT_PATTERN.matcher(valueParts[1]).matches()) {
|
||||||
|
logger.warn("{}, insecure input value", valueParts[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extraUris.put(valueParts[0], URI.create(valueParts[1]));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AndroidDebugBridgeDeviceException("Unsupported arg " + argName
|
||||||
|
+ ". Open an issue or pr for it if you think support should be added.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder adbCommandBuilder = new StringBuilder("am start " + targetPackage);
|
||||||
|
if (action != null) {
|
||||||
|
adbCommandBuilder.append(" -a ").append(action);
|
||||||
|
}
|
||||||
|
if (dataUri != null) {
|
||||||
|
adbCommandBuilder.append(" -d ").append(dataUri);
|
||||||
|
}
|
||||||
|
if (mimeType != null) {
|
||||||
|
adbCommandBuilder.append(" -t ").append(mimeType);
|
||||||
|
}
|
||||||
|
if (category != null) {
|
||||||
|
adbCommandBuilder.append(" -c ").append(category);
|
||||||
|
}
|
||||||
|
if (component != null) {
|
||||||
|
adbCommandBuilder.append(" -n ").append(component);
|
||||||
|
}
|
||||||
|
if (flags != null) {
|
||||||
|
adbCommandBuilder.append(" -f ").append(flags);
|
||||||
|
}
|
||||||
|
if (!extraStrings.isEmpty()) {
|
||||||
|
adbCommandBuilder.append(extraStrings.entrySet().stream()
|
||||||
|
.map(entry -> " --es \"" + entry.getKey() + "\" \"" + entry.getValue() + "\""));
|
||||||
|
}
|
||||||
|
if (!extraBooleans.isEmpty()) {
|
||||||
|
adbCommandBuilder.append(extraBooleans.entrySet().stream()
|
||||||
|
.map(entry -> " --ez \"" + entry.getKey() + "\" " + entry.getValue()));
|
||||||
|
}
|
||||||
|
if (!extraIntegers.isEmpty()) {
|
||||||
|
adbCommandBuilder.append(extraIntegers.entrySet().stream()
|
||||||
|
.map(entry -> " --ei \"" + entry.getKey() + "\" " + entry.getValue()));
|
||||||
|
}
|
||||||
|
if (!extraFloats.isEmpty()) {
|
||||||
|
adbCommandBuilder.append(extraFloats.entrySet().stream()
|
||||||
|
.map(entry -> " --ef \"" + entry.getKey() + "\" " + entry.getValue()));
|
||||||
|
}
|
||||||
|
if (!extraLongs.isEmpty()) {
|
||||||
|
adbCommandBuilder.append(extraLongs.entrySet().stream()
|
||||||
|
.map(entry -> " --el \"" + entry.getKey() + "\" " + entry.getValue()));
|
||||||
|
}
|
||||||
|
runAdbShell(adbCommandBuilder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
var currentSocket = socket;
|
var currentSocket = socket;
|
||||||
return currentSocket != null && currentSocket.isConnected();
|
return currentSocket != null && currentSocket.isConnected();
|
||||||
|
@ -180,6 +180,12 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case START_INTENT_CHANNEL:
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
adbConnection.startIntent(command.toFullString());
|
||||||
|
break;
|
||||||
case RECORD_INPUT_CHANNEL:
|
case RECORD_INPUT_CHANNEL:
|
||||||
recordDeviceInput(command);
|
recordDeviceInput(command);
|
||||||
break;
|
break;
|
||||||
|
@ -27,6 +27,8 @@ thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.label = Media
|
|||||||
thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.description = JSON config that allows to modify the media state detection strategy for each app. Refer to the binding documentation.
|
thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.description = JSON config that allows to modify the media state detection strategy for each app. Refer to the binding documentation.
|
||||||
thing-type.config.androiddebugbridge.android.port.label = Port
|
thing-type.config.androiddebugbridge.android.port.label = Port
|
||||||
thing-type.config.androiddebugbridge.android.port.description = Device port listening to adb connections.
|
thing-type.config.androiddebugbridge.android.port.description = Device port listening to adb connections.
|
||||||
|
thing-type.config.androiddebugbridge.android.recordDuration.label = Record Duration
|
||||||
|
thing-type.config.androiddebugbridge.android.recordDuration.description = How much time the record-input channel wait for events to record.
|
||||||
thing-type.config.androiddebugbridge.android.refreshTime.label = Refresh Time
|
thing-type.config.androiddebugbridge.android.refreshTime.label = Refresh Time
|
||||||
thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes.
|
thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes.
|
||||||
thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout
|
thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout
|
||||||
@ -329,12 +331,18 @@ channel-type.androiddebugbridge.key-event-channel.state.option.54 = KEYCODE_Z
|
|||||||
channel-type.androiddebugbridge.key-event-channel.state.option.211 = KEYCODE_ZENKAKU_HANKAKU
|
channel-type.androiddebugbridge.key-event-channel.state.option.211 = KEYCODE_ZENKAKU_HANKAKU
|
||||||
channel-type.androiddebugbridge.key-event-channel.state.option.168 = KEYCODE_ZOOM_IN
|
channel-type.androiddebugbridge.key-event-channel.state.option.168 = KEYCODE_ZOOM_IN
|
||||||
channel-type.androiddebugbridge.key-event-channel.state.option.16 = KEYCODE_ZOOM_OUT
|
channel-type.androiddebugbridge.key-event-channel.state.option.16 = KEYCODE_ZOOM_OUT
|
||||||
|
channel-type.androiddebugbridge.record-input-channel.label = Record Input
|
||||||
|
channel-type.androiddebugbridge.record-input-channel.description = Record input events under provided name
|
||||||
|
channel-type.androiddebugbridge.recorded-input-channel.label = Recorded Input
|
||||||
|
channel-type.androiddebugbridge.recorded-input-channel.description = Send previous recorded input events by name
|
||||||
channel-type.androiddebugbridge.screen-state-channel.label = Screen State
|
channel-type.androiddebugbridge.screen-state-channel.label = Screen State
|
||||||
channel-type.androiddebugbridge.screen-state-channel.description = Screen Power State
|
channel-type.androiddebugbridge.screen-state-channel.description = Screen Power State
|
||||||
channel-type.androiddebugbridge.shutdown-channel.label = Shutdown
|
channel-type.androiddebugbridge.shutdown-channel.label = Shutdown
|
||||||
channel-type.androiddebugbridge.shutdown-channel.description = Shutdown/Reboot Device
|
channel-type.androiddebugbridge.shutdown-channel.description = Shutdown/Reboot Device
|
||||||
channel-type.androiddebugbridge.shutdown-channel.state.option.POWER_OFF = POWER_OFF
|
channel-type.androiddebugbridge.shutdown-channel.state.option.POWER_OFF = POWER_OFF
|
||||||
channel-type.androiddebugbridge.shutdown-channel.state.option.REBOOT = REBOOT
|
channel-type.androiddebugbridge.shutdown-channel.state.option.REBOOT = REBOOT
|
||||||
|
channel-type.androiddebugbridge.start-intent-channel.label = Start Intent
|
||||||
|
channel-type.androiddebugbridge.start-intent-channel.description = Start application intent
|
||||||
channel-type.androiddebugbridge.start-package-channel.label = Start Package
|
channel-type.androiddebugbridge.start-package-channel.label = Start Package
|
||||||
channel-type.androiddebugbridge.start-package-channel.description = Run application by package name
|
channel-type.androiddebugbridge.start-package-channel.description = Run application by package name
|
||||||
channel-type.androiddebugbridge.stop-current-package-channel.label = Stop Current Package
|
channel-type.androiddebugbridge.stop-current-package-channel.label = Stop Current Package
|
||||||
@ -345,5 +353,7 @@ channel-type.androiddebugbridge.tap-channel.label = Send Tap
|
|||||||
channel-type.androiddebugbridge.tap-channel.description = Send tap event to android device
|
channel-type.androiddebugbridge.tap-channel.description = Send tap event to android device
|
||||||
channel-type.androiddebugbridge.text-channel.label = Send Text
|
channel-type.androiddebugbridge.text-channel.label = Send Text
|
||||||
channel-type.androiddebugbridge.text-channel.description = Send text to android device
|
channel-type.androiddebugbridge.text-channel.description = Send text to android device
|
||||||
|
channel-type.androiddebugbridge.url-channel.label = Open Url
|
||||||
|
channel-type.androiddebugbridge.url-channel.description = Open url in the browser
|
||||||
channel-type.androiddebugbridge.wake-lock-channel.label = Wake Lock
|
channel-type.androiddebugbridge.wake-lock-channel.label = Wake Lock
|
||||||
channel-type.androiddebugbridge.wake-lock-channel.description = Power Wake Lock State
|
channel-type.androiddebugbridge.wake-lock-channel.description = Power Wake Lock State
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<channel id="screen-state" typeId="screen-state-channel"/>
|
<channel id="screen-state" typeId="screen-state-channel"/>
|
||||||
<channel id="shutdown" typeId="shutdown-channel"/>
|
<channel id="shutdown" typeId="shutdown-channel"/>
|
||||||
<channel id="awake-state" typeId="awake-state-channel"/>
|
<channel id="awake-state" typeId="awake-state-channel"/>
|
||||||
|
<channel id="start-intent" typeId="start-intent-channel"/>
|
||||||
</channels>
|
</channels>
|
||||||
<representation-property>macAddress</representation-property>
|
<representation-property>macAddress</representation-property>
|
||||||
<config-description>
|
<config-description>
|
||||||
@ -447,4 +448,10 @@
|
|||||||
<state readOnly="true"/>
|
<state readOnly="true"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="start-intent-channel" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Start Intent</label>
|
||||||
|
<description>Start application intent</description>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
</thing:thing-descriptions>
|
</thing:thing-descriptions>
|
||||||
|
Loading…
Reference in New Issue
Block a user