Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ dependencies {
compile 'org.springframework:spring-context:5.0.3.RELEASE'
compile 'org.aspectj:aspectjweaver:1.8.13'
compile 'org.openpnp:opencv:3.2.0-1'

compile 'javax.websocket:javax.websocket-api:1.1'
compile 'org.glassfish.tyrus:tyrus-client:1.1'
compile 'org.glassfish.tyrus:tyrus-container-grizzly:1.1'

testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-all:1.3'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class AndroidDriver<T extends WebElement>
FindsByAndroidUIAutomator<T>, LocksDevice, HasAndroidSettings, HasDeviceDetails,
HasSupportedPerformanceDataType, AuthenticatesByFinger,
CanRecordScreen, SupportsSpecialEmulatorCommands,
SupportsNetworkStateManagement {
SupportsNetworkStateManagement, ListensToLogcatMessages {

private static final String ANDROID_PLATFORM = MobilePlatform.ANDROID;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.android;

import static io.appium.java_client.service.local.AppiumServiceBuilder.DEFAULT_APPIUM_PORT;
import static org.openqa.selenium.remote.DriverCommand.EXECUTE_SCRIPT;

import com.google.common.collect.ImmutableMap;

import io.appium.java_client.ExecutesMethod;
import io.appium.java_client.ws.MessagesHandler;
import io.appium.java_client.ws.StringWebSocketClient;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;

public interface ListensToLogcatMessages extends ExecutesMethod {
StringWebSocketClient logcatClient = new StringWebSocketClient();

/**
* Start logcat messages broadcast via web socket.
* This method assumes that Appium server is running on localhost and
* is assigned to the default port (4723).
*/
default void startLogcatBroadcast() {
startLogcatBroadcast("localhost", DEFAULT_APPIUM_PORT);
}

/**
* Start logcat messages broadcast via web socket.
* This method assumes that Appium server is assigned to the default port (4723).
*
* @param host the name of the host where Appium server is running
*/
default void startLogcatBroadcast(String host) {
startLogcatBroadcast(host, DEFAULT_APPIUM_PORT);
}

/**
* Start logcat messages broadcast via web socket.
*
* @param host the name of the host where Appium server is running
* @param port the port of the host where Appium server is running
*/
default void startLogcatBroadcast(String host, int port) {
execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: startLogsBroadcast",
"args", Collections.emptyList()));
final URI endpointUri;
try {
endpointUri = new URI(String.format("ws://%s:%s/ws/session/%s/appium/device/logcat",
host, port, ((RemoteWebDriver) this).getSessionId()));
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
logcatClient.connect(endpointUri);
}

/**
* Adds a new log broadcasting handler.
* Several handlers might be assigned to a single server.
* Multiple calls to this method will cause the handler
* to be called multiple times.
*
* @param handler an instance of a class, which implement string message handlers
*/
default void addLogcatListener(MessagesHandler<String> handler) {
logcatClient.addMessageHandler(handler);
}

/**
* Removes all existing logcat message handlers.
*/
default void removeAllLogcatListeners() {
logcatClient.removeAllMessageHandlers();
}

/**
* Stops logcat messages broadcast via web socket.
*/
default void stopLogcatBroadcast() {
execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: stopLogsBroadcast",
"args", Collections.emptyList()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public final class AppiumServiceBuilder
File.separator + BUILD_FOLDER
+ File.separator + LIB_FOLDER
+ File.separator + MAIN_JS;
private static final int DEFAULT_APPIUM_PORT = 4723;
public static final int DEFAULT_APPIUM_PORT = 4723;
private static final String BASH = "bash";
private static final String CMD_EXE = "cmd.exe";
private static final String NODE = "node";
Expand Down
65 changes: 65 additions & 0 deletions src/main/java/io/appium/java_client/ws/CanHandleMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.ws;

import java.util.List;

/**
* This interface might be assigned to classes, which
* are defined as web socket clients.
*/
public interface CanHandleMessages<T extends MessagesHandler> {
/**
* @return The list of web socket message handlers.
*/
List<T> getMessageHandlers();

/**
* Register a new message handler.
*
* @param msgHandler an instance of a class, which
* implements MessagesHandler interface
*/
default void addMessageHandler(T msgHandler) {
getMessageHandlers().add(msgHandler);
}

/**
* Removes an existing message handler.
*
* @param msgHandler an instance of a class, which
* implements MessagesHandler interface
* @return true if the given class instance was registered before and has been successfully removed.
*/
default boolean removeMessageHandler(T msgHandler) {
return getMessageHandlers().remove(msgHandler);
}

/**
* @return The count of registered message handlers.
*/
default int messageHandlersCount() {
return getMessageHandlers().size();
}

/**
* Removes all registered message handlers.
*/
default void removeAllMessageHandlers() {
getMessageHandlers().clear();
}
}
50 changes: 50 additions & 0 deletions src/main/java/io/appium/java_client/ws/MessagesHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.ws;

/**
* This is the basic interface for all web socket message handlers.
*/
public interface MessagesHandler<T> {
/**
* This event is fired when the client is
* successfully connected to a web socket.
*/
void onConnected();

/**
* This event is fired when the client is
* disconnected from a web socket.
*/
void onDisconnected();

/**
* This event is fired when there is an error
* in the web socket connection.
*
* @param cause the actual error reason.
*/
void onError(Throwable cause);

/**
* This event is fired when the client receives
* a new message from a web socket.
*
* @param message the actual web socket message content
*/
void onMessage(T message);
}
109 changes: 109 additions & 0 deletions src/main/java/io/appium/java_client/ws/StringWebSocketClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.appium.java_client.ws;

import org.openqa.selenium.WebDriverException;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

@ClientEndpoint
public class StringWebSocketClient extends WebSocketClient
implements CanHandleMessages<MessagesHandler<String>> {
private final List<MessagesHandler<String>> messageHandlers = new CopyOnWriteArrayList<>();
private volatile Session session;

@Override
public void connect(URI endpoint) {
if (session != null) {
if (endpoint.equals(this.getEndpoint())) {
return;
}

removeAllMessageHandlers();
try {
session.close();
} catch (IOException e) {
// ignore
}
session = null;
}
super.connect(endpoint);
}

/**
* This event if fired when the client is successfully
* connected to a web socket.
*
* @param session the actual web socket session instance
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
getMessageHandlers().forEach(MessagesHandler::onConnected);
}

/**
* This event if fired when the client is
* disconnected from a web socket.
*/
@OnClose
public void onClose() {
this.session = null;
getMessageHandlers().forEach(MessagesHandler::onDisconnected);
}

/**
* This event if fired when there is an unexpected
* error in web socket connection.
*
* @param cause the actual error reason
*/
@OnError
public void onError(Throwable cause) {
this.session = null;
getMessageHandlers().forEach(x -> x.onError(cause));
throw new WebDriverException(cause);
}

/**
* This event if fired when there is a
* new message from the web socket.
*
* @param message the actual message content.
*/
@OnMessage
public void onMessage(String message) {
getMessageHandlers().forEach(x -> x.onMessage(message));
}

/**
* @return The list of all registered web socket messages handlers.
*/
@Override
public List<MessagesHandler<String>> getMessageHandlers() {
return messageHandlers;
}
}
Loading