/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.motorola.studio.android.emulator.logic;
import static com.motorola.studio.android.common.log.StudioLogger.error;
import static com.motorola.studio.android.common.log.StudioLogger.info;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sequoyah.vnc.protocol.PluginProtocolActionDelegate;
import org.eclipse.sequoyah.vnc.protocol.lib.IProtocolExceptionHandler;
import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolHandle;
import com.motorola.studio.android.emulator.core.exception.InstanceStartException;
import com.motorola.studio.android.emulator.core.exception.StartCancelledException;
import com.motorola.studio.android.emulator.core.exception.StartTimeoutException;
import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
import com.motorola.studio.android.emulator.i18n.EmulatorNLS;
/**
* This class contains the logic to stablish VNC connections
*
*/
public class ConnectVncLogic implements IAndroidLogic
{
/**
* The port that is used to start the communication with the instance.
* It corresponds to the VNC display 1 port
*/
private static final String LOCALHOST_IP_ADDRESS = "127.0.0.1";
public IJobChangeEvent vncServerDoneEvent = null;
/**
* Initialize by connecting to VNC
*
* @see com.motorola.studio.android.emulator.logic.IAndroidLogic#execute(IAndroidLogicInstance, int, IProgressMonitor)
*/
public void execute(final IAndroidLogicInstance instance, final int timeout,
IProgressMonitor monitor) throws StartTimeoutException, StartCancelledException,
InstanceStartException
{
connectVnc(instance, timeout, monitor);
}
/**
* Connect to VNC
*
* @param instance instance to connect
* @param timeout timeout for the operation
* @param monitor monitor for this operation
*
* @throws InstanceStartException
*/
private void connectVnc(IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor)
throws StartTimeoutException, StartCancelledException, InstanceStartException
{
info("Trying to estabilish vnc connection with " + instance.getName());
long timeoutLimit = System.currentTimeMillis() + timeout;
try
{
startProtocol(instance, timeoutLimit, AndroidLogicUtils.getVncServerPortFoward(instance
.getInstanceIdentifier()), monitor);
}
catch (StartTimeoutException ise)
{
info("The protocol or the emulator services could not be launched. Stopping the instance.");
throw ise;
}
info("VNC Protocol is running for " + instance.getName());
}
/**
* Starts protocol connection
*
* @param instance The Android device instance
* @param timeoutLimit The timestamp of the time when timeout happens
* @param instanceHost The IP address of the started emulator instance
* @param monitor A progress monitor that will give the user feedback about this
* long running operation
*
* @throws InstanceStartException If some fatal error occurs during the start process,
* that may require status update at the clients
* @throws StartCancelledException If the user presses the "Cancel" button at the progress monitor
* @throws InstanceStartException
*/
private void startProtocol(IAndroidEmulatorInstance instance, long timeoutLimit, int port,
IProgressMonitor monitor) throws StartTimeoutException, StartCancelledException,
InstanceStartException
{
try
{
monitor.beginTask(EmulatorNLS.MON_AndroidEmulatorStarter_ConnectingToEmulator, 100);
monitor.setTaskName(EmulatorNLS.MON_AndroidEmulatorStarter_ConnectingToEmulator);
testVncServer(instance);
AndroidLogicUtils.testCanceled(monitor);
requestStartProtocol(instance, port);
ProtocolHandle handle = instance.getProtocolHandle();
while (!PluginProtocolActionDelegate.isProtocolRunning(handle))
{
AndroidLogicUtils.testCanceled(monitor);
try
{
Thread.sleep(500);
}
catch (InterruptedException e1)
{
// Do nothing.
}
AndroidLogicUtils.testTimeout(timeoutLimit,
EmulatorNLS.EXC_AndroidEmulatorStarter_TimeoutWhileRunningProtocol);
}
monitor.worked(100);
}
finally
{
monitor.done();
}
}
/**
* Set if the job has been completed
*
* @param jobEvent event job
*/
public void setVncServerDoneEvent(IJobChangeEvent jobEvent)
{
this.vncServerDoneEvent = jobEvent;
}
/**
* Test if the VNC server is up and running
*
* @param instance emulator instance
*
* @throws InstanceStartException
*/
private void testVncServer(final IAndroidEmulatorInstance instance)
throws InstanceStartException
{
if (vncServerDoneEvent != null)
{
IStatus jobResult = vncServerDoneEvent.getResult();
String reason = "";
if (IStatus.ERROR == jobResult.getSeverity())
{
reason = jobResult.getMessage();
}
else if (Status.CANCEL_STATUS.equals(jobResult))
{
reason = EmulatorNLS.INFO_ConnectVncLogic_UserCancelledVncServerStart;
}
String message =
NLS.bind(EmulatorNLS.EXC_VncServerNotRunning, new String[]
{
instance.getName(), reason
});
throw new InstanceStartException(message);
}
}
/**
* Starts the protocol execution, connecting to the server accessible through
* the provided Android Emulator instance
*
* @param androidInstance The Android device instance
*/
private void requestStartProtocol(IAndroidEmulatorInstance androidInstance, int port)
throws InstanceStartException
{
if (androidInstance != null)
{
ProtocolHandle handle = null;
try
{
// Start protocol and screen update
info("Requesting protocol start");
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("password", "");
parameters.put("bypassProxy", new Boolean(true));
IProtocolExceptionHandler excHandler = new AndroidExceptionHandler();
handle =
PluginProtocolActionDelegate.requestStartProtocolAsClient("vncProtocol38",
excHandler, LOCALHOST_IP_ADDRESS, port, parameters);
androidInstance.setProtocolHandle(handle);
}
catch (Exception e)
{
error("There is an error at the protocol specification.");
throw new InstanceStartException(EmulatorNLS.EXC_CouldNotStartProtocol);
}
}
else
{
error("Could not start the protocol, because the provided instance is null");
throw new InstanceStartException(EmulatorNLS.EXC_CouldNotStartProtocol);
}
}
}