/* * 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.io.IOException; import java.util.Collection; import java.util.LinkedList; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; import com.motorola.studio.android.adt.DDMSFacade; import com.motorola.studio.android.adt.ISerialNumbered; import com.motorola.studio.android.common.exception.AndroidException; import com.motorola.studio.android.emulator.EmulatorPlugin; 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; /** * This class contains the logic to start the VNC server on the given Emulator. */ public final class StartVncServerLogic implements IAndroidLogic { public static final String VNC_SERVER_JOB_PREFIX = "VNC Server - "; public static final Object VNC_SERVER_JOB_FAMILY = new Object(); /** * Sequence of commands that must be executed on the emulator to start the VNC server */ private final Collection<String> remoteCommands = new LinkedList<String>(); /** * Collection of listeners for the job executing the VNC server. */ private final Collection<IJobChangeListener> listeners = new LinkedList<IJobChangeListener>(); /** * Executes the logic to start the vnc server. */ public void execute(final IAndroidLogicInstance instance, int timeout, final IProgressMonitor monitor) throws InstanceStartException, StartTimeoutException, StartCancelledException, IOException { cancelCurrentVncServerJobs(instance); // Creates and starts a job that will keep running as long as the VNC server is up on that Emulator instance. // add listeners that will receive notifications about the Job life-cycle. VncServerJob vncServerJob = new VncServerJob(instance, getRemoteCommands()); for (IJobChangeListener vncServerListener : listeners) { vncServerJob.addJobChangeListener(vncServerListener); } vncServerJob.schedule(); } /** * Cancel any VncServerJob that is currently running the VNC server on the given emulator instance. * @param instance, the emulator instances where VNC server execution must be canceled. **/ public static void cancelCurrentVncServerJobs(IAndroidEmulatorInstance instance) { // stop the previous VNC Server job for this instance if any... IJobManager manager = Job.getJobManager(); Job[] allVncJobs = manager.find(StartVncServerLogic.VNC_SERVER_JOB_FAMILY); if (allVncJobs.length > 0) { for (Job job : allVncJobs) { if (job.getName().equals( StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName())) { info("Cancel execution of the VNC Server on " + instance); job.cancel(); } } } } /** * Add job listener to receive state-change notifications from the job that runs the VNC Server. * @param vncServerListener job listener that willl receive state change notifications from the VNC Serever job. */ public void addVncServerJobListener(IJobChangeListener vncServerListener) { listeners.add(vncServerListener); } /** * Add a command to be executed in the process of starting the VNC Server on the Emulator. * @param remoteCommand */ public void addRemoteCommand(String remoteCommand) { remoteCommands.add(remoteCommand); } /** * Get the list of commands to be executed on the Emulator in order to start the VNC Server. * @return the sequence of commands that must be executed on the Emulator to start the VNC Server. */ public Collection<String> getRemoteCommands() { return remoteCommands; } } /** * Job that executes the VNC Server. * It will keep running as long as the VNC Server process is running on the Emulator. */ class VncServerJob extends Job implements ISchedulingRule { private String serialNumber; /** * Sequence of commands that must be executed on the emulator to start the VNC server */ private final Collection<String> remoteCommands; /** * Creates a new job to execute the VNC server on the given emulator instance. * @param instance, emulator instance where the VNC server will be started. * @param remoteCommands, sequence of commands that must be executed on the given emulator instance to start the VNC Server. * @throws InstanceStartException */ public VncServerJob(IAndroidLogicInstance instance, Collection<String> remoteCommands) throws InstanceStartException { super(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName()); this.serialNumber = ((ISerialNumbered) instance).getSerialNumber(); try { AndroidLogicUtils.testDeviceStatus(serialNumber); } catch (AndroidException e) { throw new InstanceStartException(e.getMessage()); } this.remoteCommands = remoteCommands; setSystem(true); setRule(this); } /** * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor) */ @Override public IStatus run(IProgressMonitor monitor) { IStatus status = Status.OK_STATUS; try { info("Executing VNC Server on " + serialNumber); AndroidLogicUtils.testDeviceStatus(serialNumber); DDMSFacade.execRemoteApp(serialNumber, remoteCommands, monitor); if (monitor.isCanceled()) { status = Status.CANCEL_STATUS; } } catch (Exception e) { String errorMessage = "Error while trying to run the VNC server on " + serialNumber; error(errorMessage + " " + e.getMessage()); status = new Status(IStatus.CANCEL, EmulatorPlugin.PLUGIN_ID, errorMessage, e); } info("Finished the execution of the VNC Server on " + serialNumber + " with status " + status); return status; } /** * @see org.eclipse.core.runtime.jobs.Job#belongsTo(Object) */ @Override public boolean belongsTo(Object family) { return StartVncServerLogic.VNC_SERVER_JOB_FAMILY.equals(family); } public boolean contains(ISchedulingRule rule) { boolean contains = false; if (rule instanceof VncServerJob) { VncServerJob otherVncServerJob = (VncServerJob) rule; contains = otherVncServerJob.serialNumber.equals(serialNumber); } return contains; } public boolean isConflicting(ISchedulingRule rule) { return contains(rule); } }