/* * 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.devices.services.console; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.sequoyah.device.framework.model.IInstance; import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler; import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import com.motorola.studio.android.adt.ISerialNumbered; import com.motorola.studio.android.common.utilities.EclipseUtils; import com.motorola.studio.android.devices.services.DeviceServicesPlugin; import com.motorola.studio.android.devices.services.DeviceServicesPlugin.IConsoleKilledListener; import com.motorola.studio.android.devices.services.i18n.ServicesNLS; import com.motorola.studio.android.utilities.TelnetFrameworkAndroid; /** * Class responsible to implement the handler for the service * "Emulator Console" */ public class EmulatorConsoleHandler extends ServiceHandler { private static final Map<String, Integer> consolesCache = new HashMap<String, Integer>(); private static final Map<String, TelnetFrameworkAndroid> telnetsCache = new HashMap<String, TelnetFrameworkAndroid>(); private final IConsoleKilledListener listener = new IConsoleKilledListener() { public void consoleKilled(String name) { if (telnetsCache.containsKey(name)) { TelnetFrameworkAndroid telnet = telnetsCache.get(name); if (telnet.isConnected()) { try { telnet.disconnect(); } catch (IOException e) { EclipseUtils .showInformationDialog( ServicesNLS.GEN_Warning, ServicesNLS.WARN_EmulatorConsoleHandler_CouldNotCloseTheConsoleConnection); } } telnetsCache.remove(name); DeviceServicesPlugin.removeConsoleKilledListener(listener); } } }; public static final String CONSOLE_NAME = "Emulator Console"; private static final String LOCALHOST = "localhost"; /** * Constructor */ public EmulatorConsoleHandler() { } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#newInstance() */ @Override public IServiceHandler newInstance() { return new EmulatorConsoleHandler(); } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#runService(org.eclipse.sequoyah.device.framework.model.IInstance, java.util.Map, org.eclipse.core.runtime.IProgressMonitor) */ @Override public IStatus runService(final IInstance instance, Map<Object, Object> arguments, IProgressMonitor monitor) { IStatus status = Status.OK_STATUS; if (instance instanceof ISerialNumbered) { // Retrieve the emulator port from its serial number Pattern pattern = Pattern.compile("emulator-([0-9]+)"); final String[] serialNumber = new String[1]; serialNumber[0] = ((ISerialNumbered) instance).getSerialNumber(); if (serialNumber[0] == null) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { public void run() { ProgressMonitorDialog dialog = new ProgressMonitorDialog(new Shell(PlatformUI.getWorkbench() .getDisplay())); try { dialog.run(false, false, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { int limit = 20; SubMonitor theMonitor = SubMonitor.convert(monitor); theMonitor.beginTask( ServicesNLS.ADBShellHandler_WaitingDeviceToLoad, limit); int times = 0; while ((serialNumber[0] == null) && (times < limit)) { theMonitor.worked(1); Thread.sleep(500); serialNumber[0] = ((ISerialNumbered) instance).getSerialNumber(); times++; } theMonitor.setWorkRemaining(0); } }); } catch (Exception e) { //do nothing } } }); } // Fix a condition that Studio holds the UI thread forever if (serialNumber[0] == null) { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_EmulatorConsoleHandler_CouldNotOpenTheConsoleShell); return status; } Matcher matcher = pattern.matcher(serialNumber[0]); if (matcher.matches()) { String port = matcher.group(1); final TelnetFrameworkAndroid telnet = new TelnetFrameworkAndroid(); try { Integer i = consolesCache.get(serialNumber[0]); i = (i == null ? 1 : ++i); consolesCache.put(serialNumber[0], i); telnet.connect(LOCALHOST, Integer.parseInt(port)); InputStream in = telnet.getInputStream(); OutputStream out = telnet.getOutputStream(); String consoleName = CONSOLE_NAME + " - " + serialNumber[0]; if (i != null) { consoleName += " (" + i + ")"; } telnetsCache.put(consoleName, telnet); DeviceServicesPlugin.addConsoleKilledListener(listener); DeviceServicesPlugin.redirectStreamsToConsole(in, out, consoleName); } catch (IOException e) { status = new Status( IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_EmulatorConsoleHandler_CouldNotOpenTheConsoleShell, e); } } } else { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_EmulatorConsoleHandler_CouldNotRetrieveTheEmulatorPort); } return status; } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#updatingService(org.eclipse.sequoyah.device.framework.model.IInstance, org.eclipse.core.runtime.IProgressMonitor) */ @Override public IStatus updatingService(IInstance instance, IProgressMonitor monitor) { return Status.OK_STATUS; } }