/*
* Android Weather Notification.
* Copyright (C) 2010 Denis Nelubin aka Gelin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* http://gelin.ru
* mailto:den@gelin.ru
*/
package ru.gelin.android.weather.notification.skin;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.preference.PreferenceManager;
import ru.gelin.android.weather.notification.IntentParameters;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static ru.gelin.android.weather.notification.IntentParameters.ACTION_WEATHER_UPDATE;
import static ru.gelin.android.weather.notification.IntentParameters.ACTION_WEATHER_UPDATE_2;
import static ru.gelin.android.weather.notification.skin.PreferenceKeys.SKIN_ENABLED_PATTERN;
/**
* Contains methods to handle list of installed skins.
* The BroadcastReceivers which handles ACTION_WEATHER_UPDATE and ACTION_WEATHER_UPDATE_2
* intents are tracked.
* The activity which handles ACTION_WEATHER_SKIN_PREFERENCES intent and is placed in the same
* Android AND Java package as the received is treated as a configuration activity for the skin.
*/
public class SkinManager {
Context context;
/** Map of the skin Android package name + Java package name to the skin info. Sorted by package name. */
Map<String, SkinInfo> skins = new TreeMap<String, SkinInfo>(); //sorted by the package name
/**
* Creates the manager. Updates the list of installed skins.
*/
public SkinManager(Context context) {
this.context = context;
querySkinReceivers();
updateEnabledFlag();
querySkinConfigs();
}
/**
* Returns the list of installed skins.
*/
public List<SkinInfo> getInstalledSkins() {
List<SkinInfo> result = new ArrayList<SkinInfo>();
result.addAll(this.skins.values());
return result;
}
/**
* Returns the list of enabled skins.
*/
public List<SkinInfo> getEnabledSkins() {
List<SkinInfo> result = new ArrayList<SkinInfo>();
for (SkinInfo skin : this.skins.values()) {
if (skin.isEnabled()) {
result.add(skin);
}
}
return result;
}
/**
* Returns the list of installed, but disabled skins.
*/
public List<SkinInfo> getDisabledSkins() {
List<SkinInfo> result = new ArrayList<SkinInfo>();
for (SkinInfo skin : this.skins.values()) {
if (!skin.isEnabled()) {
result.add(skin);
}
}
return result;
}
/**
* Queries PackageManager for broadcast receivers which handles
* ACTION_WEATHER_UPDATE and ACTION_WEATHER_UPDATE_2.
* Puts found data (skin package, receiver class and label) into skins map.
*/
void querySkinReceivers() {
querySkinReceivers(ACTION_WEATHER_UPDATE, SkinInfo.Version.V1); //TODO: join intent action names and versions...
querySkinReceivers(ACTION_WEATHER_UPDATE_2, SkinInfo.Version.V2);
}
/**
* Queries PackageManager for broadcast receivers which handles specified Action.
* Puts found data (skin package, receiver class and labed) into skins map.
*/
void querySkinReceivers(String action, SkinInfo.Version version) {
PackageManager pm = context.getPackageManager();
Intent intent = new Intent(action);
List<ResolveInfo> search = pm.queryBroadcastReceivers(intent, 0); //without flags
for (ResolveInfo info : search) {
//Log.d(TAG, String.valueOf(info));
String packageName = info.activityInfo.packageName;
String label = String.valueOf(info.loadLabel(pm));
String receiverClass = info.activityInfo.name;
//Log.d(TAG, "package: " + packageName);
//Log.d(TAG, "class: " + receiverClass);
SkinInfo skin = SkinInfo.getInstance(getSkinId(info));
skin.packageName = packageName;
skin.version = version;
skin.broadcastReceiverLabel = label;
skin.broadcastReceiverClass = receiverClass;
this.skins.put(skin.getId(), skin);
}
int order = 0;
for (SkinInfo skin : this.skins.values()) {
skin.order = order;
order += 2;
}
}
/**
* Checks preferences to found which skin is enabled.
*/
void updateEnabledFlag() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.context);
for (Map.Entry<String, SkinInfo> skin : this.skins.entrySet()) {
String key = String.format(SKIN_ENABLED_PATTERN, skin.getKey());
boolean enabled = prefs.getBoolean(key, isBuiltinSkin(skin.getKey())); //builtin skin is enabled by default
skin.getValue().enabled = enabled;
}
}
boolean isBuiltinSkin(String packageName) {
return packageName.startsWith(this.context.getPackageName()) && packageName.endsWith("builtin");
}
/**
* Queries PackageManager for activities which handles ACTION_WEATHER_SKIN_PREFERENCES actions.
* Updates the skin map according the package name.
*/
void querySkinConfigs() {
PackageManager pm = context.getPackageManager();
Intent intent = new Intent(IntentParameters.ACTION_WEATHER_SKIN_PREFERENCES);
List<ResolveInfo> search = pm.queryIntentActivities(intent, 0); //without flags
for (ResolveInfo info : search) {
//Log.d(TAG, String.valueOf(info));
String label = String.valueOf(info.loadLabel(pm));
String activityClass = info.activityInfo.name;
//Log.d(TAG, "package: " + packageName);
//Log.d(TAG, "class: " + activityClass);
SkinInfo skin = this.skins.get(getSkinId(info));
if (skin == null) {
continue;
}
skin.configActivityLabel = label;
skin.configActivityClass = activityClass;
}
}
String getSkinId(ResolveInfo info) {
String androidPackageName = info.activityInfo.packageName;
String className = info.activityInfo.name;
String javaPackageName = className.substring(0, className.lastIndexOf('.'));
return androidPackageName + "/" + javaPackageName;
}
}