All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.arquillian.droidium.container.configuration.SystemImage Maven / Gradle / Ivy

There is a newer version: 1.0.1.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2014, Red Hat Middleware LLC, and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * 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 org.arquillian.droidium.container.configuration;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Enumeration of all (up to March 2014) possible types of system images.
 *
 * @author Karel Piwko
 * @author Stefan Miklosovic
 *
 */
class SystemImage {

    private static final Logger log = Logger.getLogger(SystemImage.class.getName());

    private static final String RAMDISK_NAME = "ramdisk.img";

    private final String name;

    private final String abi;

    private SystemImage(String name, String abi) {
        this.name = name;
        this.abi = abi;
    }

    /**
     * Returns System Images for given target. Uses {@code abi} to filet
     *
     * @param sdkPath
     * @param target
     * @param abi can be null or empty string
     * @return
     * @throws AndroidContainerConfigurationException If there is no ABI or multiple ABI matched abi string
     */
    public static SystemImage getSystemImageForTarget(File sdkPath, Target target, String abi)
        throws AndroidContainerConfigurationException {
        List images = getSystemImagesForTarget(sdkPath, target);

        // there is an empty ABI provided in configuration, return the only one available
        if (abi == null || "".equals(abi)) {
            if (images.size() == 1) {
                return images.iterator().next();
            }
            return guessAbi(images, target);
        }

        for (SystemImage si : images) {
            // check for full name of abi
            if (abi.contains("/")) {
                if (abi.equals(si.getAbi())) {
                    return si;
                }
            }
            // check for name without default part
            else {
                if (("default/" + abi).equals(si.getAbi())) {
                    return si;
                }
            }
        }

        if (images.size() == 1) {
            // FIXME this is original Droidium behavior. Does it make sense?!
            log.log(Level.WARNING,
                "ABI property from configuration ({0}) does not match only available image {1}. Arquillian configuration will be ignored.",
                new Object[] { abi, images.iterator().next().getAbi() });
            return images.iterator().next();
        }

        // there are more than 1 images
        return guessAbi(images, target);

    }

    /**
     * Returns all installed images for the target
     *
     * @param sdkPath Path to SDK directory
     * @param target target we want to create
     * @return
     * @throws AndroidContainerConfigurationException if no images were found
     */
    private static List getSystemImagesForTarget(File sdkPath, Target target)
        throws AndroidContainerConfigurationException {

        File dir = null;
        if (target.isGoogleAddon()) {
            dir = new File(new File(sdkPath, AndroidSDK.ADD_ONS_FOLDER_NAME), target.getImagesSubdirectory());
            // google might have release new version of image
            if (!dir.exists()) {
                List addons = FileUtils.listDirectories(new File(sdkPath, AndroidSDK.ADD_ONS_FOLDER_NAME));
                String addonName = target.getImagesSubdirectory();
                if (addonName.endsWith("/images")) {
                    addonName = addonName.substring(0, addonName.length() - "/images".length());
                }
                // find a directory that starts with with same addon name
                for (File addon : addons) {
                    if (addon.getName().startsWith(addonName) && new File(addon, "images").exists()) {
                        dir = addon;
                        break;
                    }
                }
            }
        }
        else {
            dir = new File(new File(sdkPath, AndroidSDK.SYSTEM_IMAGES_FOLDER_NAME), target.getImagesSubdirectory());
        }

        if (!dir.exists()) {
            throw new AndroidContainerConfigurationException("Unable to find out images for target: " + target
                + ", directory: " + dir + " does not exist.");
        }

        // special handling for Android 2.3 Google API image, where the dir is directly the image
        if (target.isGoogleAddon() && target.getApiLevel() == 10 && new File(dir, RAMDISK_NAME).exists()) {
            return Collections.singletonList(new SystemImage(target.getName(), "armeabi"));
        }

        List availableImages = new ArrayList();
        List directories = FileUtils.listDirectories(dir);
        for (File imageCandidate : directories) {
            // we have found an image but there might be a parent - default, android-wear, whatever
            // so we go one extra level up to figure out complete ABI name
            if (new File(imageCandidate, RAMDISK_NAME).exists()) {
                File parentDir = imageCandidate.getParentFile();
                // direct ancestors, we hit default image
                // alternatively, we hit a directory under images, which we consider default as well
                if (dir.equals(parentDir) || (parentDir != null && "images".equals(parentDir.getName()))) {
                    availableImages.add(new SystemImage(target.getName(), "default/" + imageCandidate.getName()));
                }
                else if (parentDir != null) {
                    availableImages.add(new SystemImage(target.getName(), parentDir.getName() + "/" + imageCandidate.getName()));
                }
                else {
                    throw new AndroidContainerConfigurationException("Unable to figure out what images are available for target: "
                        + target);
                }
            }
        }

        if (availableImages.isEmpty()) {
            throw new AndroidContainerConfigurationException("No system images were available for target: " + target);
        }

        // sort descending to ABI names to be filesystem independent
        Collections.sort(availableImages, new Comparator() {
            @Override
            public int compare(SystemImage o1, SystemImage o2) {
                return o2.getAbi().compareTo(o1.getAbi());
            }
        });

        return availableImages;
    }

    private static SystemImage guessAbi(List images, Target target) {

        // there are more images, we have to figure out which one to use
        StringBuilder sb = new StringBuilder("There were more ABIs for target \"")
            .append(target)
            .append("\" available: ");
        String delimiter = "";
        for (SystemImage si : images) {
            sb.append(delimiter).append(si.getAbi());
            delimiter = ", ";
        }
        sb.append(". Please use \"abi\" configuration property to select ABI. At this moment, Droidium will autoselect ")
            .append(images.iterator().next().getAbi())
            .append(".");

        log.log(Level.WARNING, sb.toString());

        return images.iterator().next();
    }

    public String getName() {
        return name;
    }

    public String getAbi() {
        return abi;
    }

    @Override
    public String toString() {
        return "image: " + name + ", abi: " + abi;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((abi == null) ? 0 : abi.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SystemImage other = (SystemImage) obj;
        if (abi == null) {
            if (other.abi != null)
                return false;
        } else if (!abi.equals(other.abi))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    private static final class FileUtils {
        static List listDirectories(File rootDirectory) {
            List dirs = new ArrayList();
            // for (File candidate : rootDirectory.listFiles()) {
            // listDirectories(candidate, dirs);
            // }
            listDirectories(rootDirectory, dirs);
            return dirs;
        }

        static void listDirectories(File rootDirectory, List acc) {
            if (rootDirectory == null || !rootDirectory.isDirectory()) {
                return;
            }

            acc.add(rootDirectory);
            for (File candidate : rootDirectory.listFiles()) {
                listDirectories(candidate, acc);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy