package com.github.xsavikx.androidscreencast.api; import com.android.ddmlib.IDevice; import com.android.ddmlib.SyncService; import com.android.ddmlib.SyncService.ISyncProgressMonitor; import com.github.xsavikx.androidscreencast.api.file.FileInfo; import com.github.xsavikx.androidscreencast.api.injector.OutputStreamShellOutputReceiver; import com.github.xsavikx.androidscreencast.exception.AndroidScreenCastRuntimeException; import com.github.xsavikx.androidscreencast.exception.ExecuteCommandException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; import java.io.ByteArrayOutputStream; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @Singleton public class AndroidDeviceImpl implements AndroidDevice { private static final Logger LOGGER = LoggerFactory.getLogger(AndroidDeviceImpl.class); private final IDevice device; @Inject public AndroidDeviceImpl(final IDevice device) { this.device = device; } @Override public String executeCommand(final String cmd) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("executeCommand(String) - start"); } try (final ByteArrayOutputStream bos = new ByteArrayOutputStream();) { device.executeShellCommand(cmd, new OutputStreamShellOutputReceiver(bos)); final String returnString = new String(bos.toByteArray(), "UTF-8"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("executeCommand(String) - end"); } return returnString; } catch (final Exception ex) { LOGGER.error("executeCommand(String)", ex); throw new ExecuteCommandException(cmd); } } @Override public List<FileInfo> list(final String path) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("list(String) - start"); } try { final String s = executeCommand("ls -l " + path); final String[] entries = s.split("\r\n"); final List<FileInfo> fileInfos = new ArrayList<>(); for (final String entry : entries) { String[] data = entry.split(" "); if (data.length < 4) continue; String attributes = data[0]; boolean directory = attributes.charAt(0) == 'd'; String name = data[data.length - 1]; final FileInfo fi = new FileInfo(); fi.attribs = attributes; fi.directory = directory; fi.name = name; fi.path = path; fi.device = this; fileInfos.add(fi); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("list(String) - end"); } return fileInfos; } catch (final Exception ex) { LOGGER.error("list(String)", ex); throw new AndroidScreenCastRuntimeException(ex); } } @Override public void openUrl(final String url) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("openUrl(String) - start"); } executeCommand("am start " + url); if (LOGGER.isDebugEnabled()) { LOGGER.debug("openUrl(String) - end"); } } @Override public void pullFile(final String removeFrom, final File localTo) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("pullFile(String, File) - start"); } // ugly hack to call the method without FileEntry try { if (device.getSyncService() == null) throw new AndroidScreenCastRuntimeException("SyncService is null, ADB crashed ?"); final Method m = device.getSyncService().getClass().getDeclaredMethod("doPullFile", String.class, String.class, ISyncProgressMonitor.class); m.setAccessible(true); device.getSyncService(); m.invoke(device.getSyncService(), removeFrom, localTo.getAbsolutePath(), SyncService.getNullProgressMonitor()); } catch (final Exception ex) { LOGGER.error("pullFile(String, File)", ex); throw new AndroidScreenCastRuntimeException(ex); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("pullFile(String, File) - end"); } } @Override public void pushFile(final File localFrom, final String remoteTo) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("pushFile(File, String) - start"); } try { if (device.getSyncService() == null) throw new AndroidScreenCastRuntimeException("SyncService is null, ADB crashed ?"); device.getSyncService().pushFile(localFrom.getAbsolutePath(), remoteTo, SyncService.getNullProgressMonitor()); } catch (final Exception ex) { LOGGER.error("pushFile(File, String)", ex); throw new AndroidScreenCastRuntimeException(ex); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("pushFile(File, String) - end"); } } }