/** * Copyright 2012 Neurowork Consulting S.L. * * This file is part of eMobc. * * LevelActivityGenerator.java * eMobc Android Framework * * eMobc is free software: you can redistribute it and/or modify * it under the terms of the Affero GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * eMobc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public License * along with eMobc. If not, see <http://www.gnu.org/licenses/>. * */ package com.emobc.android.activities.generators; import java.util.Map; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.TextView; import com.emobc.android.ActivityType; import com.emobc.android.ApplicationData; import com.emobc.android.NextLevel; import com.emobc.android.activities.R; import com.emobc.android.levels.AppLevel; import com.emobc.android.levels.AppLevelData; import com.emobc.android.themes.ActivityTypeStyle; import com.emobc.android.themes.FormatStyle; import com.emobc.android.themes.LevelStyle; import com.emobc.android.themes.Style; import com.emobc.android.utils.ImagesUtils; import com.emobc.android.utils.InvalidFileException; import com.emobc.android.utils.Utils; /** * Abstract class that implements all the methods necessary for the proper * start of the screens, focusing primarily on the current "level". * * @author Jonatan Alcocer Luna * @author Jorge E. Villaverde * @version 0.1 * @since 0.1 */ public abstract class LevelActivityGenerator extends AbstractActivtyGenerator { private static final String TAG = "LevelActivityGenerator"; /** * */ private static final long serialVersionUID = 6029596069752642543L; protected AppLevel appLevel; protected NextLevel nextLevel; public LevelActivityGenerator(AppLevel appLevel, NextLevel nextLevel) { super(); this.appLevel = appLevel; this.nextLevel = nextLevel; } public AppLevel getAppLevel() { return appLevel; } public void setAppLevel(AppLevel appLevel) { this.appLevel = appLevel; } @Override protected void intializeSubActivity(Activity activity) { AppLevelData data = appLevel.getData(activity); if(data == null){ showInvalidDataAlerDialog(activity); }else{ initializeScreen(activity, getActivityGeneratorType()); loadAppLevelData(activity, data); } } protected void showInvalidDataAlerDialog(final Activity activity) { final AlertDialog.Builder dlg = new AlertDialog.Builder(activity); dlg.setTitle(R.string.err_level_data_title); dlg.setMessage(R.string.err_level_data_alert); dlg.setNeutralButton("Ok", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { activity.onBackPressed(); } }); dlg.show(); } /** * Initializes the background, and all components formats for an activity type * @param activity * @param activityType * @param params */ protected void initializeScreen(Activity activity, ActivityType activityType){ initializeScreen(activity, activityType, nextLevel); } public static void initializeScreen(Activity activity, ActivityType activityType, NextLevel nextLevel){ ApplicationData applicationData = AbstractActivtyGenerator.getApplicationData(activity); ActivityTypeStyle activityTypeStyle = applicationData.getActivityTypeStyle(activityType); LevelStyle levelStyle = null; if(nextLevel != null && nextLevel.isDefined()) levelStyle = applicationData.getLevelStyle(nextLevel.getLevelId()); // Fist try to apply ActivityType Style if(activityTypeStyle != null && !activityTypeStyle.isCleanFormat()){ initializeScreenWithFormat(activity, activityTypeStyle); } // Then try to apply Level Stype if(levelStyle != null && !levelStyle.isCleanFormat()){ initializeScreenWithFormat(activity, levelStyle); } } /** * Initialize the specific background for a level * @param activity * @param activityType */ public static void initializeBackground(Activity activity, Style style){ if(activity == null || style == null) return; String backgroundFileName = style.getBackground(); if(Utils.hasLength(backgroundFileName)){ ViewGroup backgroundLayout = (ViewGroup)activity.findViewById(R.id.backgroundLayout); if(backgroundLayout == null) return; Drawable backgroundDrawable; try { backgroundDrawable = ImagesUtils.getDrawable(activity, backgroundFileName); backgroundLayout.setBackgroundDrawable(backgroundDrawable); } catch (InvalidFileException e) { Log.e(TAG, e.getLocalizedMessage()); } } } /** * Initializes the background, and all components formats for an specific level * @param activity * @param levelTypeStyle */ public static void initializeScreenWithFormat(Activity activity, Style style){ initializeBackground(activity, style); initializeWidgetFormat(activity, style); } /** * Initialize the widget's components (textColor, textSize, textStyle, typeFace) * with the XML content, depending on a specific screen type. * @param activity * @param typeScreen * @param currWidget */ public static void initializeWidgetFormat(Activity activity, Style levelStyle){ Map<String, FormatStyle> formatStyleMap = AbstractActivtyGenerator.getApplicationData(activity).getFormatStyleMap(activity); if(levelStyle == null) return; if(levelStyle.getListComponents() == null) return; for(String currWidget : levelStyle.getListComponents()){ FormatStyle currFormat = getCurrentFormatWidget(levelStyle, currWidget, activity); if(currFormat == null) currFormat = formatStyleMap.get("default"); try{ int resID = activity.getResources().getIdentifier(currWidget, "id", activity.getPackageName()); TextView v = (TextView) activity.findViewById(resID); if(v == null) continue; if(Utils.hasLength(currFormat.getTextColor())) v.setTextColor(Color.parseColor(currFormat.getTextColor())); String complexSize = currFormat.getTextSize(); if(Utils.hasLength(complexSize)){ int sep = getSeparation(0, complexSize); String unitStr = complexSize.substring(sep); int size = Integer.parseInt(complexSize.substring(0, sep)); int unit; if(unitStr.equals("sp")){ unit = TypedValue.COMPLEX_UNIT_SP; }else if(unitStr.equals("dip")){ unit = TypedValue.COMPLEX_UNIT_DIP; }else if(unitStr.equals("px")){ unit = TypedValue.COMPLEX_UNIT_PX; }else//default unit = TypedValue.COMPLEX_UNIT_SP; v.setTextSize(unit, size); } String complexStyle = currFormat.getTextStyle(); if(Utils.hasLength(complexStyle)){ int style; if(complexStyle.equals("normal")){ style = Typeface.NORMAL; }else if(complexStyle.equals("bold")){ style = Typeface.BOLD; }else if(complexStyle.equals("italic")){ style = Typeface.ITALIC; }else//default style = Typeface.NORMAL; String type = currFormat.getTypeFace(); if(Utils.hasLength(type)){ Typeface tf; //Try create a typeface with the type and the style. //If it can't, it uses the specific font in assets/fonts try{ Typeface tfAux = Typeface.createFromAsset(activity.getApplicationContext().getAssets(), "fonts/"+type+".ttf"); tf = Typeface.create(tfAux, style); v.setTypeface(tf); }catch(Exception e){ Log.e(TAG, "Impossible to apply any typeface: " + e.getMessage()); } } } }catch(Exception e){ Log.e(TAG,"Impossible to apply the format: " + e.getMessage()); }//END Try-catch }//END While } /** * Returns the format to associated with activity type and a widget * @param activityType * @param currWidget * @return */ private static FormatStyle getCurrentFormatWidget(Style style, String currWidget, Activity activity){ Map<String, FormatStyle> formatStyleMap = AbstractActivtyGenerator.getApplicationData(activity).getFormatStyleMap(activity); Map<String,String> mapFormatComponents = style.getMapFormatComponents(); String formatName = mapFormatComponents.get(currWidget); return formatStyleMap.get(formatName); } /** * Initialize the list's components (textColor, textSize, textStyle, typeFace, cacheColorHint) * with the XML content. * @param activity * @param textView * @param fs */ private void initializeSelectionFormat(Activity activity, View view, FormatStyle fs){ try{ ListView list = (ListView) activity.findViewById(R.id.list); TextView textView = (TextView)view.findViewById(R.id.list_item_text); if(Utils.hasLength(fs.getCacheColorHint())) list.setCacheColorHint(Color.parseColor(fs.getCacheColorHint())); if(Utils.hasLength(fs.getBackgroundColor())) list.setBackgroundColor(Color.parseColor(fs.getBackgroundColor())); if(Utils.hasLength(fs.getTextColor())) textView.setTextColor(Color.parseColor(fs.getTextColor())); String complexSize = fs.getTextSize(); if(Utils.hasLength(complexSize)){ int sep = getSeparation(0, complexSize); String unitStr = complexSize.substring(sep); int size = Integer.parseInt(complexSize.substring(0, sep)); int unit; if(unitStr.equals("sp")){ unit = TypedValue.COMPLEX_UNIT_SP; }else if(unitStr.equals("dip")){ unit = TypedValue.COMPLEX_UNIT_DIP; }else if(unitStr.equals("px")){ unit = TypedValue.COMPLEX_UNIT_PX; }else//default unit = TypedValue.COMPLEX_UNIT_SP; textView.setTextSize(unit, size); } String complexStyle = fs.getTextStyle(); if(Utils.hasLength(complexStyle)){ int style; if(complexStyle.equals("normal")){ style = Typeface.NORMAL; }else if(complexStyle.equals("bold")){ style = Typeface.BOLD; }else if(complexStyle.equals("italic")){ style = Typeface.ITALIC; }else//default style = Typeface.NORMAL; String type = fs.getTypeFace(); if(Utils.hasLength(type)){ Typeface tf; //Try create a typeface with the type and the style. //If it can't, it uses the specific font in assets/fonts try{ Typeface tfAux = Typeface.createFromAsset(activity.getApplicationContext().getAssets(), "fonts/"+type+".ttf"); tf = Typeface.create(tfAux, style); textView.setTypeface(tf); }catch(Exception e){ Log.e(TAG,"Impossible to apply any typeface: " + e.getMessage()); } } } }catch(Exception e){ Log.e(TAG,"Impossible to apply the format: " + e.getMessage()); } } /** * Initialize the list's format and background, with the XML content, * depending on a specific screen type. * @param activity * @param activityType * @param textView */ public void initializeListFormat(Activity activity, ActivityType activityType, View view){ Map<ActivityType, ActivityTypeStyle> activityTypeStyleTypeMap = AbstractActivtyGenerator.getApplicationData(activity).getActivityTypeStyleTypeMap(activity); Map<String, LevelStyle> levelStyleTypeMap = AbstractActivtyGenerator.getApplicationData(activity).getLevelStyleTypeMap(activity); Map<String, FormatStyle> formatStyleMap = AbstractActivtyGenerator.getApplicationData(activity).getFormatStyleMap(activity); ActivityTypeStyle activityTypeStyle = activityTypeStyleTypeMap.get(activityType); LevelStyle levelStyle = levelStyleTypeMap.get(nextLevel.getLevelId()); if(activityTypeStyle != null && !activityTypeStyle.isCleanFormat()){ applyStyle(activity, activityTypeStyle, formatStyleMap, view); } if(levelStyle != null && !levelStyle.isCleanFormat()){ applyStyle(activity, levelStyle, formatStyleMap, view); } } private void applyStyle(Activity activity, Style style, Map<String, FormatStyle> formatStyleMap, View view) { String listFormat = style.getSelectionList(); FormatStyle fs = formatStyleMap.get(listFormat); if(fs != null){ String backgroundSelectionFileName = fs.getBackgroundSelectionFileName(); String backgroundSelectionName = backgroundSelectionFileName.split("\\.")[0]; int imageResource = activity.getResources().getIdentifier(backgroundSelectionName, "drawable", activity.getPackageName()); Drawable backgroundSelectionDrawable = activity.getResources().getDrawable(imageResource); view.setBackgroundDrawable(backgroundSelectionDrawable); initializeSelectionFormat(activity, view, fs); } } /** * Recursive method witch returns the position between number and character * @param i * @param complexSize * @return */ private static int getSeparation(int i, String complexSize){ if(isNumeric(complexSize.charAt(i))){ i++; i = getSeparation(i, complexSize); } return i; } /** * Return true if character is a number, and false if it isn't * @param cadena * @return */ private static boolean isNumeric(char character){ try { Integer.parseInt(String.valueOf(character)); return true; } catch (NumberFormatException nfe){ return false; } } /** * Primary method of ActivityGenerator. It initializes all components * of the screen, depending on the type of activity to call him. * @param activity * @param data */ protected abstract void loadAppLevelData(final Activity activity, final AppLevelData data); /** * * @return Type of Activity that the generator implements */ protected abstract ActivityType getActivityGeneratorType(); }