/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdklib.internal.export;
import com.android.sdklib.xml.ManifestData;
import java.util.HashMap;
import java.util.Map;
/**
* Class representing one apk (or more if there are soft variants) that needs to be generated.
* This contains a link to the project used for the export, and which extra filters should be used.
*
* This class is meant to be sortable in a way that allows generation of the buildInfo
* value that goes in the composite versionCode.
*/
public final class ApkData implements Comparable<ApkData> {
private static final String PROP_PROJECT = "project";
private static final String PROP_BUILDINFO = "buildInfo";
private static final String PROP_MINOR = "minorCode";
private static final String PROP_ABI = "abi";
private static final String PROP_RESOURCES = "resources";
/**
* List of ABI order.
* This is meant to be a list of CPU/CPU2 to indicate the order required by the build info.
* If the ABIs being compared in {@link #compareTo(ApkData)} are in the same String array,
* then the value returned must ensure that the {@link ApkData} will ordered the same as the
* array.
* If the ABIs are not in the same array, any order can be returned.
*/
private static final String[][] ABI_SORTING = new String[][] {
new String[] { "armeabi", "armeabi-v7a" }
};
private final ProjectConfig mProjectConfig;
private final HashMap<String, String> mOutputNames = new HashMap<String, String>();
private int mBuildInfo;
private int mMinorCode;
// the following are used to sort the export data and generate buildInfo
private final String mAbi;
private final Map<String, String> mSoftVariantMap = new HashMap<String, String>();
ApkData(ProjectConfig projectConfig, String abi, Map<String, String> softVariants) {
mProjectConfig = projectConfig;
mAbi = abi;
if (softVariants != null) {
mSoftVariantMap.putAll(softVariants);
}
}
ApkData(ProjectConfig projectConfig, String abi) {
this(projectConfig, abi, null /*softVariants*/);
}
ApkData(ProjectConfig projectConfig, Map<String, String> softVariants) {
this(projectConfig, null /*abi*/, softVariants);
}
ApkData(ProjectConfig projectConfig) {
this(projectConfig, null /*abi*/, null /*softVariants*/);
}
public ProjectConfig getProjectConfig() {
return mProjectConfig;
}
public String getOutputName(String key) {
return mOutputNames.get(key);
}
public void setOutputName(String key, String outputName) {
mOutputNames.put(key, outputName);
}
public int getBuildInfo() {
return mBuildInfo;
}
void setBuildInfo(int buildInfo) {
mBuildInfo = buildInfo;
}
public int getMinorCode() {
return mMinorCode;
}
void setMinorCode(int minor) {
mMinorCode = minor;
}
public String getAbi() {
return mAbi;
}
public Map<String, String> getSoftVariantMap() {
return mSoftVariantMap;
}
/**
* Computes and returns the composite version code
* @param versionCode the major version code.
* @return the composite versionCode to be used in the manifest.
*/
public int getCompositeVersionCode(int versionCode) {
int trueVersionCode = versionCode * MultiApkExportHelper.OFFSET_VERSION_CODE;
trueVersionCode += getBuildInfo() * MultiApkExportHelper.OFFSET_BUILD_INFO;
trueVersionCode += getMinorCode();
return trueVersionCode;
}
@Override
public String toString() {
return getLogLine(null);
}
public String getLogLine(String key) {
StringBuilder sb = new StringBuilder();
sb.append(getOutputName(key)).append(':');
LogHelper.write(sb, PROP_BUILDINFO, mBuildInfo);
LogHelper.write(sb, PROP_MINOR, mMinorCode);
LogHelper.write(sb, PROP_PROJECT, mProjectConfig.getRelativePath());
sb.append(mProjectConfig.getConfigString(true /*onlyManifestData*/));
if (mAbi != null) {
LogHelper.write(sb, PROP_ABI, mAbi);
}
String filter = mSoftVariantMap.get(key);
if (filter != null) {
LogHelper.write(sb, PROP_RESOURCES, filter);
}
return sb.toString();
}
public int compareTo(ApkData o) {
// compare only the hard properties, and in a specific order:
// 1. minSdkVersion
int minSdkDiff = mProjectConfig.getMinSdkVersion() - o.mProjectConfig.getMinSdkVersion();
if (minSdkDiff != 0) {
return minSdkDiff;
}
// 2. <supports-screens>
// only compare if they have don't have the same size support. This is because
// this compare method throws an exception if the values cannot be compared.
if (mProjectConfig.getSupportsScreens().hasSameScreenSupportAs(
o.mProjectConfig.getSupportsScreens()) == false) {
return mProjectConfig.getSupportsScreens().compareScreenSizesWith(
o.mProjectConfig.getSupportsScreens());
}
// 3. glEsVersion
int comp;
if (mProjectConfig.getGlEsVersion() != ManifestData.GL_ES_VERSION_NOT_SET) {
if (o.mProjectConfig.getGlEsVersion() != ManifestData.GL_ES_VERSION_NOT_SET) {
comp = mProjectConfig.getGlEsVersion() - o.mProjectConfig.getGlEsVersion();
if (comp != 0) return comp;
} else {
return -1;
}
} else if (o.mProjectConfig.getGlEsVersion() != ManifestData.GL_ES_VERSION_NOT_SET) {
return 1;
}
// 4. ABI
// here the returned value is only important if both abi are non null.
if (mAbi != null && o.mAbi != null) {
comp = compareAbi(mAbi, o.mAbi);
if (comp != 0) return comp;
}
return 0;
}
private int compareAbi(String abi, String abi2) {
// look for the abis in each of the ABI sorting array
for (String[] abiArray : ABI_SORTING) {
int abiIndex = -1, abiIndex2 = -1;
final int count = abiArray.length;
for (int i = 0 ; i < count ; i++) {
if (abiArray[i].equals(abi)) {
abiIndex = i;
}
if (abiArray[i].equals(abi2)) {
abiIndex2 = i;
}
}
// if both were found
if (abiIndex != -1 && abiIndex != -1) {
return abiIndex - abiIndex2;
}
}
return 0;
}
}