src/main/java/com/simpligility/maven/plugins/android/AbstractAndroidMojo.java
protected void doWithDevices( final DeviceCallback deviceCallback )
            throws MojoExecutionException, MojoFailureException
    {
        final AndroidDebugBridge androidDebugBridge = initAndroidDebugBridge();

        if ( !androidDebugBridge.isConnected() )
        {
            throw new MojoExecutionException( "Android Debug Bridge is not connected." );
        }

        waitForInitialDeviceList( androidDebugBridge );
        List<IDevice> devices = Arrays.asList( androidDebugBridge.getDevices() );
        int numberOfDevices = devices.size();
        getLog().debug( "Found " + numberOfDevices + " devices connected with the Android Debug Bridge" );
        if ( devices.size() == 0 )
        {
            throw new MojoExecutionException( "No online devices attached." );
        }

        int threadCount = getDeviceThreads();
        if ( getDeviceThreads() == 0 )
        {
            getLog().info( "android.devicesThreads parameter not set, using a thread for each attached device" );
            threadCount = numberOfDevices;
        }
        else
        {
            getLog().info( "android.devicesThreads parameter set to " + getDeviceThreads() );
        }

        boolean shouldRunOnAllDevices = getDevices().size() == 0;
        if ( shouldRunOnAllDevices )
        {
            getLog().info( "android.devices parameter not set, using all attached devices" );
        }
        else
        {
            getLog().info( "android.devices parameter set to " + getDevices().toString() );
        }

        ArrayList<DoThread> doThreads = new ArrayList<DoThread>();
        ExecutorService executor = Executors.newFixedThreadPool( threadCount );
        for ( final IDevice idevice : devices )
        {
            if ( shouldRunOnAllDevices )
            {
                String deviceType = idevice.isEmulator() ? "Emulator " : "Device ";
                getLog().info( deviceType + DeviceHelper.getDescriptiveName( idevice ) + " found." );
            }
            if ( shouldRunOnAllDevices || shouldDoWithThisDevice( idevice ) )
            {
                DoThread deviceDoThread = new DoThread() {
                    public void runDo() throws MojoFailureException, MojoExecutionException
                    {
                        deviceCallback.doWithDevice( idevice );
                    }
                };
                doThreads.add( deviceDoThread );
                executor.execute( deviceDoThread );
            }
        }
        executor.shutdown();
        while ( ! executor.isTerminated() )
        {
            // waiting for threads finish
        }
        throwAnyDoThreadErrors( doThreads );

        if ( ! shouldRunOnAllDevices && doThreads.isEmpty() )
        {
            throw new MojoExecutionException( "No device found for android.device=" + getDevices().toString() );
        }
    }
protected void doWithDevices( final DeviceCallback deviceCallback )
            throws MojoExecutionException, MojoFailureException
    {
        final AndroidDebugBridge androidDebugBridge = initAndroidDebugBridge();

        if ( !androidDebugBridge.isConnected() )
        {
            throw new MojoExecutionException( "Android Debug Bridge is not connected." );
        }

        waitForInitialDeviceList( androidDebugBridge );
        List<IDevice> devices = Arrays.asList( androidDebugBridge.getDevices() );
        int numberOfDevices = devices.size();
        getLog().debug( "Found " + numberOfDevices + " devices connected with the Android Debug Bridge" );
        if ( devices.size() == 0 )
        {
            throw new MojoExecutionException( "No online devices attached." );
        }

        int threadCount = getDeviceThreads();
        if ( getDeviceThreads() == 0 )
        {
            getLog().info( "android.devicesThreads parameter not set, using a thread for each attached device" );
            threadCount = numberOfDevices;
        }
        else
        {
            getLog().info( "android.devicesThreads parameter set to " + getDeviceThreads() );
        }

        boolean shouldRunOnAllDevices = getDevices().size() == 0;
        if ( shouldRunOnAllDevices )
        {
            getLog().info( "android.devices parameter not set, using all attached devices" );
        }
        else
        {
            getLog().info( "android.devices parameter set to " + getDevices().toString() );
        }

        ArrayList<DoThread> doThreads = new ArrayList<DoThread>();
        ExecutorService executor = Executors.newFixedThreadPool( threadCount );
        for ( final IDevice idevice : devices )
        {
            if ( shouldRunOnAllDevices )
            {
                String deviceType = idevice.isEmulator() ? "Emulator " : "Device ";
                getLog().info( deviceType + DeviceHelper.getDescriptiveName( idevice ) + " found." );
            }
            if ( shouldRunOnAllDevices || shouldDoWithThisDevice( idevice ) )
            {
                DoThread deviceDoThread = new DoThread() {
                    public void runDo() throws MojoFailureException, MojoExecutionException
                    {
                        deviceCallback.doWithDevice( idevice );
                    }
                };
                doThreads.add( deviceDoThread );
                executor.execute( deviceDoThread );
            }
        }
        executor.shutdown();
        while ( ! executor.isTerminated() )
        {
            // waiting for threads finish
        }
        throwAnyDoThreadErrors( doThreads );

        if ( ! shouldRunOnAllDevices && doThreads.isEmpty() )
        {
            throw new MojoExecutionException( "No device found for android.device=" + getDevices().toString() );
        }
    }
Performs the callback action on the devices determined by
{@link #shouldDoWithThisDevice(com.android.ddmlib.IDevice)}

@param deviceCallback the action to perform on each device
@throws org.apache.maven.plugin.MojoExecutionException
in case there is a problem
@throws org.apache.maven.plugin.MojoFailureException
in case there is a problem