/*
* Copyright (C) 2012 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.motorolamobility.preflighting.core.applicationdata;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/***
* This class is intended to be used to represent the resources folder (\res) of an application
*/
public class ResourcesFolderElement extends FolderElement
{
private static final String VALUES = "values";
private static final String STRINGS_XML = "strings.xml";
/**
* Represents the Android's Project "drawable" folder.
*/
public static final String DRAWABLE_FOLDER = "drawable";
/**
* Represents the Android's Project "drawable-ldpi" folder.
*/
public static final String LDPI_DRAWABLE_FOLDER = "drawable-ldpi";
/**
* Represents the Android's Project "drawable-mdpi" folder.
*/
public static final String MDPI_DRAWABLE_FOLDER = "drawable-mdpi";
/**
* Represents the Android's Project "drawable-hdpi" folder.
*/
public static final String HDPI_DRAWABLE_FOLDER = "drawable-hdpi";
/**
* Represents the Android's Project "drawable-xhdpi" folder.
*/
public static final String XHDPI_DRAWABLE_FOLDER = "drawable-xhdpi";
private List<Locale> localeList = null;
/***
* Class constructor that always call superclass constructor using type {@link Element.Type#FOLDER_RES}.
*
* @param name Folder File representing the folder.
* @param parent Parent element.
*/
public ResourcesFolderElement(File folder, Element parent)
{
super(folder, parent, Type.FOLDER_RES);
}
/* Drawable methods */
/***
* Gets all drawable folders found in a a application.
*
* @return A list of drawable folders.
*/
public List<FolderElement> getDrawableFolders()
{
List<FolderElement> list = new ArrayList<FolderElement>();
for (Element element : this.getChildren())
{
if (element.getType() == Element.Type.FOLDER_DRAWABLE)
{
if (element instanceof FolderElement)
{
list.add((FolderElement) element);
}
}
}
return list;
}
/**
* Gets the standard drawable folder
*
* @return Retruns the folder element that represents the standard drawable folder.
*/
public FolderElement getDrawableFolder()
{
return getDrawableFolder(ResourcesFolderElement.DRAWABLE_FOLDER);
}
/***
* Gets the low DPI drawable folder.
*
* @return Retruns the folder element that represents the low DPI drawable folder. Can be null.
*/
public FolderElement getLdpiDrawableFolder()
{
return getDrawableFolder(ResourcesFolderElement.LDPI_DRAWABLE_FOLDER);
}
/***
* Gets the medium DPI drawable folder.
*
* @return Returns the folder element that represents the medium DPI drawable folder. Can be null.
*/
public FolderElement getMdpiDrawableFolder()
{
return getDrawableFolder(ResourcesFolderElement.MDPI_DRAWABLE_FOLDER);
}
/***
* Gets the high DPI drawable folder.
*
* @return Returns the folder element that represents the high DPI drawable folder. Can be null.
*/
public FolderElement getHdpiDrawableFolder()
{
return getDrawableFolder(ResourcesFolderElement.HDPI_DRAWABLE_FOLDER);
}
/***
* Gets the extra high DPI drawable folder.
*
* @return Returns the folder element that represents the extra high DPI drawable folder. Can be null.
*/
public FolderElement getXhdpiDrawableFolder()
{
return getDrawableFolder(ResourcesFolderElement.XHDPI_DRAWABLE_FOLDER);
}
/***
* Gets an drawable folder.
*
* @param folderName Foler name which represents a drawable one.
*
* @return Returns the folder element.
*/
private FolderElement getDrawableFolder(String folderName)
{
FolderElement result = null;
for (FolderElement element : getDrawableFolders())
{
if (element.getName().equals(folderName))
{
result = element;
break;
}
}
return result;
}
/*Strings methods*/
/**
* Gets all values folders elements.
*
* @return Returns the folder element list.
*/
public List<FolderElement> getValuesFolders()
{
List<FolderElement> result = new ArrayList<FolderElement>();
for (Element element : getChildren())
{
if (element.getType().equals(Element.Type.FOLDER_VALUES))
{
if (element instanceof FolderElement)
{
result.add((FolderElement) element);
}
}
}
return result;
}
/**
* Gets all available Locales.
*
* @return Returns all available locales.
*/
public List<Locale> getAvailableLocales()
{
if (localeList == null)
{
localeList = new ArrayList<Locale>();
Locale locale;
for (FolderElement folder : getValuesFolders())
{
locale = getLocaleFromFolderName(folder.getName());
if ((locale != null) && !localeList.contains(locale))
{
localeList.add(locale);
}
}
}
return localeList;
}
/**
* Merge a list of string elements in a single one.
*
* @return Returns the merged String Elements.
*/
private StringsElement mergeStringsElements(List<StringsElement> list)
{
StringsElement stringsUnion = null;
if (list.size() > 0)
{
stringsUnion = new StringsElement(STRINGS_XML, null);
for (StringsElement element : list)
{
for (String key : element.getKeyList())
{
Object value = element.getValue(key);
boolean valid = value != null;
if (valid && (value instanceof String))
{
valid = ((String) value).length() > 0;
}
else if (valid && (value instanceof List))
{
valid = ((List) value).size() > 0;
}
if (!stringsUnion.containsKey(key) || (stringsUnion.containsKey(key) && !valid))
{
stringsUnion.addEntry(key, element.getValue(key));
}
}
}
}
return stringsUnion;
}
/**
* Gets the Strings Element for a a specific Locale.
*
* @param locale Specific {@link Locale}.
*
* @return Returns the specific Strings element.
*/
public StringsElement getValuesElement(Locale locale)
{
List<StringsElement> stringsElementsToMerge = new ArrayList<StringsElement>();
Locale localefromFolder;
for (FolderElement folder : getValuesFolders())
{
localefromFolder = getLocaleFromFolderName(folder.getName());
//Searching for default values
if (locale == null)
{
//Found default values
if (localefromFolder == null)
{
for (Element stringsElement : folder.getChildren())
{
if ((stringsElement.getType() == Element.Type.FILE_STRINGS))
{
stringsElementsToMerge.add((StringsElement) stringsElement);
}
}
}
}
//Searching for specific language
else
{
//Ignoring default values
if (localefromFolder != null)
{
if (localefromFolder.getLanguage().equals(locale.getLanguage())
&& localefromFolder.getCountry().equals(locale.getCountry()))
{
for (Element stringsElement : folder.getChildren())
{
if ((stringsElement.getType() == Element.Type.FILE_STRINGS))
{
stringsElementsToMerge.add((StringsElement) stringsElement);
}
}
}
}
}
}
return mergeStringsElements(stringsElementsToMerge);
}
/**
* Gets the default values element.
*
* @return Returns the default Strings set.
*/
public StringsElement getDefaultValuesElement()
{
return getValuesElement(null);
}
/***
* Extract a locale based on a folder name.
*
* @param folderName Folder name which the {@link Locale} will be based on.
*
* @return Returns the extracted {@link Locale}. Can be null.
*/
private static Locale getLocaleFromFolderName(String folderName)
{
Locale result = null;
folderName = folderName.replace(VALUES, "");
String[] segments = folderName.split("-");
String language = null;
String country = null;
List<String> isoLanguages = new ArrayList<String>();
for (String lang : Locale.getISOLanguages())
{
isoLanguages.add(lang);
}
List<String> isoContries = new ArrayList<String>();
for (String lang : Locale.getISOCountries())
{
isoContries.add(lang);
}
for (int i = 1; i < segments.length; i++)
{
if ((segments[i].length() == 2) && (language == null)
&& (isoLanguages.contains(segments[i])))
{
language = segments[i];
}
else if (segments[i].matches("r[A-Z]{2}") && (country == null)
&& (isoContries.contains(segments[i].substring(1))))
{
// Ignore 'r' character
country = segments[i].substring(1);
}
}
if (language != null)
{
if (country != null)
{
result = new Locale(language, country);
}
else
{
result = new Locale(language);
}
}
return result;
}
/**
* Clean the {@link Locale} list.
*/
@Override
public void clean()
{
super.clean();
this.localeList = null;
}
}