private void copyGdbServer( File destinationDirectory, String architecture ) throws MojoExecutionException
    {

        try
        {
            final File destDir = new File( destinationDirectory, architecture );
            if ( destDir.exists() )
            {
                // Copy the gdbserver binary to libs/<architecture>/
                final File gdbServerFile = getAndroidNdk().getGdbServer( architecture );
                final File destFile = new File( destDir, "gdbserver" );
                if ( ! destFile.exists() )
                {
                    getLog().debug( "Copying gdbServer to " + destFile );
                    FileUtils.copyFile( gdbServerFile, destFile );
                }
                else
                {
                    getLog().info( "Note: gdbserver binary already exists at destination, will not copy over" );
                }
            }
        }
        catch ( Exception e )
        {
            getLog().error( "Error while copying gdbserver: " + e.getMessage(), e );
            throw new MojoExecutionException( "Error while copying gdbserver: " + e.getMessage(), e );
        }

    }

Copy the Ndk GdbServer into the architecture output folder if the folder exists but the GdbServer doesn't.

Copy the Ndk GdbServer into the architecture output folder if the folder exists but the GdbServer doesn t .


private static File getJavaExecutable()
    {
        final String javaHome = System.getProperty( "java.home" );
        final String slash = File.separator;
        return new File( javaHome + slash + "bin" + slash + "java" );
    }

private static File getJavaExecutable ( ) { final String javaHome = System . getProperty ( "java.home" ) ; final String slash = File . separator ; return new File ( javaHome + slash + "bin" + slash + "java" ) ; }

Figure out the full path to the current java executable.

@return the full path to the current java executable.

Figure out the full path to the current java executable .


public String getProguardJarPath()
    {
        File directory = new File( getToolsPath(), "proguard" + File.separator + "lib" + File.separator );
        File proguardJar = new File( directory, "proguard.jar" );
        if ( proguardJar.exists() )
        {
            return proguardJar.getAbsolutePath();
        }
        throw new InvalidSdkException( "Cannot find " + proguardJar );
    }

public
String
getProguardJarPath
(
)
{
File
directory
=
new
File
(
getToolsPath
(
)
,
"proguard"
+
File
.
separator
+
"lib"
+
File
.
separator
)
;
File
proguardJar
=
new
File
(
directory
,
"proguard.jar"
)
;
if
(
proguardJar
.
exists
(
)
)
{
return
proguardJar
.
getAbsolutePath
(
)
;
}
throw
new
InvalidSdkException
(
"Cannot find "
+
proguardJar
)
;
}


public String getShrinkedAndroidJarPath()
    {
        File shrinkedAndroidJar = new File( getBuildToolsLibDirectoryPath(), "shrinkedAndroid.jar" );
        if ( shrinkedAndroidJar.exists() )
        {
            return shrinkedAndroidJar.getAbsolutePath();
        }
        throw new InvalidSdkException( "Cannot find " + shrinkedAndroidJar );
    }

public
String
getShrinkedAndroidJarPath
(
)
{
File
shrinkedAndroidJar
=
new
File
(
getBuildToolsLibDirectoryPath
(
)
,
"shrinkedAndroid.jar"
)
;
if
(
shrinkedAndroidJar
.
exists
(
)
)
{
return
shrinkedAndroidJar
.
getAbsolutePath
(
)
;
}
throw
new
InvalidSdkException
(
"Cannot find "
+
shrinkedAndroidJar
)
;
}

Get the path for shrinkedAndroid.jar
@return


public String getBuildToolsLibDirectoryPath()
    {
        File buildToolsLib = new File( getBuildToolInfo().getLocation(), "lib" );
        if ( buildToolsLib.exists() )
        {
            return buildToolsLib.getAbsolutePath();
        }
        throw new InvalidSdkException( "Cannot find " + buildToolsLib );
    }

public
String
getBuildToolsLibDirectoryPath
(
)
{
File
buildToolsLib
=
new
File
(
getBuildToolInfo
(
)
.
getLocation
(
)
,
"lib"
)
;
if
(
buildToolsLib
.
exists
(
)
)
{
return
buildToolsLib
.
getAbsolutePath
(
)
;
}
throw
new
InvalidSdkException
(
"Cannot find "
+
buildToolsLib
)
;
}

Get the path for build-tools lib directory
@return

Get the path for build - tools lib directory


public String getMainDexClassesRulesPath()
    {
        File mainDexClassesRules = new File( getBuildToolInfo().getLocation(),
                "mainDexClasses.rules" );
        if ( mainDexClassesRules.exists() )
        {
            return mainDexClassesRules.getAbsolutePath();
        }
        throw new InvalidSdkException( "Cannot find " + mainDexClassesRules );
    }

public
String
getMainDexClassesRulesPath
(
)
{
File
mainDexClassesRules
=
new
File
(
getBuildToolInfo
(
)
.
getLocation
(
)
,
"mainDexClasses.rules"
)
;
if
(
mainDexClassesRules
.
exists
(
)
)
{
return
mainDexClassesRules
.
getAbsolutePath
(
)
;
}
throw
new
InvalidSdkException
(
"Cannot find "
+
mainDexClassesRules
)
;
}

Get the path for mainDexClasses.rules
@return


public String getAndroidPath()
    {
        String cmd = "android";
        String ext = SdkConstants.currentPlatform() == 2 ? ".bat" : "";

        return getPathForTool( cmd + ext );
    }

public String getAndroidPath ( ) { String cmd = "android" ; String ext = SdkConstants . currentPlatform ( ) == 2 ? ".bat" : "" ; return getPathForTool ( cmd + ext ) ; }


public File getAndroidJar() throws MojoExecutionException
    {
        final String androidJarPath = androidTarget.getPath( IAndroidTarget.ANDROID_JAR );
        if ( androidJarPath == null )
        {
            throw new MojoExecutionException( "No AndroidJar found for " + androidTarget.getLocation() );
        }
        return new File ( androidJarPath );
    }

public
File
getAndroidJar
(
)
throws
MojoExecutionException
{
final
String
androidJarPath
=
androidTarget
.
getPath
(
IAndroidTarget
.
ANDROID_JAR
)
;
if
(
androidJarPath
==
)
{
throw
new
MojoExecutionException
(
"No AndroidJar found for "
+
androidTarget
.
getLocation
(
)
)
;
}
return
new
File
(
androidJarPath
)
;
}

Resolves the android.jar from this SDK.

@return a File pointing to the android.jar file.
@throws org.apache.maven.plugin.MojoExecutionException
if the file can not be resolved.

Resolves the android . jar from this SDK .


public File getPlatform()
    {
        assertPathIsDirectory( sdkPath );

        final File platformsDirectory = new File( sdkPath, PLATFORMS_FOLDER_NAME );
        assertPathIsDirectory( platformsDirectory );

        final File platformDirectory;
        if ( androidTarget == null )
        {
            IAndroidTarget latestTarget = null;
            AndroidTargetManager targetManager = sdkManager.getAndroidTargetManager( progressIndicator );
            for ( IAndroidTarget target: targetManager.getTargets( progressIndicator ) )
            {
                if ( target.isPlatform() )
                {
                    if ( latestTarget == null
                            || target.getVersion().getApiLevel() > latestTarget.getVersion().getApiLevel() )
                    {
                        latestTarget = target;
                    }
                }
            }
            platformDirectory = new File ( latestTarget.getLocation() );
        }
        else
        {
            platformDirectory = new File( androidTarget.getLocation() );
        }
        assertPathIsDirectory( platformDirectory );
        return platformDirectory;
    }

public File getPlatform ( ) { assertPathIsDirectory ( sdkPath ) ; final File platformsDirectory = new File ( sdkPath , PLATFORMS_FOLDER_NAME ) ; assertPathIsDirectory ( platformsDirectory ) ; final File platformDirectory ; if ( androidTarget == null ) { IAndroidTarget latestTarget = null ; AndroidTargetManager targetManager = sdkManager . getAndroidTargetManager ( progressIndicator ) ; for ( IAndroidTarget target : targetManager . getTargets ( progressIndicator ) ) { if ( target . isPlatform ( ) ) { if ( latestTarget == null || target . getVersion ( ) . getApiLevel ( ) > latestTarget . getVersion ( ) . getApiLevel ( ) ) { latestTarget = target ; } } } platformDirectory = new File ( latestTarget . getLocation ( ) ) ; } else { platformDirectory = new File ( androidTarget . getLocation ( ) ) ; } assertPathIsDirectory ( platformDirectory ) ; return platformDirectory ; }

This method returns the previously specified version. However, if none have been specified it returns the
"latest" version.

This method returns the previously specified version . However if none have been specified it returns the latest version .


private void loadSDKToolsMajorVersion()
    {
        File propFile = new File( sdkPath, "tools/" + SOURCE_PROPERTIES_FILENAME );
        Properties properties = new Properties();
        try
        {
            properties.load( new FileInputStream( propFile ) );
        }
        catch ( IOException e )
        {
            throw new InvalidSdkException( "Error reading " + propFile.getAbsoluteFile() );
        }

        if ( properties.containsKey( SDK_TOOLS_REVISION_PROPERTY ) )
        {
            try
            {
                String versionString = properties.getProperty( SDK_TOOLS_REVISION_PROPERTY );
                String majorVersion;
                if ( versionString.matches( ".*[\\.| ].*" ) )
                {
                    String[] versions = versionString.split( "[\\.| ]" );
                    majorVersion = versions[ 0 ];
                }
                else
                {
                    majorVersion = versionString;
                }
                sdkMajorVersion = Integer.parseInt( majorVersion );
            }
            catch ( NumberFormatException e )
            {
                throw new InvalidSdkException( "Error - The property '" + SDK_TOOLS_REVISION_PROPERTY
                        + "' in the SDK source.properties file  number is not an Integer: "
                        + properties.getProperty( SDK_TOOLS_REVISION_PROPERTY ) );
            }
        }
    }


public void execute() throws MojoExecutionException, MojoFailureException
    {
        // If the current POM isn't an Android-related POM, then don't do
        // anything. This helps work with multi-module projects.
        if ( !isCurrentProjectAndroid() )
        {
            return;
        }

        validateStandardLocations();

        try
        {
            targetDirectory.mkdirs();
            copyManifest();

            // Check for a deprecated AAR > APKLIB artifact combination
            if ( warnOnApklibDependencies )
            {
                checkForApklibDependencies();
            }

            // TODO Do we really want to continue supporting APKSOURCES? How long has it been deprecated
            extractSourceDependencies();

            // Extract the apklib and aar dependencies into unpacked-libs so that they can be referenced in the build.
            extractLibraryDependencies();

            // Copy project assets to combinedAssets so that aapt has a single assets folder to load.
            copyFolder( assetsDirectory, combinedAssets );

            final String[] relativeAidlFileNames1 = findRelativeAidlFileNames( aidlSourceDirectory );
            final String[] relativeAidlFileNames2 = findRelativeAidlFileNames( extractedDependenciesJavaSources );
            final Map<String, String[]> relativeApklibAidlFileNames = new HashMap<String, String[]>();

            if ( !isInstrumentationTest() )
            {
                // Only add transitive APKLIB deps if we are building an APK and not an instrumentation test apk.
                for ( Artifact artifact : getTransitiveDependencyArtifacts( APKLIB ) )
                {
                    final File libSourceFolder = getUnpackedApkLibSourceFolder( artifact );
                    final String[] apklibAidlFiles = findRelativeAidlFileNames( libSourceFolder );
                    relativeApklibAidlFileNames.put( artifact.getId(), apklibAidlFiles );
                }
            }

            checkPackagesForDuplicates();
            checkForConflictingLayouts();
            generateR();
            generateBuildConfig();

            // When compiling AIDL for this project,
            // make sure we compile AIDL for dependencies as well.
            // This is so project A, which depends on project B, can
            // use AIDL info from project B in its own AIDL
            final Map<File, String[]> files = new HashMap<File, String[]>();
            files.put( aidlSourceDirectory, relativeAidlFileNames1 );
            files.put( extractedDependenciesJavaSources, relativeAidlFileNames2 );

            if ( !isInstrumentationTest() )
            {
                // Only add transitive APKLIB deps if we are building an APK and not an instrumentation test apk.
                for ( Artifact artifact : getTransitiveDependencyArtifacts( APKLIB ) )
                {
                    final File unpackedLibSourceFolder = getUnpackedApkLibSourceFolder( artifact );
                    files.put( unpackedLibSourceFolder, relativeApklibAidlFileNames.get( artifact.getId() ) );
                }
            }
            generateAidlFiles( files );
        }
        catch ( MojoExecutionException e )
        {
            getLog().error( "Error when generating sources.", e );
            throw e;
        }
    }

Generates the sources.

@throws MojoExecutionException if it fails.
@throws MojoFailureException   if it fails.


protected void copyManifest() throws MojoExecutionException
    {
        getLog().debug( "copyManifest: " + androidManifestFile + " -> " + destinationManifestFile );
        if ( androidManifestFile == null )
        {
            getLog().debug( "Manifest copying disabled. Using default manifest only" );
            return;
        }

        try
        {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse( androidManifestFile );
            Source source = new DOMSource( doc );

            TransformerFactory xfactory = TransformerFactory.newInstance();
            Transformer xformer = xfactory.newTransformer();
            xformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );

            FileWriter writer = null;
            try
            {
                destinationManifestFile.getParentFile().mkdirs();

                writer = new FileWriter( destinationManifestFile, false );
                if ( doc.getXmlEncoding() != null && doc.getXmlVersion() != null )
                {
                    String xmldecl = String.format( "<?xml version=\"%s\" encoding=\"%s\"?>%n",
                            doc.getXmlVersion(), doc.getXmlEncoding() );

                    writer.write( xmldecl );
                }
                Result result = new StreamResult( writer );
                xformer.transform( source, result );
                getLog().info( "Manifest copied from " + androidManifestFile + " to " + destinationManifestFile );
            }
            finally
            {
                IOUtils.closeQuietly( writer );
            }
        }
        catch ( Exception e )
        {
            getLog().error( "Error during copyManifest" );
            throw new MojoExecutionException( "Error during copyManifest", e );
        }
    }

Copy the AndroidManifest.xml from androidManifestFile to destinationManifestFile

@throws MojoExecutionException

Copy the AndroidManifest . xml from androidManifestFile to destinationManifestFile


protected void extractSourceDependencies() throws MojoExecutionException
    {
        for ( Artifact artifact : getDirectDependencyArtifacts() )
        {
            String type = artifact.getType();
            if ( type.equals( APKSOURCES ) )
            {
                getLog().debug( "Detected apksources dependency " + artifact + " with file " + artifact.getFile()
                        + ". Will resolve and extract..." );

                final File apksourcesFile = resolveArtifactToFile( artifact );
                getLog().debug( "Extracting " + apksourcesFile + "..." );
                extractApksources( apksourcesFile );
            }
        }

        if ( extractedDependenciesJavaResources.exists() )
        {
            projectHelper.addResource( project, extractedDependenciesJavaResources.getAbsolutePath(), null, null );
            project.addCompileSourceRoot( extractedDependenciesJavaSources.getAbsolutePath() );
        }
    }

protected
void
extractSourceDependencies
(
)
throws
MojoExecutionException
{
for
(
Artifact
artifact
:
getDirectDependencyArtifacts
(
)
)
{
String
type
=
artifact
.
getType
(
)
;
if
(
type
.
equals
(
APKSOURCES
)
)
{
getLog
(
)
.
debug
(
"Detected apksources dependency "
+
artifact
+
" with file "
+
artifact
.
getFile
(
)
+
". Will resolve and extract..."
)
;
final
File
apksourcesFile
=
resolveArtifactToFile
(
artifact
)
;
getLog
(
)
.
debug
(
"Extracting "
+
apksourcesFile
+
"..."
)
;
extractApksources
(
apksourcesFile
)
;
}
}
if
(
extractedDependenciesJavaResources
.
exists
(
)
)
{
projectHelper
.
addResource
(
project
,
extractedDependenciesJavaResources
.
getAbsolutePath
(
)
,
,
)
;
project
.
addCompileSourceRoot
(
extractedDependenciesJavaSources
.
getAbsolutePath
(
)
)
;
}
}

Extract the source dependencies.

@throws MojoExecutionException if it fails.


private void extractApklib( Artifact apklibArtifact ) throws MojoExecutionException
    {
        getUnpackedLibHelper().extractApklib( apklibArtifact );

        // Copy the assets to the the combinedAssets folder.
        // Add the apklib source and resource to the compile.
        // NB apklib sources are added to compileSourceRoot because we may need to compile against them.
        //    This means the apklib classes will be compiled into target/classes and packaged with this build.
        copyFolder( getUnpackedLibAssetsFolder( apklibArtifact ), combinedAssets );

        final File apklibSourceFolder = getUnpackedApkLibSourceFolder( apklibArtifact );
        final List<String> resourceExclusions = Arrays.asList( "**/*.java", "**/*.aidl" );
        projectHelper.addResource( project, apklibSourceFolder.getAbsolutePath(), null, resourceExclusions );
        project.addCompileSourceRoot( apklibSourceFolder.getAbsolutePath() );
    }

Extracts ApkLib and adds the assets and apklib sources and resources to the build.

Extracts ApkLib and adds the assets and apklib sources and resources to the build .


private void extractAarLib( Artifact aarArtifact ) throws MojoExecutionException
    {
        getUnpackedLibHelper().extractAarLib( aarArtifact );

        // Copy the assets to the the combinedAssets folder, but only if an APK build.
        // Ie we only want to package assets that we own.
        // Assets should only live within their owners or the final APK.
        if ( isAPKBuild() )
        {
            copyFolder( getUnpackedLibAssetsFolder( aarArtifact ), combinedAssets );
        }

        // Aar lib resources should only be included if we are building an apk.
        // So we need to extract them into a folder that we then add to the resource classpath.
        if ( isAPKBuild() )
        {
            // (If we are including SYSTEM_SCOPE artifacts when considering resources for APK packaging)
            // then adding the AAR resources to the project would have them added twice.
            getLog().debug( "Not adding AAR resources to resource classpath : " + aarArtifact );
        }
    }

Extracts AarLib and if this is an APK build then adds the assets and resources to the build.

Extracts AarLib and if this is an APK build then adds the assets and resources to the build .


private void checkForApklibDependencies() throws MojoExecutionException
    {
        final boolean isAarBuild = project.getPackaging().equals( AAR );

        final DependencyResolver dependencyResolver = getDependencyResolver();

        final Set<Artifact> allArtifacts = project.getArtifacts();
        Set<Artifact> dependencyArtifacts = getArtifactResolverHelper().getFilteredArtifacts( allArtifacts );

        boolean foundApklib = false;

        for ( Artifact artifact : dependencyArtifacts )
        {
            final String type = artifact.getType();
            if ( type.equals( APKLIB ) && isAarBuild )
            {
                getLog().warn( "Detected APKLIB transitive dependency: " + artifact.getId() );
                foundApklib = true;
            }
            else if ( type.equals( AAR ) )
            {
                final Set<Artifact> dependencies = dependencyResolver
                        .getLibraryDependenciesFor( session, repositorySystem, artifact );
                for ( Artifact dependency : dependencies )
                {
                    if ( dependency.getType().equals( APKLIB ) )
                    {
                        getLog().warn( "Detected " + artifact.getId() + " that depends on APKLIB: "
                                + dependency.getId() );
                        foundApklib = true;
                    }
                }
            }
        }

        if ( foundApklib )
        {
            getLog().warn( "AAR libraries should not depend or include APKLIB artifacts.\n"
                    + "APKLIBs have been deprecated and the combination of the two may yield unexpected results.\n"
                    + "Check the problematic AAR libraries for newer versions that use AAR packaging." );
        }
    }

Traverses the list of project dependencies looking for "AAR depends on APKLIB" artifact combination
that has been deprecated. For each occurrence of an AAR artifact with APKLIB direct or transitive dependency,
produces a warning message to inform the user. Future plugin versions may default to skipping or not handling
unsupported artifacts during build lifecycle.

@throws MojoExecutionException

Traverses the list of project dependencies looking for &quot ; AAR depends on APKLIB&quot ; artifact combination that has been deprecated . For each occurrence of an AAR artifact with APKLIB direct or transitive dependency produces a warning message to inform the user . Future plugin versions may default to skipping or not handling unsupported artifacts during build lifecycle .


Map<String, Set<Artifact>> getPackageCompareMap( Set<Artifact> dependencyArtifacts ) throws MojoExecutionException
    {
        if ( dependencyArtifacts == null )
        {
            throw new IllegalArgumentException( "dependencies must be initialized" );
        }

        Map<String, Set<Artifact>> packageCompareMap = new HashMap<String, Set<Artifact>>();

        Set<Artifact> artifactSet = new HashSet<Artifact>();
        artifactSet.add( project.getArtifact() );
        packageCompareMap.put( getAndroidManifestPackageName(), artifactSet );

        for ( Artifact artifact : dependencyArtifacts )
        {
            String libPackage = extractPackageNameFromAndroidArtifact( artifact );

            Set<Artifact> artifacts = packageCompareMap.get( libPackage );
            if ( artifacts == null )
            {
                artifacts = new HashSet<Artifact>();
                packageCompareMap.put( libPackage, artifacts );
            }
            artifacts.add( artifact );
        }
        return packageCompareMap;
    }

Map
<
String
,
Set
<
Artifact
>
>
getPackageCompareMap
(
Set
<
Artifact
>
dependencyArtifacts
)
throws
MojoExecutionException
{
if
(
dependencyArtifacts
==
)
{
throw
new
IllegalArgumentException
(
"dependencies must be initialized"
)
;
}
Map
<
String
,
Set
<
Artifact
>
>
packageCompareMap
=
new
HashMap
<
String
,
Set
<
Artifact
>
>
(
)
;
Set
<
Artifact
>
artifactSet
=
new
HashSet
<
Artifact
>
(
)
;
artifactSet
.
add
(
project
.
getArtifact
(
)
)
;
packageCompareMap
.
put
(
getAndroidManifestPackageName
(
)
,
artifactSet
)
;
for
(
Artifact
artifact
:
dependencyArtifacts
)
{
String
libPackage
=
extractPackageNameFromAndroidArtifact
(
artifact
)
;
Set
<
Artifact
>
artifacts
=
packageCompareMap
.
get
(
libPackage
)
;
if
(
artifacts
==
)
{
artifacts
=
new
HashSet
<
Artifact
>
(
)
;
packageCompareMap
.
put
(
libPackage
,
artifacts
)
;
}
artifacts
.
add
(
artifact
)
;
}
return
packageCompareMap
;
}

Provides map with all provided dependencies or project itself grouped by package name

@param dependencyArtifacts artifacts that should be grouped by package name
@return map of with package names(String) and sets of artifacts (Set<Artifact>)
that have similar package names
@throws MojoExecutionException


private void generateCorrectRJavaForApklibDependencies( ResourceClassGenerator resourceGenerator )
            throws MojoExecutionException
    {
        getLog().debug( "" );
        getLog().debug( "#generateCorrectRJavaFoApklibDeps" );

        // Generate R.java for apklibs
        // Compatibility with Apklib which isn't present in AndroidBuilder
        getLog().debug( "Generating Rs for apklib deps of project " + project.getArtifact() );
        final Set<Artifact> apklibDependencies = getTransitiveDependencyArtifacts( APKLIB );
        for ( final Artifact artifact : apklibDependencies )
        {
            getLog().debug( "Generating apklib R.java for " + artifact.getArtifactId() + "..." );
            generateRForApkLibDependency( artifact );
        }

        // Generate corrected R.java for APKLIB dependencies, but only if this is an APK build.
        if ( !apklibDependencies.isEmpty() && APK.equals( project.getArtifact().getType() ) )
        {
            // Generate R.java for each APKLIB based on R.txt
            getLog().debug( "" );
            getLog().debug( "Rewriting R files for APKLIB dependencies : " + apklibDependencies );
            resourceGenerator.generateLibraryRs( apklibDependencies );
        }
    }

Generate correct R.java for apklibs dependencies of a current project

@throws MojoExecutionException

Generate correct R . java for apklibs dependencies of a current project


private void generateCorrectRJavaForAarDependencies( ResourceClassGenerator resourceGenerator )
            throws MojoExecutionException
    {
        // Generate corrected R.java for AAR dependencies.
        final Set<Artifact> aarLibraries = getTransitiveDependencyArtifacts( AAR );
        if ( !aarLibraries.isEmpty() )
        {
            // Generate R.java for each AAR based on R.txt
            getLog().debug( "Generating R file for AAR dependencies" );
            resourceGenerator.generateLibraryRs( aarLibraries );
        }
    }

Generate correct R.java for aar dependencies of a current project

@throws MojoExecutionException if it could not generate the R java for one of the libraries.

Generate correct R . java for aar dependencies of a current project


private void generateRForApkLibDependency( Artifact apklibArtifact ) throws MojoExecutionException
    {
        final File unpackDir = getUnpackedLibFolder( apklibArtifact );
        getLog().debug( "Generating incomplete R file for apklib: " + apklibArtifact.getGroupId()
                + ":" + apklibArtifact.getArtifactId() );
        final File apklibManifest = new File( unpackDir, "AndroidManifest.xml" );
        final File apklibResDir = new File( unpackDir, "res" );

        List<File> dependenciesResDirectories = new ArrayList<File>();
        final Set<Artifact> apklibDeps = getDependencyResolver()
                .getLibraryDependenciesFor( this.session, this.repositorySystem, apklibArtifact );
        getLog().debug( "apklib=" + apklibArtifact + "  dependencies=" + apklibDeps );
        for ( Artifact dependency : apklibDeps )
        {
            // Add in the resources that are dependencies of the apklib.
            final String extension = dependency.getType();
            final File dependencyResDir = getUnpackedLibResourceFolder( dependency );
            if ( ( extension.equals( APKLIB ) || extension.equals( AAR ) ) && dependencyResDir.exists() )
            {
                dependenciesResDirectories.add( dependencyResDir );
            }
        }

        // Create combinedAssets for this apklib dependency - can't have multiple -A args
        final File apklibCombAssets = new File( getUnpackedLibFolder( apklibArtifact ), "combined-assets" );
        for ( Artifact dependency : apklibDeps )
        {
            // Accumulate assets for dependencies of the apklib (if they exist).
            final String extension = dependency.getType();
            final File dependencyAssetsDir = getUnpackedLibAssetsFolder( dependency );
            if ( ( extension.equals( APKLIB ) || extension.equals( AAR ) ) )
            {
                copyFolder( dependencyAssetsDir, apklibCombAssets );
            }
        }
        // Overlay the apklib dependency assets (if they exist)
        final File apkLibAssetsDir = getUnpackedLibAssetsFolder( apklibArtifact );
        copyFolder( apkLibAssetsDir, apklibCombAssets );

        final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor();
        executor.setLogger( getLog() );

        final AaptCommandBuilder commandBuilder = AaptCommandBuilder
                .packageResources( getLog() )
                .makeResourcesNonConstant()
                .makePackageDirectories()
                .setResourceConstantsFolder( genDirectory )
                .generateRIntoPackage( extractPackageNameFromAndroidManifest( apklibManifest ) )
                .setPathToAndroidManifest( apklibManifest )
                .addResourceDirectoryIfExists( apklibResDir )
                .addResourceDirectoriesIfExists( dependenciesResDirectories )
                .autoAddOverlay()
                .addRawAssetsDirectoryIfExists( apklibCombAssets )
                .addExistingPackageToBaseIncludeSet( getAndroidSdk().getAndroidJar() )
                .addConfigurations( configurations )
                .setVerbose( aaptVerbose )
                .addExtraArguments( aaptExtraArgs )
                // We need to generate R.txt for all projects as it needs to be consumed when generating R class.
                // It also needs to be consumed when packaging aar.
                .generateRTextFile( unpackDir );

        getLog().debug( getAndroidSdk().getAaptPath() + " " + commandBuilder.toString() );
        try
        {
            executor.setCaptureStdOut( true );
            final List<String> commands = commandBuilder.build();
            executor.executeCommand( getAndroidSdk().getAaptPath(), commands, project.getBasedir(), false );
        }
        catch ( ExecutionException e )
        {
            throw new MojoExecutionException( "", e );
        }
    }

Executes aapt to generate the R class for the given apklib.

@param apklibArtifact apklib for which to generate the R class.
@throws MojoExecutionException if it fails.

Executes aapt to generate the R class for the given apklib .


private boolean isBuildConfigPresent( Artifact artifact ) throws MojoExecutionException
    {
        String depPackageName = extractPackageNameFromAndroidArtifact( artifact );

        return isBuildConfigPresent( artifact, depPackageName );
    }

private boolean isBuildConfigPresent ( Artifact artifact ) throws MojoExecutionException { String depPackageName = extractPackageNameFromAndroidArtifact ( artifact ) ; return isBuildConfigPresent ( artifact , depPackageName ) ; }

Check if given artifact includes a matching BuildConfig class

@throws MojoExecutionException


private boolean isBuildConfigPresent( Artifact artifact, String packageName ) throws MojoExecutionException
    {
        try
        {
            JarFile jar = new JarFile( getUnpackedAarClassesJar( artifact ) );
            JarEntry entry = jar.getJarEntry( packageName.replace( '.', '/' ) + "/BuildConfig.class" );

            return ( entry != null );
        }
        catch ( IOException e )
        {
            getLog().error( "Error generating BuildConfig ", e );
            throw new MojoExecutionException( "Error generating BuildConfig", e );
        }
    }

private
boolean
isBuildConfigPresent
(
Artifact
artifact
,
String
packageName
)
throws
MojoExecutionException
{
try
{
JarFile
jar
=
new
JarFile
(
getUnpackedAarClassesJar
(
artifact
)
)
;
JarEntry
entry
=
jar
.
getJarEntry
(
packageName
.
replace
(
'
'
,
'
'
)
+
"/BuildConfig.class"
)
;
return
(
entry
!=
)
;
}
catch
(
IOException
e
)
{
getLog
(
)
.
error
(
"Error generating BuildConfig "
,
e
)
;
throw
new
MojoExecutionException
(
"Error generating BuildConfig"
,
e
)
;
}
}

Check whether the artifact includes a BuildConfig located in a given package.

@param artifact    an AAR artifact to look for BuildConfig in
@param packageName BuildConfig package name
@throws MojoExecutionException

Check whether the artifact includes a BuildConfig located in a given package .


private Set< File > getDexInputFiles() throws MojoExecutionException
    {
        Set< File > inputs = new HashSet< File >();

        if ( obfuscatedJar != null && obfuscatedJar.exists() )
        {
            // proguard has been run, use this jar
            getLog().debug( "Adding dex input (obfuscatedJar) : " + obfuscatedJar );
            inputs.add( obfuscatedJar );
        }
        else
        {
            getLog().debug( "Using non-obfuscated input" );
            // no proguard, use original config
            inputs.add( projectOutputDirectory );
            getLog().debug( "Adding dex input : " + project.getBuild().getOutputDirectory() );
            for ( Artifact artifact : filterArtifacts( getTransitiveDependencyArtifacts(), skipDependencies,
                artifactTypeSet.getIncludes(), artifactTypeSet.getExcludes(), artifactSet.getIncludes(),
                artifactSet.getExcludes() ) )
            {
                if ( artifact.getType().equals( Const.ArtifactType.NATIVE_SYMBOL_OBJECT )
                    || artifact.getType().equals( Const.ArtifactType.NATIVE_IMPLEMENTATION_ARCHIVE ) )
                {
                    // Ignore native dependencies - no need for dexer to see those
                }
                else if ( artifact.getType().equals( APKLIB ) )
                {
                    // Any jars in the libs folder should now be
                    // automatically included because they will be a transitive dependency.
                }
                else if ( artifact.getType().equals( AAR ) )
                {
                    // The Aar classes.jar should now be automatically included
                    // because it will be a transitive dependency. As should any jars in the libs folder.
                }
                else if ( artifact.getType().equals( APK ) )
                {
                    // We need to dex the APK classes including the APK R.
                    // But we don't want to add a second instance of the embedded Rs for any of the APK's dependencies
                    // as they will already have been generated to target/classes. The R values from the APK will be
                    // the correct ones, so best solution is to extract the APK classes (including all Rs) to
                    // target/classes overwriting any generated Rs and let dex pick up the values from there.
                    getLog().debug( "Extracting APK classes to target/classes : " + artifact.getArtifactId() );
                    final File apkClassesJar = getUnpackedLibHelper().getJarFileForApk( artifact );
                    getLog().debug( "Extracting APK : " + apkClassesJar + " to " + targetDirectory );
                    final ZipExtractor extractor = new ZipExtractor( getLog() );
                    extractor.extract( apkClassesJar, targetDirectory, ".class" );
                }
                else
                {
                    getLog().debug( "Adding dex input : " + artifact.getFile() );
                    inputs.add( artifact.getFile().getAbsoluteFile() );
                }
            }
        }

        return inputs;
    }

Gets the input files for dex. This is a combination of directories and jar files.

@return

Gets the input files for dex . This is a combination of directories and jar files .


public void execute() throws MojoExecutionException, MojoFailureException
    {

        // If we're not on a supported packaging with just skip (Issue 87)
        // http://code.google.com/p/maven-android-plugin/issues/detail?id=87
        if ( ! SUPPORTED_PACKAGING_TYPES.contains( project.getPackaging() ) )
        {
            getLog().info( "Skipping zipalign on " + project.getPackaging() );
            return;
        }

        ConfigHandler configHandler = new ConfigHandler( this, this.session, this.execution );
        configHandler.parseConfiguration();

        parsedInputApk = FilenameUtils.separatorsToSystem( parsedInputApk );
        parsedOutputApk = FilenameUtils.separatorsToSystem( parsedOutputApk );

        getLog().debug( "skip:" + parsedSkip );
        getLog().debug( "verbose:" + parsedVerbose );
        getLog().debug( "inputApk:" + parsedInputApk );
        getLog().debug( "outputApk:" + parsedOutputApk );
        getLog().debug( "classifier:" + parsedClassifier );

        if ( parsedSkip )
        {
            getLog().info( "Skipping zipalign" );
        }
        else
        {
            boolean outputToSameFile = sameOutputAsInput();

            CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor();
            executor.setLogger( this.getLog() );

            String command = getAndroidSdk().getZipalignPath();

            List<String> parameters = new ArrayList<String>();
            if ( parsedVerbose )
            {
                parameters.add( "-v" );
            }
            parameters.add( "-f" ); // force overwriting existing output file
            parameters.add( "4" ); // byte alignment has to be 4!
            parameters.add( parsedInputApk );
            String outputApk = outputToSameFile ? getTemporaryOutputApkFilename() : parsedOutputApk;
            parameters.add( outputApk );

            try
            {
                getLog().info( "Running command: " + command );
                getLog().info( "with parameters: " + parameters );
                executor.setCaptureStdOut( true );
                executor.executeCommand( command, parameters );

                if ( FileUtils.fileExists( outputApk ) )
                {
                    if ( outputToSameFile )
                    {
                        // No needs to attach zipaligned apk to artifacts
                        try
                        {
                            FileUtils.rename( new File( outputApk ),  new File( parsedInputApk ) );
                        }
                        catch ( IOException e )
                        {
                            getLog().error( "Failed to replace original apk with aligned "
                                    + getFullPathWithName( outputApk ), e );
                        }
                    }
                    else
                    {
                        // Attach the resulting artifact (Issue 88)
                        // http://code.google.com/p/maven-android-plugin/issues/detail?id=88
                        projectHelper.attachArtifact( project, APK, parsedClassifier, new File( outputApk ) );
                        getLog().info( "Attach " + getFullPathWithName( outputApk )  + " as '"
                                + parsedClassifier + "' to the project" );
                    }
                }
                else
                {
                    getLog().error( "Cannot attach " + getFullPathWithName( outputApk ) + " to the project"
                            + " - The file does not exist" );
                }
            }
            catch ( ExecutionException e )
            {
                throw new MojoExecutionException( "", e );
            }
        }
    }

Execute the mojo by parsing the confign and actually doing the zipalign.

@throws MojoExecutionException

Execute the mojo by parsing the confign and actually doing the zipalign .


private static void checkClientSecretsFile( GoogleClientSecrets clientSecrets )
    {
        if ( clientSecrets.getDetails().getClientId().startsWith( "[[INSERT" )
                || clientSecrets.getDetails().getClientSecret().startsWith( "[[INSERT" ) )
        {
            LOG.error( "Enter Client ID and Secret from "
                    + "APIs console into resources/client_secrets.json." );
            System.exit( 1 );
        }
    }

Ensure the client secrets file has been filled out.

@param clientSecrets the GoogleClientSecrets containing data from the
file

Ensure the client secrets file has been filled out .


private void addLibsJarsToClassPath( UnpackedLibHelper helper, MavenProject project, Artifact artifact )
        throws MavenExecutionException
    {
         try
         {
             final File unpackLibFolder = helper.getUnpackedLibFolder( artifact );
             final File artifactFile = helper.getArtifactToFile( artifact );
             ZipFile zipFile = new ZipFile( artifactFile );
             Enumeration enumeration = zipFile.entries();
             while ( enumeration.hasMoreElements() )
             {
                 ZipEntry entry = ( ZipEntry )  enumeration.nextElement();
                 String entryName = entry.getName();

                 // Only jar files under 'libs' directory to be processed.
                 if ( Pattern.matches( "^libs/.+\\.jar$", entryName ) )
                 {
                     final File libsJarFile = new File( unpackLibFolder, entryName );
                     log.warn( "Adding jar from libs folder to classpath: " + libsJarFile );

                     // In order to satisfy the LifecycleDependencyResolver on execution up to a phase that
                     // has a Mojo requiring dependency resolution I need to create a dummy classesJar here.
                     if ( !libsJarFile.getParentFile().exists() )
                     {
                         libsJarFile.getParentFile().mkdirs();
                     }
                     libsJarFile.createNewFile();

                     // Add the jar to the classpath.
                     final Dependency dependency =
                            createSystemScopeDependency( artifact, libsJarFile, libsJarFile.getName() );

                     project.getModel().addDependency( dependency );
                     addedJarFromLibs = true;
                 }
             }
         }
         catch ( MojoExecutionException e )
         {
             log.debug( "Error extract jars" );
         }
         catch ( ZipException e )
         {
             log.debug( "Error" );
         }
         catch ( IOException e )
         {
             log.debug( "Error" );
         }
    }

Add jar files in libs into the project classpath.

Add jar files in libs into the project classpath .


private void addClassesToClasspath( UnpackedLibHelper helper, MavenProject project, Artifact artifact )
        throws MavenExecutionException
    {
        // Work out where the dep will be extracted and calculate the file path to the classes jar.
        // This is location where the GenerateSourcesMojo will extract the classes.
        final File classesJar = helper.getUnpackedClassesJar( artifact );
        log.debug( "Adding to classpath : " + classesJar );

        // In order to satisfy the LifecycleDependencyResolver on execution up to a phase that
        // has a Mojo requiring dependency resolution I need to create a dummy classesJar here.
        if ( !classesJar.exists() )
        {
            classesJar.getParentFile().mkdirs();
            try
            {
                final ZipOutputStream zipOutputStream = new ZipOutputStream( new FileOutputStream( classesJar ) );
                zipOutputStream.putNextEntry( new ZipEntry( "dummy" ) );
                zipOutputStream.close();
                log.debug( "Created dummy " + classesJar.getName() + " exist=" + classesJar.exists() );
            }
            catch ( IOException e )
            {
                throw new MavenExecutionException( "Could not add " + classesJar.getName() + " as dependency", e );
            }
        }

        // Modify the classpath to use an extracted dex file.  This will overwrite
        // any exisiting dependencies with the same information.
        final Dependency dependency = createSystemScopeDependency( artifact, classesJar, null );
        final Dependency providedJar = findProvidedDependencies( dependency, project );
        if ( providedJar != null )
        {
            project.getModel().removeDependency( providedJar );
        }
        project.getModel().addDependency( dependency );
    }

Add the dependent library classes to the project classpath.

Add the dependent library classes to the project classpath .


@Override
    public void execute() throws MojoExecutionException, MojoFailureException
    {
        ConfigHandler configHandler = new ConfigHandler( this, this.session, this.execution );
        configHandler.parseConfiguration();
        getLog().debug( "Parsed values for Android Lint invocation: " );
        getLog().debug( "failOnError:" + parsedFailOnError );
        getLog().debug( "skip:" + parsedSkip );
        getLog().debug( "legacy:" + parsedLegacy );
        getLog().debug( "quiet:" + parsedQuiet );
        getLog().debug( "ignoreWarnings:" + parsedIgnoreWarnings );
        getLog().debug( "warnAll:" + parsedWarnAll );
        getLog().debug( "warningsAsErrors:" + parsedWarningsAsErrors );
        getLog().debug( "config2:" + parsedConfig );

        getLog().debug( "fullPath:" + parsedFullPath );
        getLog().debug( "showAll:" + parsedShowAll );
        getLog().debug( "disableSourceLines:" + parsedDisableSourceLines );

        getLog().debug( "enablehtml: " + parsedEnableHtml );
        getLog().debug( "htmlOutputPath:" + parsedHtmlOutputPath );

        getLog().debug( "enableSimpleHtml: " + parsedEnableSimpleHtml );
        getLog().debug( "simpleHtmlOutputPath:" + parsedSimpleHtmlOutputPath );

        getLog().debug( "enableXml: " + parsedEnableXml );
        getLog().debug( "xmlOutputPath:" + parsedXmlOutputPath );

        getLog().debug( "sources:" + parsedSources );
        getLog().debug( "classpath:" + parsedClasspath );
        getLog().debug( "libraries:" + parsedLibraries );

        if ( parsedSkip )
        {
            getLog().info( "Skipping lint analysis." );
        }
        else
        {
            getLog().info( "Performing lint analysis." );

            if ( parsedLegacy )
            {
                getLog().info( "Using Lint from the Android SDK." );
                executeWhenConfigured();
            }
            else
            {
                getLog().info( "Using Lint dependency library." );
                runLint();
            }
        }
    }

Execute the mojo by parsing the config and actually invoking the lint command from the Android SDK.

@throws MojoExecutionException

Execute the mojo by parsing the config and actually invoking the lint command from the Android SDK .


public static String getGAV()
  {
    StringBuilder builder = new StringBuilder()
      .append( groupId )
      .append( COLON )
      .append( artifactId )
      .append( COLON )
      .append( version );
      return builder.toString();
  }

public static String getGAV ( ) { StringBuilder builder = new StringBuilder ( ) . append ( groupId ) . append ( COLON ) . append ( artifactId ) . append ( COLON ) . append ( version ) ; return builder . toString ( ) ; }

Get the Maven GAV string of the plugin.
@return

Get the Maven GAV string of the plugin .


private void collectJvmArguments( List< String > commands )
    {
        if ( parsedJvmArguments != null )
        {
            for ( String jvmArgument : parsedJvmArguments )
            {
                // preserve backward compatibility allowing argument with or without dash (e.g.
                // Xmx512m as well as -Xmx512m should work) (see
                // http://code.google.com/p/maven-android-plugin/issues/detail?id=153)
                if ( !jvmArgument.startsWith( "-" ) )
                {
                    jvmArgument = "-" + jvmArgument;
                }
                commands.add( jvmArgument );
            }
        }
    }

Convert the jvm arguments in parsedJvmArguments as populated by the config in format as needed by the java
command. Also preserve backwards compatibility in terms of dashes required or not..

Convert the jvm arguments in parsedJvmArguments as populated by the config in format as needed by the java command . Also preserve backwards compatibility in terms of dashes required or not ..


private File getJVMLibrary( String fileName )
    {
        File libFile = new File( getJavaLibDir(), fileName );
        if ( !libFile.exists() )
        {
            libFile = new File( getAltJavaLibDir(), fileName );
            if ( !libFile.exists() )
            {
                libFile = null;
            }
        }
        return libFile;
    }

private File getJVMLibrary ( String fileName ) { File libFile = new File ( getJavaLibDir ( ) , fileName ) ; if ( ! libFile . exists ( ) ) { libFile = new File ( getAltJavaLibDir ( ) , fileName ) ; if ( ! libFile . exists ( ) ) { libFile = null ; } } return libFile ; }

Finds a library file in either the primary or alternate lib directory.
@param fileName The base name of the file.
@return Either a canonical filename, or {@code null} if not found.

Finds a library file in either the primary or alternate lib directory .


public String getToolchain( File file ) throws MojoExecutionException
    {
        String resolvedNdkToolchain = null;

        // try to resolve the toolchain now
        String ndkArchitecture = file.getParentFile().getName();
        if ( ndkArchitecture.startsWith( "armeabi" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( ARM_TOOLCHAIN );
        }
        else if ( ndkArchitecture.startsWith( "arm64" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( ARM64_TOOLCHAIN );
        }
        else if ( ndkArchitecture.startsWith( "x86_64" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( X86_64_TOOLCHAIN );
        }
        else if ( ndkArchitecture.startsWith( "x86" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( X86_TOOLCHAIN );
        }
        else if ( ndkArchitecture.startsWith( "mips64" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( MIPS64_TOOLCHAIN );
        }
        else if ( ndkArchitecture.startsWith( "mips" ) )
        {
            resolvedNdkToolchain = resolveNdkToolchain( MIPS_TOOLCHAIN );
        }

        // if no toolchain can be found
        if ( resolvedNdkToolchain == null )
        {
            throw new MojoExecutionException(
                "Can not resolve automatically a toolchain to use. Please specify one." );
        }
        return resolvedNdkToolchain;
    }

Tries to resolve the toolchain based on the path of the file.

@param file Native library
@return String
@throws MojoExecutionException When no toolchain is found

Tries to resolve the toolchain based on the path of the file .


public String getNdkBuildPath()
    {
        if ( SystemUtils.IS_OS_WINDOWS )
        {
            return new File( ndkPath, "/ndk-build.cmd" ).getAbsolutePath();
        }
        else
        {
            return new File( ndkPath, "/ndk-build" ).getAbsolutePath();
        }
    }

public String getNdkBuildPath ( ) { if ( SystemUtils . IS_OS_WINDOWS ) { return new File ( ndkPath , "/ndk-build.cmd" ) . getAbsolutePath ( ) ; } else { return new File ( ndkPath , "/ndk-build" ) . getAbsolutePath ( ) ; } }

Returns the complete path for the ndk-build tool, based on this NDK.

@return the complete path as a String, including the tool's filename.

Returns the complete path for the ndk - build tool based on this NDK .


private Document readManifest( File manifestFile ) throws IOException, ParserConfigurationException, SAXException
    {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse( manifestFile );
        return doc;
    }

private Document readManifest ( File manifestFile ) throws IOException , ParserConfigurationException , SAXException { DocumentBuilderFactory dbf = DocumentBuilderFactory . newInstance ( ) ; DocumentBuilder db = dbf . newDocumentBuilder ( ) ; Document doc = db . parse ( manifestFile ) ; return doc ; }


private void writeManifest( File manifestFile, Document doc ) throws IOException, TransformerException
    {
        TransformerFactory xfactory = TransformerFactory.newInstance();
        Transformer xformer = xfactory.newTransformer();
        xformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
        Source source = new DOMSource( doc );

        OutputStreamWriter writer = null;
        try
        {
            manifestFile.getParentFile().mkdirs();

            String encoding = doc.getXmlEncoding() != null ? doc.getXmlEncoding() : "UTF-8";
            writer = new OutputStreamWriter( new FileOutputStream( manifestFile, false ), encoding );
            if ( doc.getXmlEncoding() != null && doc.getXmlVersion() != null )
            {
                String xmldecl = String
                    .format( "<?xml version=\"%s\" encoding=\"%s\"?>%n", doc.getXmlVersion(), doc.getXmlEncoding() );
                writer.write( xmldecl );
            }
            Result result = new StreamResult( writer );

            xformer.transform( source, result );
        }
        finally
        {
            IOUtils.closeQuietly( writer );
        }
    }


private void exportProperties()
    {
        project.getProperties().setProperty( "android.manifest.versionName", parsedVersionName );
        project.getProperties().setProperty( "android.manifest.versionCodeAutoIncrement",
                String.valueOf( parsedVersionCodeAutoIncrement ) );
        project.getProperties().setProperty( "android.manifest.versionCodeUpdateFromVersion",
                String.valueOf( parsedVersionCodeUpdateFromVersion ) );
        project.getProperties().setProperty( "android.manifest.debuggable", String.valueOf( parsedDebuggable ) );
        if ( parsedSharedUserId != null )
        {
            project.getProperties().setProperty( "android.manifest.sharedUserId", parsedSharedUserId );
        }
    }

Expose the version properties and other simple parsed manifest entries.

Expose the version properties and other simple parsed manifest entries .


private void performVersionCodeUpdateFromVersion( Element manifestElement ) throws MojoExecutionException
    {
        String verString = project.getVersion();
        getLog().debug( "Generating versionCode for " + verString );
        String verCode = generateVersionCodeFromVersionName( verString );
        getLog().info( "Setting " + ATTR_VERSION_CODE + " to " + verCode );
        manifestElement.setAttribute( ATTR_VERSION_CODE, verCode );
        project.getProperties().setProperty( "android.manifest.versionCode", String.valueOf( verCode ) );
    }

private
void
performVersionCodeUpdateFromVersion
(
Element
manifestElement
)
throws
MojoExecutionException
{
String
verString
=
project
.
getVersion
(
)
;
getLog
(
)
.
debug
(
"Generating versionCode for "
+
verString
)
;
String
verCode
=
generateVersionCodeFromVersionName
(
verString
)
;
getLog
(
)
.
info
(
"Setting "
+
ATTR_VERSION_CODE
+
" to "
+
verCode
)
;
manifestElement
.
setAttribute
(
ATTR_VERSION_CODE
,
verCode
)
;
project
.
getProperties
(
)
.
setProperty
(
"android.manifest.versionCode"
,
String
.
valueOf
(
verCode
)
)
;
}

If the specified version name cannot be properly parsed then fall back to
an automatic method.
If the version can be parsed then generate a version code from the
version components.  In an effort to preseve uniqueness two digits
are allowed for both the minor and incremental versions.
@throws MojoExecutionException

If the specified version name cannot be properly parsed then fall back to an automatic method . If the version can be parsed then generate a version code from the version components . In an effort to preseve uniqueness two digits are allowed for both the minor and incremental versions .


public static String extractArchitectureFromArtifact( Artifact artifact, final String defaultArchitecture )
    {
        String classifier = artifact.getClassifier();
        if ( classifier != null )
        {
            //
            // We loop backwards to catch the case where the classifier is
            // potentially armeabi-v7a - this collides with armeabi if looping
            // through this loop in the other direction
            //

            for ( int i = AndroidNdk.NDK_ARCHITECTURES.length - 1; i >= 0; i-- )
            {
                String ndkArchitecture = AndroidNdk.NDK_ARCHITECTURES[i];
                if ( classifier.startsWith( ndkArchitecture ) )
                {
                    return ndkArchitecture;
                }
            }

        }
        // Default case is to return the default architecture
        return defaultArchitecture;
    }

Extracts, if embedded correctly, the artifacts architecture from its classifier.  The format of the
classifier, if including the architecture is <architecture>-<classifier>.  If no
architecture is embedded in the classifier, 'armeabi' will be returned.

@param artifact The artifact to retrieve the classifier from.
@param defaultArchitecture The architecture to return if can't be resolved from the classifier
@return The retrieved architecture, or defaulArchitecture if not resolveable

Extracts if embedded correctly the artifacts architecture from its classifier . The format of the classifier if including the architecture is &lt ; architecture&gt ; - &lt ; classifier&gt ; . If no architecture is embedded in the classifier armeabi will be returned .


public String[] getFileNames( File baseDirectory )
    {
        if ( !baseDirectory.exists() )
        {
            return new String[ 0 ];
        }

        final DirectoryScanner directoryScanner = new DirectoryScanner();
        directoryScanner.setBasedir( baseDirectory );
        directoryScanner.setIncludes( includes );
        directoryScanner.addDefaultExcludes();
        directoryScanner.scan();

        return directoryScanner.getIncludedFiles();
    }

public String [ ] getFileNames ( File baseDirectory ) { if ( ! baseDirectory . exists ( ) ) { return new String [ 0 ] ; } final DirectoryScanner directoryScanner = new DirectoryScanner ( ) ; directoryScanner . setBasedir ( baseDirectory ) ; directoryScanner . setIncludes ( includes ) ; directoryScanner . addDefaultExcludes ( ) ; directoryScanner . scan ( ) ; return directoryScanner . getIncludedFiles ( ) ; }

Finds the files in the supplied folder that match the configured includes.

@param baseDirectory Directory to find files in.
@return String[] of the files' paths and names, relative to baseDirectory. Empty
String[] if baseDirectory does not exist.

Finds the files in the supplied folder that match the configured includes .


public static String encrypt(String data, String key) {
        try {
            Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding");
            c.init(Cipher.ENCRYPT_MODE, SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key.getBytes())));
            return Hex.encodeHexString(c.doFinal(data.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

public static String encrypt ( String data , String key ) { try { Cipher c = Cipher . getInstance ( "DES/ECB/PKCS5Padding" ) ; c . init ( Cipher . ENCRYPT_MODE , SecretKeyFactory . getInstance ( "DES" ) . generateSecret ( new DESKeySpec ( key . getBytes ( ) ) ) ) ; return Hex . encodeHexString ( c . doFinal ( data . getBytes ( ) ) ) ; } catch ( Exception e ) { e . printStackTrace ( ) ; } return null ; }

Convert data to encrypted hex string
@param data data to encrypt
@param key encrypt key
@return hex string


public static String decrypt(String data, String key) {
        try {
            Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding");
            c.init(Cipher.DECRYPT_MODE, SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(key.getBytes())));
            return new String(c.doFinal(Hex.decodeHex(data.toCharArray())), Charset.defaultCharset());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

public static String decrypt ( String data , String key ) { try { Cipher c = Cipher . getInstance ( "DES/ECB/PKCS5Padding" ) ; c . init ( Cipher . DECRYPT_MODE , SecretKeyFactory . getInstance ( "DES" ) . generateSecret ( new DESKeySpec ( key . getBytes ( ) ) ) ) ; return new String ( c . doFinal ( Hex . decodeHex ( data . toCharArray ( ) ) ) , Charset . defaultCharset ( ) ) ; } catch ( Exception e ) { e . printStackTrace ( ) ; } return null ; }

Convert encrypted hex string to UTF-8 string
@param data data to decrypt
@param key decrypt key
@return UTF-8 string

Convert encrypted hex string to UTF - 8 string


private static String readName(
            byte data[],
            int offset,
            HashSet<Integer> jumps
    ) throws IOException {
        int c = data[offset] & 0xff;
        if ((c & 0xc0) == 0xc0) {
            c = ((c & 0x3f) << 8) + (data[offset + 1] & 0xff);
            if (jumps.contains(c)) {
                throw new DnsException("", "Cyclic offsets detected.");
            }
            jumps.add(c);
            return readName(data, c, jumps);
        }
        if (c == 0) {
            return "";
        }
        String s = new String(data, offset + 1, c);
        String t = readName(data, offset + 1 + c, jumps);
        if (t.length() > 0) {
            s = s + "." + t;
        }
        return s;
    }

private
static
String
readName
(
byte
data
[
]
,
int
offset
,
HashSet
<
Integer
>
jumps
)
throws
IOException
{
int
c
=
data
[
offset
]
&
0xff
;
if
(
(
c
&
0xc0
)
==
0xc0
)
{
c
=
(
(
c
&
0x3f
)
<<
8
)
+
(
data
[
offset
+
1
]
&
0xff
)
;
if
(
jumps
.
contains
(
c
)
)
{
throw
new
DnsException
(
""
,
"Cyclic offsets detected."
)
;
}
jumps
.
add
(
c
)
;
return
readName
(
data
,
c
,
jumps
)
;
}
if
(
c
==
0
)
{
return
""
;
}
String
s
=
new
String
(
data
,
offset
+
1
,
c
)
;
String
t
=
readName
(
data
,
offset
+
1
+
c
,
jumps
)
;
if
(
t
.
length
(
)
>
0
)
{
s
=
s
+
"."
+
t
;
}
return
s
;
}

Parse a domain name starting at the given offset.

@param data   The raw data.
@param offset The offset.
@param jumps  The list of jumps (by now).
@return The parsed domain name.
@throws IOException on cycles.

Parse a domain name starting at the given offset .


protected static int toDigit(final char ch, final int index) throws HexDecodeException {
        final int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new HexDecodeException("Illegal hexadecimal character " + ch + " at index " + index);
        }
        return digit;
    }

protected
static
int
toDigit
(
final
char
ch
,
final
int
index
)
throws
HexDecodeException
{
final
int
digit
=
Character
.
digit
(
ch
,
16
)
;
if
(
digit
==
1
)
{
throw
new
HexDecodeException
(
"Illegal hexadecimal character "
+
ch
+
" at index "
+
index
)
;
}
return
digit
;
}

Converts a hexadecimal character to an integer.

@param ch    A character to convert to an integer digit
@param index The index of the character in the source
@return An integer
@throws HexDecodeException Thrown if ch is an illegal hex character

Converts a hexadecimal character to an integer .


private boolean tryToMove(float deltaY) {

        // has reached the bottom
        if ((deltaY > 0 && mCurrentPos == 0)) {
            if (DEBUG) {
                Log.d(LOG_TAG, String.format("has reached the bottom"));
            }
            return false;
        }

        // has reached the top
        if ((deltaY < 0 && mCurrentPos == -mHeaderHeight)) {
            if (DEBUG) {
                Log.d(LOG_TAG, String.format("has reached the top"));
            }
            return false;
        }

        int to = mCurrentPos + (int) deltaY;

        // over top
        if (to < -mHeaderHeight) {
            if (DEBUG) {
                Log.d(LOG_TAG, String.format("over top"));
            }
            to = -mHeaderHeight;
        }

        // over bottom
        if (to > 0) {
            if (DEBUG) {
                Log.d(LOG_TAG, String.format("over bottom"));
            }
            to = 0;
        }
        return moveTo(to);
    }

private
boolean
tryToMove
(
float
deltaY
)
{
// has reached the bottom
if
(
(
deltaY
>
0
&&
mCurrentPos
==
0
)
)
{
if
(
DEBUG
)
{
Log
.
d
(
LOG_TAG
,
String
.
format
(
"has reached the bottom"
)
)
;
}
return
false
;
}
// has reached the top
if
(
(
deltaY
<
0
&&
mCurrentPos
==
mHeaderHeight
)
)
{
if
(
DEBUG
)
{
Log
.
d
(
LOG_TAG
,
String
.
format
(
"has reached the top"
)
)
;
}
return
false
;
}
int
to
=
mCurrentPos
+
(
int
)
deltaY
;
// over top
if
(
to
<
mHeaderHeight
)
{
if
(
DEBUG
)
{
Log
.
d
(
LOG_TAG
,
String
.
format
(
"over top"
)
)
;
}
to
=
mHeaderHeight
;
}
// over bottom
if
(
to
>
0
)
{
if
(
DEBUG
)
{
Log
.
d
(
LOG_TAG
,
String
.
format
(
"over bottom"
)
)
;
}
to
=
0
;
}
return
moveTo
(
to
)
;
}

if deltaY > 0, tryToMove the content down

if deltaY > 0 tryToMove the content down


public synchronized void startListening(Context context) {
        if (!mListening) {
            mContext = context;

            IntentFilter filter = new IntentFilter();
            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
            context.registerReceiver(mReceiver, filter);
            mListening = true;
        }
    }

public synchronized void startListening ( Context context ) { if ( ! mListening ) { mContext = context ; IntentFilter filter = new IntentFilter ( ) ; filter . addAction ( ConnectivityManager . CONNECTIVITY_ACTION ) ; context . registerReceiver ( mReceiver , filter ) ; mListening = true ; } }

This method starts listening for network connectivity state changes.

@param context

This method starts listening for network connectivity state changes .


public synchronized void stopListening() {
        if (mListening) {
            mContext.unregisterReceiver(mReceiver);
            mContext = null;
            mNetworkInfo = null;
            mOtherNetworkInfo = null;
            mIsFailOver = false;
            mReason = null;
            mListening = false;
        }
    }

public synchronized void stopListening ( ) { if ( mListening ) { mContext . unregisterReceiver ( mReceiver ) ; mContext = null ; mNetworkInfo = null ; mOtherNetworkInfo = null ; mIsFailOver = false ; mReason = null ; mListening = false ; } }

This method stops this class from listening for network changes.

This method stops this class from listening for network changes .


public void send() throws IOException {

        HashMap<String, RequestData.UploadFileInfo> uploadFiles = mRequestData.getUploadFiles();

        HashMap<String, Object> mPostData = mRequestData.getPostData();
        // send data to Server
        if (mPostData != null && mPostData.size() != 0) {

            Iterator<Map.Entry<String, Object>> iterator = mPostData.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> item = iterator.next();
                Object value = item.getValue();
                if (value == null) {
                    value = "";
                }
                addFormField(item.getKey(), value.toString());
            }
        }

        // send file to server
        Iterator<Map.Entry<String, RequestData.UploadFileInfo>> iterator = uploadFiles.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, RequestData.UploadFileInfo> item = iterator.next();
            RequestData.UploadFileInfo uploadFileInfo = item.getValue();
            addFilePart(uploadFileInfo.fieldName, uploadFileInfo.uploadFile, uploadFileInfo.fileName);
        }
    }

public
void
send
(
)
throws
IOException
{
HashMap
<
String
,
RequestData
.
UploadFileInfo
>
uploadFiles
=
mRequestData
.
getUploadFiles
(
)
;
HashMap
<
String
,
Object
>
mPostData
=
mRequestData
.
getPostData
(
)
;
// send data to Server
if
(
mPostData
!=
&&
mPostData
.
size
(
)
!=
0
)
{
Iterator
<
Map
.
Entry
<
String
,
Object
>
>
iterator
=
mPostData
.
entrySet
(
)
.
iterator
(
)
;
while
(
iterator
.
hasNext
(
)
)
{
Map
.
Entry
<
String
,
Object
>
item
=
iterator
.
next
(
)
;
Object
value
=
item
.
getValue
(
)
;
if
(
value
==
)
{
value
=
""
;
}
addFormField
(
item
.
getKey
(
)
,
value
.
toString
(
)
)
;
}
}
// send file to server
Iterator
<
Map
.
Entry
<
String
,
RequestData
.
UploadFileInfo
>
>
iterator
=
uploadFiles
.
entrySet
(
)
.
iterator
(
)
;
while
(
iterator
.
hasNext
(
)
)
{
Map
.
Entry
<
String
,
RequestData
.
UploadFileInfo
>
item
=
iterator
.
next
(
)
;
RequestData
.
UploadFileInfo
uploadFileInfo
=
item
.
getValue
(
)
;
addFilePart
(
uploadFileInfo
.
fieldName
,
uploadFileInfo
.
uploadFile
,
uploadFileInfo
.
fileName
)
;
}
}


public void addFormField(String name, String value) {
        mWriter.append("--" + mBoundary).append(LINE_FEED);
        mWriter.append("Content-Disposition: form-data; name=\"" + name + "\"")
                .append(LINE_FEED);
        mWriter.append("Content-Type: text/plain; charset=" + mCharset).append(
                LINE_FEED);
        mWriter.append(LINE_FEED);
        mWriter.append(value).append(LINE_FEED);
        mWriter.flush();
    }

Adds a form field to the request

@param name  field name
@param value field value


public void addFilePart(String fieldName, File uploadFile, String fileName) throws IOException {
        if (TextUtils.isEmpty(fileName)) {
            fileName = uploadFile.getName();
        }
        mWriter.append("--" + mBoundary).append(LINE_FEED);
        mWriter.append(
                "Content-Disposition: form-data; name=\"" + fieldName
                        + "\"; filename=\"" + fileName + "\"")
                .append(LINE_FEED);
        mWriter.append(
                "Content-Type: " + URLConnection.guessContentTypeFromName(fileName))
                .append(LINE_FEED);
        mWriter.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
        mWriter.append(LINE_FEED);
        mWriter.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            mOutputStream.write(buffer, 0, bytesRead);
        }
        mOutputStream.flush();
        inputStream.close();

        mWriter.append(LINE_FEED);
        mWriter.flush();
    }

Adds a upload file section to the request

@param fieldName  name attribute in <input type="file" name="..." />
@param uploadFile a File to be uploaded
@param fileName   the filename field
@throws IOException


public BitmapDrawable createBitmapDrawable(Resources resources, Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }
        BitmapDrawable drawable = null;
        if (bitmap != null) {
            if (Version.hasHoneycomb()) {
                // Running on Honeycomb or newer, so wrap in a standard BitmapDrawable
                drawable = new BitmapDrawable(resources, bitmap);
            } else {
                // Running on Gingerbread or older, so wrap in a RecyclingBitmapDrawable
                // which will recycle automatically
                drawable = new RecyclingBitmapDrawable(resources, bitmap);
            }
        }
        return drawable;
    }

Create a BitmapDrawable which can be managed in ImageProvider

@param resources
@param bitmap
@return


public void preLoadImages(String[] urls) {
        int len = urls.length;
        for (int i = 0; i < len; i++) {
            ImageLoadRequest request = new ImageLoadRequest(urls[i]);
            final ImageTask imageTask = createImageTask(request);
            imageTask.setIsPreLoad();
            addImageTask(imageTask, null);
        }
    }

public void preLoadImages ( String [ ] urls ) { int len = urls . length ; for ( int i = 0 ; i < len ; i ++ ) { ImageLoadRequest request = new ImageLoadRequest ( urls [ i ] ) ; final ImageTask imageTask = createImageTask ( request ) ; imageTask . setIsPreLoad ( ) ; addImageTask ( imageTask , null ) ; } }


public void detachImageViewFromImageTask(ImageTask imageTask, CubeImageView imageView) {
        imageTask.removeImageView(imageView);
        if (imageTask.isLoading()) {
            if (!imageTask.isPreLoad() && !imageTask.stillHasRelatedImageView()) {
                LoadImageTask task = mLoadWorkList.get(imageTask.getIdentityKey());
                if (task != null) {
                    task.cancel();
                }
                if (DEBUG) {
                    CLog.d(LOG_TAG, "%s previous work is cancelled.", imageTask);
                }
            }
        }
        if (!imageTask.stillHasRelatedImageView()) {
            imageTask.tryToRecycle();
        }
    }

public
void
detachImageViewFromImageTask
(
ImageTask
imageTask
,
CubeImageView
imageView
)
{
imageTask
.
removeImageView
(
imageView
)
;
if
(
imageTask
.
isLoading
(
)
)
{
if
(
!
imageTask
.
isPreLoad
(
)
&&
!
imageTask
.
stillHasRelatedImageView
(
)
)
{
LoadImageTask
task
=
mLoadWorkList
.
get
(
imageTask
.
getIdentityKey
(
)
)
;
if
(
task
!=
)
{
task
.
cancel
(
)
;
}
if
(
DEBUG
)
{
CLog
.
d
(
LOG_TAG
,
"%s previous work is cancelled."
,
imageTask
)
;
}
}
}
if
(
!
imageTask
.
stillHasRelatedImageView
(
)
)
{
imageTask
.
tryToRecycle
(
)
;
}
}

Detach the ImageView from the ImageTask.

@param imageTask
@param imageView

Detach the ImageView from the ImageTask .


public void addImageTask(ImageTask imageTask, CubeImageView imageView) {
        if (!mHasBeenAddedToComponentManager) {
            CLog.w(LOG_TAG, "ImageLoader has not been add to a Component Manager.", this);
        }
        LoadImageTask runningTask = mLoadWorkList.get(imageTask.getIdentityKey());
        if (runningTask != null) {
            if (imageView != null) {
                if (DEBUG) {
                    CLog.d(LOG_TAG, MSG_ATTACK_TO_RUNNING_TASK, imageTask, runningTask.getImageTask());
                }
                runningTask.getImageTask().addImageView(imageView);
                runningTask.getImageTask().notifyLoading(mImageLoadHandler, imageView);
            }
            return;
        } else {
            imageTask.addImageView(imageView);
        }

        imageTask.onLoading(mImageLoadHandler);

        LoadImageTask loadImageTask = createLoadImageTask(imageTask);
        mLoadWorkList.put(imageTask.getIdentityKey(), loadImageTask);
        mImageTaskExecutor.execute(loadImageTask);
    }

Add the ImageTask into loading list.

@param imageTask
@param imageView


public boolean queryCache(ImageTask imageTask, CubeImageView imageView) {
        if (null == mImageProvider) {
            return false;
        }
        BitmapDrawable drawable = mImageProvider.getBitmapFromMemCache(imageTask);

        if (imageTask.getStatistics() != null) {
            imageTask.getStatistics().s0_afterCheckMemoryCache(drawable != null);
        }
        if (drawable == null) {
            return false;
        }

        if (DEBUG) {
            CLog.d(LOG_TAG, MSG_HIT_CACHE, imageTask, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        }
        imageTask.addImageView(imageView);
        imageTask.onLoadTaskFinish(drawable, mImageLoadHandler);
        return true;
    }

public boolean queryCache ( ImageTask imageTask , CubeImageView imageView ) { if ( null == mImageProvider ) { return false ; } BitmapDrawable drawable = mImageProvider . getBitmapFromMemCache ( imageTask ) ; if ( imageTask . getStatistics ( ) != null ) { imageTask . getStatistics ( ) . s0_afterCheckMemoryCache ( drawable != null ) ; } if ( drawable == null ) { return false ; } if ( DEBUG ) { CLog . d ( LOG_TAG , MSG_HIT_CACHE , imageTask , drawable . getIntrinsicWidth ( ) , drawable . getIntrinsicHeight ( ) ) ; } imageTask . addImageView ( imageView ) ; imageTask . onLoadTaskFinish ( drawable , mImageLoadHandler ) ; return true ; }

Check weather this imageTask has cache Drawable data.

Check weather this imageTask has cache Drawable data .


public void recoverWork() {
        if (DEBUG) {
            CLog.d(LOG_TAG, "work_status: recoverWork %s", this);
        }
        mExitTasksEarly = false;
        setPause(false);
        Iterator<Entry<String, LoadImageTask>> it = (Iterator<Entry<String, LoadImageTask>>) mLoadWorkList.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, LoadImageTask> item = it.next();
            LoadImageTask task = item.getValue();
            task.restart();
            mImageTaskExecutor.execute(task);
        }
    }

public
void
recoverWork
(
)
{
if
(
DEBUG
)
{
CLog
.
d
(
LOG_TAG
,
"work_status: recoverWork %s"
,
this
)
;
}
mExitTasksEarly
=
false
;
setPause
(
false
)
;
Iterator
<
Entry
<
String
,
LoadImageTask
>
>
it
=
(
Iterator
<
Entry
<
String
,
LoadImageTask
>
>
)
mLoadWorkList
.
entrySet
(
)
.
iterator
(
)
;
while
(
it
.
hasNext
(
)
)
{
Entry
<
String
,
LoadImageTask
>
item
=
it
.
next
(
)
;
LoadImageTask
task
=
item
.
getValue
(
)
;
task
.
restart
(
)
;
mImageTaskExecutor
.
execute
(
task
)
;
}
}


public void stopWork() {
        if (DEBUG) {
            CLog.d(LOG_TAG, "work_status: stopWork %s", this);
        }
        mExitTasksEarly = true;
        setPause(false);

        flushFileCache();
    }

public
void
stopWork
(
)
{
if
(
DEBUG
)
{
CLog
.
d
(
LOG_TAG
,
"work_status: stopWork %s"
,
this
)
;
}
mExitTasksEarly
=
true
;
setPause
(
false
)
;
flushFileCache
(
)
;
}

Drop all the work, and leave it in the work list.

Drop all the work and leave it in the work list .


public void destroy() {
        if (DEBUG) {
            CLog.d(LOG_TAG, "work_status: destroy %s", this);
        }
        mExitTasksEarly = true;
        setPause(false);

        Iterator<Entry<String, LoadImageTask>> it = (Iterator<Entry<String, LoadImageTask>>) mLoadWorkList.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, LoadImageTask> item = it.next();
            final LoadImageTask task = item.getValue();
            it.remove();
            if (task != null) {
                task.cancel();
            }
        }
        mLoadWorkList.clear();
    }

public
void
destroy
(
)
{
if
(
DEBUG
)
{
CLog
.
d
(
LOG_TAG
,
"work_status: destroy %s"
,
this
)
;
}
mExitTasksEarly
=
true
;
setPause
(
false
)
;
Iterator
<
Entry
<
String
,
LoadImageTask
>
>
it
=
(
Iterator
<
Entry
<
String
,
LoadImageTask
>
>
)
mLoadWorkList
.
entrySet
(
)
.
iterator
(
)
;
while
(
it
.
hasNext
(
)
)
{
Entry
<
String
,
LoadImageTask
>
item
=
it
.
next
(
)
;
final
LoadImageTask
task
=
item
.
getValue
(
)
;
it
.
remove
(
)
;
if
(
task
!=
)
{
task
.
cancel
(
)
;
}
}
mLoadWorkList
.
clear
(
)
;
}


public ImageLoader attachToCubeFragment(CubeFragment fragment) {
        if (fragment != null) {
            if (LifeCycleComponentManager.tryAddComponentToContainer(this, fragment, true)) {
                mHasBeenAddedToComponentManager = true;
            }
        }
        return this;
    }

public ImageLoader attachToCubeFragment ( CubeFragment fragment ) { if ( fragment != null ) { if ( LifeCycleComponentManager . tryAddComponentToContainer ( this , fragment , true ) ) { mHasBeenAddedToComponentManager = true ; } } return this ; }

LiefCycle phase will be same to CubeFragment, an will be processed automatically.

@param fragment
@return

LiefCycle phase will be same to CubeFragment an will be processed automatically .


public void invalidateCache(String key) {
        if (DEBUG) {
            CLog.d(LOG_TAG, "key: %s, invalidateCache", key);
        }
        try {
            mFileCache.getDiskCache().delete(key);
        } catch (IOException e) {
            if (DEBUG) {
                e.printStackTrace();
            }
        }
        mMemoryCache.remove(key);
    }

public
void
invalidateCache
(
String
key
)
{
if
(
DEBUG
)
{
CLog
.
d
(
LOG_TAG
,
"key: %s, invalidateCache"
,
key
)
;
}
try
{
mFileCache
.
getDiskCache
(
)
.
delete
(
key
)
;
}
catch
(
IOException
e
)
{
if
(
DEBUG
)
{
e
.
printStackTrace
(
)
;
}
}
mMemoryCache
.
remove
(
key
)
;
}


public void clearDiskCache() {
        if (null != mFileCache) {
            try {
                mFileCache.getDiskCache().clear();
            } catch (IOException e) {
                if (DEBUG) {
                    e.printStackTrace();
                }
            }
        }
    }

public void clearDiskCache ( ) { if ( null != mFileCache ) { try { mFileCache . getDiskCache ( ) . clear ( ) ; } catch ( IOException e ) { if ( DEBUG ) { e . printStackTrace ( ) ; } } } }


private SimpleHashSetEntry<T>[] makeTable(int newCapacity) {
        @SuppressWarnings("unchecked")
        SimpleHashSetEntry<T>[] newTable = (SimpleHashSetEntry<T>[]) new SimpleHashSetEntry[newCapacity];
        mTable = newTable;
        threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
        return newTable;
    }

private
SimpleHashSetEntry
<
T
>
[
]
makeTable
(
int
newCapacity
)
{
@
SuppressWarnings
(
"unchecked"
)
SimpleHashSetEntry
<
T
>
[
]
newTable
=
(
SimpleHashSetEntry
<
T
>
[
]
)
new
SimpleHashSetEntry
[
newCapacity
]
;
mTable
=
newTable
;
threshold
=
(
newCapacity
>>
1
)
+
(
newCapacity
>>
2
)
;
// 3/4 capacity
return
newTable
;
}

Allocate a table of the given capacity and set the threshold accordingly.

@param newCapacity must be a power of two

Allocate a table of the given capacity and set the threshold accordingly .


private SimpleHashSetEntry<T>[] doubleCapacity() {
        SimpleHashSetEntry<T>[] oldTable = mTable;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            return oldTable;
        }
        int newCapacity = oldCapacity * 2;
        SimpleHashSetEntry<T>[] newTable = makeTable(newCapacity);
        if (mSize == 0) {
            return newTable;
        }

        for (int j = 0; j < oldCapacity; j++) {
            /*
             * Rehash the bucket using the minimum number of field writes.
             * This is the most subtle and delicate code in the class.
             */
            SimpleHashSetEntry<T> e = oldTable[j];
            if (e == null) {
                continue;
            }
            int highBit = e.mHash & oldCapacity;
            SimpleHashSetEntry<T> broken = null;
            newTable[j | highBit] = e;
            for (SimpleHashSetEntry<T> n = e.mNext; n != null; e = n, n = n.mNext) {
                int nextHighBit = n.mHash & oldCapacity;
                if (nextHighBit != highBit) {
                    if (broken == null) {
                        newTable[j | nextHighBit] = n;
                    } else {
                        broken.mNext = n;
                    }
                    broken = e;
                    highBit = nextHighBit;
                }
            }
            if (broken != null)
                broken.mNext = null;
        }
        return newTable;
    }

Doubles the capacity of the hash table. Existing entries are placed in
the correct bucket on the enlarged table. If the current capacity is,
MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which
will be new unless we were already at MAXIMUM_CAPACITY.

Doubles the capacity of the hash table . Existing entries are placed in the correct bucket on the enlarged table . If the current capacity is MAXIMUM_CAPACITY this method is a no - op . Returns the table which will be new unless we were already at MAXIMUM_CAPACITY .


public void write(String key, Bitmap bitmap) {
        if (key == null || bitmap == null) {
            return;
        }

        // Add to disk cache
        OutputStream out = null;
        try {
            CacheEntry cacheEntry = mDiskCache.beginEdit(key);
            if (cacheEntry != null) {
                out = cacheEntry.newOutputStream();
                bitmap.compress(DEFAULT_COMPRESS_FORMAT, DEFAULT_COMPRESS_QUALITY, out);
                cacheEntry.commit();
                out.close();
            }
        } catch (final IOException e) {
            CLog.e(LOG_TAG, "addBitmapToCache - " + e);
        } catch (Exception e) {
            CLog.e(LOG_TAG, "addBitmapToCache - " + e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
            }
        }
    }

public
void
write
(
String
key
,
Bitmap
bitmap
)
{
if
(
key
==
||
bitmap
==
)
{
return
;
}
// Add to disk cache
OutputStream
out
=
;
try
{
CacheEntry
cacheEntry
=
mDiskCache
.
beginEdit
(
key
)
;
if
(
cacheEntry
!=
)
{
out
=
cacheEntry
.
newOutputStream
(
)
;
bitmap
.
compress
(
DEFAULT_COMPRESS_FORMAT
,
DEFAULT_COMPRESS_QUALITY
,
out
)
;
cacheEntry
.
commit
(
)
;
out
.
close
(
)
;
}
}
catch
(
final
IOException
e
)
{
CLog
.
e
(
LOG_TAG
,
"addBitmapToCache - "
+
e
)
;
}
catch
(
Exception
e
)
{
CLog
.
e
(
LOG_TAG
,
"addBitmapToCache - "
+
e
)
;
}
finally
{
try
{
if
(
out
!=
)
{
out
.
close
(
)
;
}
}
catch
(
IOException
e
)
{
}
}
}

Adds a bitmap to both memory and disk cache

@param key    Unique identifier for the bitmap to store
@param bitmap The bitmap to store


public String getString() throws IOException {
        InputStream in = getInputStream();
        return in != null ? inputStreamToString(in) : null;
    }

public String getString ( ) throws IOException { InputStream in = getInputStream ( ) ; return in != null ? inputStreamToString ( in ) : null ; }

Returns the last committed value as a string, or null if no value
has been committed.

Returns the last committed value as a string or null if no value has been committed .


public CacheEntry setString(String value) throws IOException {
        Writer writer = null;
        try {
            writer = new OutputStreamWriter(newOutputStream(), UTF_8);
            writer.write(value);
        } finally {
            FileUtils.closeQuietly(writer);
        }
        return this;
    }

public CacheEntry setString ( String value ) throws IOException { Writer writer = null ; try { writer = new OutputStreamWriter ( newOutputStream ( ) , UTF_8 ) ; writer . write ( value ) ; } finally { FileUtils . closeQuietly ( writer ) ; } return this ; }


public boolean delete() throws IOException {
        if (mIsUnderEdit) {
            throw new IOException("Try to delete an cache entry that has been being editing.");
        }
        FileUtils.deleteIfExists(getCacheFile());
        FileUtils.deleteIfExists(getTempFile());
        return true;
    }


public void commit() throws IOException {
        if (!mIsUnderEdit) {
            throw new IOException("CacheEntry has been closed.");
        }
        if (hasErrors) {
            mDiskCache.delete(mKey);
        } else {
            File dirty = getTempFile();
            if (dirty.exists()) {
                File clean = getCacheFile();
                dirty.renameTo(clean);
                mOldSize = mSize;
                mSize = clean.length();
                mDiskCache.commitEdit(this);
            } else {
                abortEdit();
            }
        }
        mIsUnderEdit = false;
    }

public
void
commit
(
)
throws
IOException
{
if
(
!
mIsUnderEdit
)
{
throw
new
IOException
(
"CacheEntry has been closed."
)
;
}
if
(
hasErrors
)
{
mDiskCache
.
delete
(
mKey
)
;
}
else
{
File
dirty
=
getTempFile
(
)
;
if
(
dirty
.
exists
(
)
)
{
File
clean
=
getCacheFile
(
)
;
dirty
.
renameTo
(
clean
)
;
mOldSize
=
mSize
;
mSize
=
clean
.
length
(
)
;
mDiskCache
.
commitEdit
(
this
)
;
}
else
{
abortEdit
(
)
;
}
}
mIsUnderEdit
=
false
;
}

Commits this edit so it is visible to readers.  This releases the
edit lock so another edit may be started on the same key.

Commits this edit so it is visible to readers . This releases the edit lock so another edit may be started on the same key .


@SuppressWarnings({"unused"})
    public RequestData addFile(String fieldName, String uploadFile, String fileName) {
        addFile(fieldName, new File(uploadFile), fileName);
        return this;
    }

@ SuppressWarnings ( { "unused" } ) public RequestData addFile ( String fieldName , String uploadFile , String fileName ) { addFile ( fieldName , new File ( uploadFile ) , fileName ) ; return this ; }

add file to be uploaded

@param fieldName
@param uploadFile
@param fileName   if provided, will use this as filename
@return


@Override
    public void clear() {
        if (mMemoryCache != null) {
            mMemoryCache.evictAll();
            if (DEBUG) {
                Log.d(LOG_TAG, "Memory cache cleared");
            }
        }
    }

@
Override
public
void
clear
(
)
{
if
(
mMemoryCache
!=
)
{
mMemoryCache
.
evictAll
(
)
;
if
(
DEBUG
)
{
Log
.
d
(
LOG_TAG
,
"Memory cache cleared"
)
;
}
}
}


public void tryToResume() throws IOException {
        if (mJournalFile.exists()) {
            try {
                readJournal();
                processJournal();
                mJournalWriter = new BufferedWriter(new FileWriter(mJournalFile, true),
                        IO_BUFFER_SIZE);
                if (SimpleDiskLruCache.DEBUG) {
                    CLog.d(SimpleDiskLruCache.LOG_TAG, "open success");
                }
            } catch (IOException journalIsCorrupt) {
                journalIsCorrupt.printStackTrace();
                if (SimpleDiskLruCache.DEBUG) {
                    CLog.d(SimpleDiskLruCache.LOG_TAG, "clear old cache");
                }
                clear();
            }
        } else {

            if (SimpleDiskLruCache.DEBUG) {
                CLog.d(SimpleDiskLruCache.LOG_TAG, "create new cache");
            }

            // create a new empty cache
            if (mDirectory.exists()) {
                mDirectory.delete();
            }
            mDirectory.mkdirs();
            rebuildJournal();
        }
    }

public
void
tryToResume
(
)
throws
IOException
{
if
(
mJournalFile
.
exists
(
)
)
{
try
{
readJournal
(
)
;
processJournal
(
)
;
mJournalWriter
=
new
BufferedWriter
(
new
FileWriter
(
mJournalFile
,
true
)
,
IO_BUFFER_SIZE
)
;
if
(
SimpleDiskLruCache
.
DEBUG
)
{
CLog
.
d
(
SimpleDiskLruCache
.
LOG_TAG
,
"open success"
)
;
}
}
catch
(
IOException
journalIsCorrupt
)
{
journalIsCorrupt
.
printStackTrace
(
)
;
if
(
SimpleDiskLruCache
.
DEBUG
)
{
CLog
.
d
(
SimpleDiskLruCache
.
LOG_TAG
,
"clear old cache"
)
;
}
clear
(
)
;
}
}
else
{
if
(
SimpleDiskLruCache
.
DEBUG
)
{
CLog
.
d
(
SimpleDiskLruCache
.
LOG_TAG
,
"create new cache"
)
;
}
// create a new empty cache
if
(
mDirectory
.
exists
(
)
)
{
mDirectory
.
delete
(
)
;
}
mDirectory
.
mkdirs
(
)
;
rebuildJournal
(
)
;
}
}

try to resume last status when we got off

@throws java.io.IOException


private void processJournal() throws IOException {
        FileUtils.deleteIfExists(mJournalFileTmp);
        for (Iterator<CacheEntry> i = mLruEntries.values().iterator(); i.hasNext(); ) {
            CacheEntry cacheEntry = i.next();
            if (!cacheEntry.isUnderEdit()) {
                mSize += cacheEntry.getSize();
            } else {
                cacheEntry.delete();
                i.remove();
            }
        }
    }

private void processJournal ( ) throws IOException { FileUtils . deleteIfExists ( mJournalFileTmp ) ; for ( Iterator < CacheEntry > i = mLruEntries . values ( ) . iterator ( ) ; i . hasNext ( ) ; ) { CacheEntry cacheEntry = i . next ( ) ; if ( ! cacheEntry . isUnderEdit ( ) ) { mSize += cacheEntry . getSize ( ) ; } else { cacheEntry . delete ( ) ; i . remove ( ) ; } } }

Computes the initial size and collects garbage as a part of opening the
cache. Dirty entries are assumed to be inconsistent and will be deleted.

Computes the initial size and collects garbage as a part of opening the cache . Dirty entries are assumed to be inconsistent and will be deleted .


private void rebuildJournal() throws IOException {
        if (mJournalWriter != null) {
            mJournalWriter.close();
        }

        Writer writer = new BufferedWriter(new FileWriter(mJournalFileTmp), IO_BUFFER_SIZE);
        writer.write(MAGIC);
        writer.write("\n");
        writer.write(VERSION_1);
        writer.write("\n");
        writer.write(Integer.toString(mAppVersion));
        writer.write("\n");
        writer.write("\n");

        for (CacheEntry cacheEntry : mLruEntries.values()) {
            if (cacheEntry.isUnderEdit()) {
                writer.write(sACTION_LIST[ACTION_DIRTY] + ' ' + cacheEntry.getKey() + " " + cacheEntry.getSize() + '\n');
            } else {
                writer.write(sACTION_LIST[ACTION_CLEAN] + ' ' + cacheEntry.getKey() + " " + cacheEntry.getSize() + '\n');
            }
        }

        writer.close();
        mJournalFileTmp.renameTo(mJournalFile);
        mJournalWriter = new BufferedWriter(new FileWriter(mJournalFile, true), IO_BUFFER_SIZE);
    }

private
void
rebuildJournal
(
)
throws
IOException
{
if
(
mJournalWriter
!=
)
{
mJournalWriter
.
close
(
)
;
}
Writer
writer
=
new
BufferedWriter
(
new
FileWriter
(
mJournalFileTmp
)
,
IO_BUFFER_SIZE
)
;
writer
.
write
(
MAGIC
)
;
writer
.
write
(
"\n"
)
;
writer
.
write
(
VERSION_1
)
;
writer
.
write
(
"\n"
)
;
writer
.
write
(
Integer
.
toString
(
mAppVersion
)
)
;
writer
.
write
(
"\n"
)
;
writer
.
write
(
"\n"
)
;
for
(
CacheEntry
cacheEntry
:
mLruEntries
.
values
(
)
)
{
if
(
cacheEntry
.
isUnderEdit
(
)
)
{
writer
.
write
(
sACTION_LIST
[
ACTION_DIRTY
]
+
'
'
+
cacheEntry
.
getKey
(
)
+
" "
+
cacheEntry
.
getSize
(
)
+
'
'
)
;
}
else
{
writer
.
write
(
sACTION_LIST
[
ACTION_CLEAN
]
+
'
'
+
cacheEntry
.
getKey
(
)
+
" "
+
cacheEntry
.
getSize
(
)
+
'
'
)
;
}
}
writer
.
close
(
)
;
mJournalFileTmp
.
renameTo
(
mJournalFile
)
;
mJournalWriter
=
new
BufferedWriter
(
new
FileWriter
(
mJournalFile
,
true
)
,
IO_BUFFER_SIZE
)
;
}

Creates a new journal that omits redundant information. This replaces the
current journal if it exists.

Creates a new journal that omits redundant information . This replaces the current journal if it exists .


private synchronized void trimToSize() {

        if (mSize > mCapacity) {
            if (SimpleDiskLruCache.DEBUG) {
                CLog.d(SimpleDiskLruCache.LOG_TAG, "should trim, current is: %s", mSize);
            }
        }
        while (mSize > mCapacity) {
            Map.Entry<String, CacheEntry> toEvict = mLruEntries.entrySet().iterator().next();
            String key = toEvict.getKey();
            CacheEntry cacheEntry = toEvict.getValue();
            mLruEntries.remove(key);

            mSize -= cacheEntry.getSize();
            addActionLog(ACTION_PENDING_DELETE, cacheEntry);
            if (SimpleDiskLruCache.DEBUG) {
                CLog.d(SimpleDiskLruCache.LOG_TAG, "pending remove: %s, size: %s, after remove total: %s", key, cacheEntry.getSize(), mSize);
            }
        }
    }


@Override
    public void onBackPressed() {

        // process back for fragment
        if (processBackPressed()) {
            return;
        }

        // process back for fragment
        boolean enableBackPressed = true;
        if (mCurrentFragment != null) {
            enableBackPressed = !mCurrentFragment.processBackPressed();
        }
        if (enableBackPressed) {
            int cnt = getSupportFragmentManager().getBackStackEntryCount();
            if (cnt <= 1 && isTaskRoot()) {
                String closeWarningHint = getCloseWarning();
                if (!mCloseWarned && !TextUtils.isEmpty(closeWarningHint)) {
                    Toast toast = Toast.makeText(this, closeWarningHint, Toast.LENGTH_SHORT);
                    toast.show();
                    mCloseWarned = true;
                } else {
                    doReturnBack();
                }
            } else {
                mCloseWarned = false;
                doReturnBack();
            }
        }
    }

@
Override
public
void
onBackPressed
(
)
{
// process back for fragment
if
(
processBackPressed
(
)
)
{
return
;
}
// process back for fragment
boolean
enableBackPressed
=
true
;
if
(
mCurrentFragment
!=
)
{
enableBackPressed
=
!
mCurrentFragment
.
processBackPressed
(
)
;
}
if
(
enableBackPressed
)
{
int
cnt
=
getSupportFragmentManager
(
)
.
getBackStackEntryCount
(
)
;
if
(
cnt
<=
1
&&
isTaskRoot
(
)
)
{
String
closeWarningHint
=
getCloseWarning
(
)
;
if
(
!
mCloseWarned
&&
!
TextUtils
.
isEmpty
(
closeWarningHint
)
)
{
Toast
toast
=
Toast
.
makeText
(
this
,
closeWarningHint
,
Toast
.
LENGTH_SHORT
)
;
toast
.
show
(
)
;
mCloseWarned
=
true
;
}
else
{
doReturnBack
(
)
;
}
}
else
{
mCloseWarned
=
false
;
doReturnBack
(
)
;
}
}
}


@Override
    public void loadMoreFinish(boolean emptyResult, boolean hasMore) {
        mLoadError = false;
        mListEmpty = emptyResult;
        mIsLoading = false;
        mHasMore = hasMore;

        if (mLoadMoreUIHandler != null) {
            mLoadMoreUIHandler.onLoadFinish(this, emptyResult, hasMore);
        }
    }

@ Override public void loadMoreFinish ( boolean emptyResult , boolean hasMore ) { mLoadError = false ; mListEmpty = emptyResult ; mIsLoading = false ; mHasMore = hasMore ; if ( mLoadMoreUIHandler != null ) { mLoadMoreUIHandler . onLoadFinish ( this , emptyResult , hasMore ) ; } }

page has loaded

@param emptyResult
@param hasMore


public ImageReuseInfo create(String thisSize) {
        ArrayList<String> list = new ArrayList<String>();
        boolean canBeReused = false;
        for (int i = 0; i < mSizeList.length; i++) {
            String size = mSizeList[i];

            if (!canBeReused && thisSize.equals(size)) {
                canBeReused = true;
                continue;
            }
            if (canBeReused && !thisSize.equals(size)) {
                list.add(size);
            }
        }
        if (list.size() == 0) {
            return new ImageReuseInfo(thisSize, null);
        } else {
            String[] sizeList = new String[list.size()];
            list.toArray(sizeList);
            return new ImageReuseInfo(thisSize, sizeList);
        }
    }

public ImageReuseInfo create ( String thisSize ) { ArrayList < String > list = new ArrayList < String > ( ) ; boolean canBeReused = false ; for ( int i = 0 ; i < mSizeList . length ; i ++ ) { String size = mSizeList [ i ] ; if ( ! canBeReused && thisSize . equals ( size ) ) { canBeReused = true ; continue ; } if ( canBeReused && ! thisSize . equals ( size ) ) { list . add ( size ) ; } } if ( list . size ( ) == 0 ) { return new ImageReuseInfo ( thisSize , null ) ; } else { String [ ] sizeList = new String [ list . size ( ) ] ; list . toArray ( sizeList ) ; return new ImageReuseInfo ( thisSize , sizeList ) ; } }

Find out the size list can be re-sued.

@param thisSize if "small_180" is input
@return {"big_360", "big_720"} will be returned.

Find out the size list can be re - sued .


@Override
    protected T doRequestSync() {
        T data = RequestCacheManager.getInstance().requestCacheSync(this);
        if (data == null) {
            data = RequestManager.getInstance().getRequestProxy(this).requestSync(this);
        }
        return data;
    }

@ Override protected T doRequestSync ( ) { T data = RequestCacheManager . getInstance ( ) . requestCacheSync ( this ) ; if ( data == null ) { data = RequestManager . getInstance ( ) . getRequestProxy ( this ) . requestSync ( this ) ; } return data ; }

Timeout will not be considerate

@return