/* * Copyright (C) 2012 The CyanogenMod 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.cyanogenmod.filemanager.ui; import android.app.ActionBar; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.preferences.FileManagerSettings; import java.util.ArrayList; import java.util.List; /** * A class that manage the use of themes inside the application. */ public final class ThemeManager { private static final String TAG = "ThemeManager"; //$NON-NLS-1$ private static boolean DEBUG = false; /** * The permission that MUST have the activity that holds the themes */ public static final String PERMISSION_READ_THEME = "com.cyanogenmod.filemanager.permissions.READ_THEME"; //$NON-NLS-1$ /** * The action that MUST have all app that want to register as a theme for this app */ public static final String ACTION_MAIN_THEME = "com.cyanogenmod.filemanager.actions.MAIN_THEME"; //$NON-NLS-1$ /** * The category that MUST have all app that want to register as a theme for this app */ public static final String CATEGORY_THEME = "com.cyanogenmod.filemanager.categories.THEME"; //$NON-NLS-1$ private static final String RESOURCE_THEMES_IDS = "themes_ids"; //$NON-NLS-1$ private static final String RESOURCE_THEMES_NAMES = "themes_names"; //$NON-NLS-1$ private static final String RESOURCE_THEMES_DESCRIPTIONS = "themes_descriptions"; //$NON-NLS-1$ private static final String RESOURCE_THEMES_AUTHOR = "themes_author"; //$NON-NLS-1$ /** * @hide */ static Theme mDefaultTheme; private static Theme mCurrentTheme; /** * Method that returns the current theme * * @param ctx The current context * @return Theme The current theme */ public static synchronized Theme getCurrentTheme(Context ctx) { if (mCurrentTheme == null) { // Use the default theme mCurrentTheme = getDefaultTheme(ctx); } return mCurrentTheme; } /** * Method that returns the default theme * * @param ctx The current context * @return Theme The default theme */ public static synchronized Theme getDefaultTheme(Context ctx) { if (mDefaultTheme == null) { // Use the default theme mDefaultTheme = new Theme(); String themeSettings = (String)FileManagerSettings.SETTINGS_THEME.getDefaultValue(); mDefaultTheme.mPackage = themeSettings.substring(0, themeSettings.indexOf(":")); //$NON-NLS-1$ mDefaultTheme.mId = themeSettings.substring(themeSettings.indexOf(":") + 1); //$NON-NLS-1$ mDefaultTheme.mName = ctx.getString(R.string.theme_default_name); mDefaultTheme.mDescription = ctx.getString(R.string.theme_default_description); mDefaultTheme.mAuthor = ctx.getString(R.string.themes_author); mDefaultTheme.mContext = ctx; mDefaultTheme.mResources = ctx.getResources(); } return mDefaultTheme; } /** * A method for set the current theme that should be applied to the UI. * * @param ctx The current context (of this application) * @param theme The theme of the app (package:id) * @return boolean If the theme was set */ public static synchronized boolean setCurrentTheme(Context ctx, String theme) { // Retrieve the available themes List<Theme> themes = getAvailableThemes(ctx); String themePackage = theme.substring(0, theme.indexOf(":")); //$NON-NLS-1$ String themeId = theme.substring(theme.indexOf(":") + 1); //$NON-NLS-1$ int cc = themes.size(); for (int i = 0; i < cc; i++) { Theme t = themes.get(i); if (t.mPackage.compareTo(themePackage) == 0 && t.mId.compareTo(themeId) == 0) { // We have the theme. Save it and notify mCurrentTheme = t; Intent intent = new Intent(FileManagerSettings.INTENT_THEME_CHANGED); intent.putExtra(FileManagerSettings.EXTRA_THEME_PACKAGE, t.mPackage); intent.putExtra(FileManagerSettings.EXTRA_THEME_ID, t.mId); ctx.sendBroadcast(intent); return true; } } // Not found return false; } /** * Method that returns the list of available themes for the file manager app. * * @param ctx The current context * @return List<Theme> List of themes */ public static List<Theme> getAvailableThemes(Context ctx) { Intent intent = new Intent(ACTION_MAIN_THEME); intent.addCategory(CATEGORY_THEME); if (DEBUG) { intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); } // Obtain the list of packages that matches with theme requirements for register as // a file manager theme PackageManager pm = ctx.getPackageManager(); List<ResolveInfo> result = pm.queryIntentActivities(intent, 0); // Read now the information about the themes List<Theme> themes = new ArrayList<Theme>(); int cc = result.size(); for (int i = 0; i < cc; i++) { try { ResolveInfo info = result.get(i); String appPackage = info.activityInfo.packageName; // Check permission for read theme String appPermission = info.activityInfo.permission; if (appPermission == null || appPermission.compareTo(PERMISSION_READ_THEME) != 0) { Log.w(TAG, String.format( "\"%s\" hasn't READ_THEME permission. Ignored.", //$NON-NLS-1$ appPackage)); continue; } Resources appResources = pm.getResourcesForApplication(appPackage); if (appResources != null) { // We need the ids, names, descriptions and author of every // theme in the application //- Identifiers int identifiers = appResources.getIdentifier( RESOURCE_THEMES_IDS, "array", //$NON-NLS-1$ appPackage); if (identifiers == 0) continue; String[] ids = appResources.getStringArray(identifiers); //- Name int namesId = appResources.getIdentifier( RESOURCE_THEMES_NAMES, "array", //$NON-NLS-1$ appPackage); if (namesId == 0) continue; String[] names = appResources.getStringArray(namesId); //- Descriptions int descriptionsId = appResources.getIdentifier( RESOURCE_THEMES_DESCRIPTIONS, "array", //$NON-NLS-1$ appPackage); if (descriptionsId == 0) continue; String[] descriptions = appResources.getStringArray(descriptionsId); //- Author int authorId = appResources.getIdentifier( RESOURCE_THEMES_AUTHOR, "string", //$NON-NLS-1$ appPackage); if (authorId == 0) continue; String author = appResources.getString(authorId); // Get the resources and the context Context context = ctx.createPackageContext( appPackage, Context.CONTEXT_RESTRICTED); Resources resources = pm.getResourcesForApplication(appPackage); // Add every theme found for (int j = 0; j < names.length; j++) { Theme theme = new Theme(); theme.mPackage = appPackage; theme.mId = ids[j]; theme.mName = names[j]; theme.mDescription = descriptions[j]; theme.mAuthor = author; theme.mContext = context; theme.mResources = resources; themes.add(theme); if (DEBUG) { Log.v(TAG, String.format("Found theme: %s", theme)); //$NON-NLS-1$ } } } } catch (Exception e) {/**NON BLOCK**/} } // Return the themes found themes.add(0, getDefaultTheme(ctx)); return themes; } /** * Method that returns if the theme is the default theme * * @param theme The theme to check * @return boolean Id the current theme is the default theme */ public static boolean isDefaultTheme(Theme theme) { String themeSettings = (String)FileManagerSettings.SETTINGS_THEME.getDefaultValue(); String defaultPackage = themeSettings.substring(0, themeSettings.indexOf(":")); //$NON-NLS-1$ String defaultId = themeSettings.substring(themeSettings.indexOf(":") + 1); //$NON-NLS-1$ return theme.mPackage.compareTo(defaultPackage) == 0 && theme.mId.compareTo(defaultId) == 0; } /** * A class that represents a theme for the file manager app. */ public static class Theme implements Comparable<Theme> { String mPackage; String mId; String mName; String mDescription; String mAuthor; Context mContext; Resources mResources; /** * Constructor of <code>Theme</code> */ Theme() { super(); } /** * Method that returns the composed identifier * * @return String The composed identifier */ public String getComposedId() { return String.format("%s:%s", this.mPackage, this.mId); //$NON-NLS-1$ } /** * Method that returns the package name of the apk that contains the theme * * @return String The package name of the apk that contains the theme */ public String getPackage() { return this.mPackage; } /** * Method that returns the id of the theme inside the themes apk * * @return String The id of the theme inside the themes apk */ public String getId() { return this.mId; } /** * Method that returns the name of the theme * * @return String The name of the theme */ public String getName() { return this.mName; } /** * Method that returns the description of the theme * * @return String The description of the theme */ public String getDescription() { return this.mDescription; } /** * Method that returns the author of the theme * * @return String The author of the theme */ public String getAuthor() { return this.mAuthor; } /** * Method that returns the preview image of the current theme * * @param ctx The current context * @return Drawable The drawable */ public Drawable getPreviewImage(Context ctx) { String resId = "theme_preview_drawable"; //$NON-NLS-1$ if (this.compareTo(ThemeManager.getDefaultTheme(ctx)) != 0) { resId = String.format( "%s_%s", //$NON-NLS-1$ this.mId, "theme_preview_drawable"); //$NON-NLS-1$ } int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { return this.mResources.getDrawable(id); } return null; } /** * Method that returns the preview image of the current theme * * @param ctx The current context * @return Drawable The drawable */ public Drawable getNoPreviewImage(Context ctx) { String resId = String.format( "%s_%s", //$NON-NLS-1$ this.mId, "theme_no_preview_drawable"); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { return this.mResources.getDrawable(id); } // Default theme id = mDefaultTheme.mResources.getIdentifier( "theme_no_preview_drawable", //$NON-NLS-1$ "drawable", //$NON-NLS-1$ mDefaultTheme.mPackage); return mDefaultTheme.mResources.getDrawable(id); } /** * Method that sets the base theme of the current context * * @param ctx The current context * @param overlay Indicates if the theme should be the overlay one */ public void setBaseTheme(Context ctx, boolean overlay) { String resId = String.format("%s_%s", this.mId, "base_theme"); //$NON-NLS-1$ //$NON-NLS-2$ int id = this.mResources.getIdentifier(resId, "string", this.mPackage); //$NON-NLS-1$ if (id != 0) { String base = this.mResources.getString(id, "holo_light"); //$NON-NLS-1$ int themeId = base.compareTo("holo") == 0 ? //$NON-NLS-1$ R.style.FileManager_Theme_Holo : R.style.FileManager_Theme_Holo_Light; if (overlay) { themeId = base.compareTo("holo") == 0 ? //$NON-NLS-1$ R.style.FileManager_Theme_Holo_Overlay : R.style.FileManager_Theme_Holo_Light_Overlay; } ctx.setTheme(themeId); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( "base_theme", "string", mDefaultTheme.mPackage); //$NON-NLS-1$ //$NON-NLS-2$ String base = this.mResources.getString(id, "holo_light"); //$NON-NLS-1$ int themeId = base.compareTo("holo") == 0 ? //$NON-NLS-1$ R.style.FileManager_Theme_Holo : R.style.FileManager_Theme_Holo_Light; if (overlay) { themeId = base.compareTo("holo") == 0 ? //$NON-NLS-1$ R.style.FileManager_Theme_Holo_Overlay : R.style.FileManager_Theme_Holo_Light_Overlay; } ctx.setTheme(themeId); } /** * Method that sets the titlebar drawable of an ActionBar * * @param ctx The current context * @param actionBar The action bar * @param resource The string resource */ public void setTitlebarDrawable(Context ctx, ActionBar actionBar, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { actionBar.setBackgroundDrawable(this.mResources.getDrawable(id)); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "drawable", mDefaultTheme.mPackage); //$NON-NLS-1$ actionBar.setBackgroundDrawable(mDefaultTheme.mResources.getDrawable(id)); } /** * Method that sets the background drawable of a View * * @param ctx The current context * @param view The view which apply the style * @param resource The string resource */ public void setBackgroundDrawable(Context ctx, View view, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { view.setBackground(this.mResources.getDrawable(id)); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "drawable", mDefaultTheme.mPackage); //$NON-NLS-1$ view.setBackground(mDefaultTheme.mResources.getDrawable(id)); } /** * Method that sets the image drawable of a ImageView * * @param ctx The current context * @param view The view which apply the style * @param resource The string resource */ public void setImageDrawable(Context ctx, ImageView view, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { view.setImageDrawable(this.mResources.getDrawable(id)); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "drawable", mDefaultTheme.mPackage); //$NON-NLS-1$ view.setImageDrawable(mDefaultTheme.mResources.getDrawable(id)); } /** * Method that returns an image drawable of the current theme * * @param ctx The current context * @param resource The string resource * @return Drawable The drawable */ public Drawable getDrawable(Context ctx, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "drawable", this.mPackage); //$NON-NLS-1$ if (id != 0) { return this.mResources.getDrawable(id); } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "drawable", mDefaultTheme.mPackage); //$NON-NLS-1$ return mDefaultTheme.mResources.getDrawable(id); } /** * Method that sets the text color of a TextView * * @param ctx The current context * @param view The view which apply the style * @param resource The string resource */ public void setTextColor(Context ctx, TextView view, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "color", this.mPackage); //$NON-NLS-1$ if (id != 0) { view.setTextColor(this.mResources.getColor(id)); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "color", mDefaultTheme.mPackage); //$NON-NLS-1$ view.setTextColor(mDefaultTheme.mResources.getColor(id)); } /** * Method that returns a color from the theme * * @param ctx The current context * @param resource The string resource * @return int The color reference */ public int getColor(Context ctx, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "color", this.mPackage); //$NON-NLS-1$ if (id != 0) { return this.mResources.getColor(id); } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "color", mDefaultTheme.mPackage); //$NON-NLS-1$ return mDefaultTheme.mResources.getColor(id); } /** * Method that sets the background color of a View * * @param ctx The current context * @param view The view which apply the style * @param resource The string resource */ public void setBackgroundColor(Context ctx, View view, String resource) { String resId = String.format("%s_%s", this.mId, resource); //$NON-NLS-1$ int id = this.mResources.getIdentifier(resId, "color", this.mPackage); //$NON-NLS-1$ if (id != 0) { view.setBackgroundColor(this.mResources.getColor(id)); return; } // Default theme id = mDefaultTheme.mResources.getIdentifier( resource, "color", mDefaultTheme.mPackage); //$NON-NLS-1$ view.setBackgroundColor(mDefaultTheme.mResources.getColor(id)); } /** * Method that set the style of the dialog. * * @param ctx The current context * @param dialog The dialog which apply the style */ @SuppressWarnings("deprecation") public void setDialogStyle(Context ctx, AlertDialog dialog) { applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON1)); applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON2)); applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON3)); applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON_NEGATIVE)); applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON_NEUTRAL)); applyButtonStyle(ctx, dialog.getButton(DialogInterface.BUTTON_POSITIVE)); } /** * Method that apply the current style to a button * * @param ctx The current context * @param button The button which apply the style */ private void applyButtonStyle(Context ctx, Button button) { if (button != null) { setBackgroundDrawable(ctx, button, "selectors_button_drawable"); //$NON-NLS-1$ setTextColor(ctx, button, "text_color"); //$NON-NLS-1$ } } /** * {@inheritDoc} */ @Override public String toString() { return "Theme [Package=" + this.mPackage + //$NON-NLS-1$ ", Id=" + this.mId + //$NON-NLS-1$ ", Name=" + this.mName //$NON-NLS-1$ + ", Description=" + this.mDescription //$NON-NLS-1$ + ", Author=" + this.mAuthor + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } /** * {@inheritDoc} */ @Override public int compareTo(Theme another) { return getComposedId().compareTo(another.getComposedId()); } } }