package com.buzzbuddy.android;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.acra.ACRA;
import org.acra.annotation.ReportsCrashes;
import android.app.Application;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
@ReportsCrashes(formKey = "dDhUXzBZT1VmWEYtbDMwazlGa2loRlE6MQ", logcatArguments = { "-t", "150", "-v", "long",
"dalvikvm:S" })
public class BuzzBuddyApp extends Application implements Comparator<ResolveInfo> {
private static final String SYSTEM_PACKAGE_REGEX = "(com.android.(mms|contacts|calendar|email|phone)|com.google.android.*)";
private static final String BUZZ_BUDDY_PACKAGE = BuzzBuddyApp.class.getPackage().getName();
private static final String INSTALL_SHORTCUT_INTENT = "com.android.launcher.action.INSTALL_SHORTCUT";
private static final String HOME_SCREEN_ACTIVITY = BuzzBuddyActivity.class.getSimpleName();
private static final String TAG = BuzzBuddyApp.class.getSimpleName();
private static final String DATABASE_FILENAME = BuzzDB.DATABASE_NAME;
private BuzzDB base;
private DrawableManager drawableManager;
private ArrayList<ResolveInfo> unassignedApps;
private ArrayList<ResolveInfo> assignedApps;
private ArrayList<ResolveInfo> recommendedApps;
static final Set<String> recommendedPackages = new HashSet<String>() {
private static final long serialVersionUID = 1L;
{
add("com.jb.gosms");
add("com.whatsapp");
add("com.yahoo.mobile.client.android.mail");
add("com.sgiggle.production");
add("com.instagram.android");
add("com.twitter.android");
add("com.skype.raider");
add("com.android.vending");
add("com.google.android.apps.maps");
add("com.google.android.apps.plus");
add("com.omgpop.dstfree");
add("com.zynga.scramble");
add("com.facebook.orca");
add("com.google.android.gm");
add("com.google.android.talk");
add("com.facebook.katana");
add("com.google.android.apps.googlevoice");
add("com.android.mms");
add("com.android.calendar");
}
};
private final class AppListThread extends Thread {
private final String packageToDelete;
public AppListThread(final String packageName) {
super();
packageToDelete = packageName;
}
@Override
public void run() {
if (packageToDelete != null) {
Log.i(TAG, "deleting package " + packageToDelete + " from database, since app was just deleted");
base.deleteByPackageName(packageToDelete);
}
unassignedApps = assignedApps = recommendedApps = null;
getAppsFromPhone();
}
}
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCreate");
}
ACRA.init(this);
if (isFirstRun()) {
Log.i(TAG, "first Run");
addShortcutToHomeScreen();
}
drawableManager = new DrawableManager(getPackageManager());
addSystemAppsToRecommendedPackages();
base = new BuzzDB(this);
base.open();
refreshAppList(null);
}
private void addSystemAppsToRecommendedPackages() {
final PackageManager pm = getPackageManager();
final Intent stockIntent = new Intent();
stockIntent.addCategory(Intent.CATEGORY_DEFAULT);
stockIntent.setAction(Intent.ACTION_SENDTO);
stockIntent.setType("vnd.android-dir/mms-sms");
stockIntent.setData(Uri.parse("sms:2125551234"));
addAllPackageStrings(recommendedPackages,
pm.queryIntentActivities(stockIntent, PackageManager.MATCH_DEFAULT_ONLY));
stockIntent.setAction(Intent.ACTION_CALL);
stockIntent.setType(null);
stockIntent.setData(Uri.parse("tel:1234567890"));
addAllPackageStrings(recommendedPackages,
pm.queryIntentActivities(stockIntent, PackageManager.MATCH_DEFAULT_ONLY));
stockIntent.setAction(Intent.ACTION_SENDTO);
stockIntent.setType(null);
stockIntent.setData(Uri.parse("mailto:foo@bar.com"));
addAllPackageStrings(recommendedPackages,
pm.queryIntentActivities(stockIntent, PackageManager.MATCH_DEFAULT_ONLY));
final Intent calendarIntent = new Intent(Intent.ACTION_EDIT);
calendarIntent.setType("vnd.android.cursor.item/event");
calendarIntent.putExtra("allDay", true);
calendarIntent.putExtra("rrule", "FREQ=YEARLY");
addAllPackageStrings(recommendedPackages,
pm.queryIntentActivities(calendarIntent, PackageManager.MATCH_DEFAULT_ONLY));
}
private void addAllPackageStrings(final Set<String> set, final List<ResolveInfo> apps) {
for (final ResolveInfo rInfo : apps) {
set.add(rInfo.activityInfo.applicationInfo.packageName);
}
}
public void refreshAppList(final String packageToDelete) {
new AppListThread(packageToDelete).start();
}
public List<ResolveInfo> getUnassignedApps() {
if (unassignedApps == null) {
if (BuildConfig.DEBUG) {
Log.i(TAG, "unassignedApps is null");
}
getAppsFromPhone();
}
return unassignedApps;
}
public List<ResolveInfo> getAssignedApps() {
if (assignedApps == null) {
if (BuildConfig.DEBUG) {
Log.i(TAG, "assignedApps is null");
}
getAppsFromPhone();
}
return assignedApps;
}
public List<ResolveInfo> getRecommendedApps() {
if (recommendedApps == null) {
if (BuildConfig.DEBUG) {
Log.i(TAG, "recommendedApps is null");
}
getAppsFromPhone();
}
return recommendedApps;
}
private synchronized void getAppsFromPhone() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "entering getAppsFromPhone, thread id = " + Thread.currentThread().getId());
}
if (unassignedApps != null || recommendedApps != null || assignedApps != null) {
Log.i(TAG, "we already have the data, let's exit");
return;
}
Log.i(TAG, "do not have data, not exiting getAppsFromPhone");
final PackageManager pm = getPackageManager();
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> launcherApps = pm.queryIntentActivities(intent, 0);
final Map<String, ResolveInfo> candidateApps = filterSystemApps(launcherApps);
unassignedApps = new ArrayList<ResolveInfo>();
assignedApps = new ArrayList<ResolveInfo>();
recommendedApps = new ArrayList<ResolveInfo>();
sortAppAssignment(candidateApps, unassignedApps, recommendedApps, assignedApps, pm);
}
private synchronized void sortAppAssignment(final Map<String, ResolveInfo> allApps,
final List<ResolveInfo> unassignedApps, final List<ResolveInfo> recommendedApps,
final List<ResolveInfo> assignedApps, final PackageManager pm) {
final Cursor baseApps = base.queryAll(BuzzDB.DATABASE_APP_TABLE);
baseApps.moveToFirst();
while (!baseApps.isAfterLast()) {
final String packageName = baseApps.getString(BuzzDB.APP_INDEX_NAME);
Log.i(TAG,
"first column = " + packageName + ", second column = "
+ baseApps.getString(BuzzDB.APP_INDEX_VIBRATION));
assignedApps.add(allApps.remove(packageName));
baseApps.moveToNext();
}
unassignedApps.addAll(allApps.values());
for (final String elem : recommendedPackages) {
if (allApps.containsKey(elem)) {
final ResolveInfo current = allApps.get(elem);
if (!recommendedApps.contains(current)) {
recommendedApps.add(current);
}
unassignedApps.remove(current);
}
}
Collections.sort(unassignedApps, this);
Collections.sort(recommendedApps, this);
baseApps.close();
}
private Map<String, ResolveInfo> filterSystemApps(final List<ResolveInfo> allApps) {
final Map<String, ResolveInfo> notificationApps = new HashMap<String, ResolveInfo>();
final List<ResolveInfo> drawableList = new LinkedList<ResolveInfo>();
for (final ResolveInfo rInfo : allApps) {
final String packageName = rInfo.activityInfo.applicationInfo.packageName;
if ((rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 1
|| packageName.matches(SYSTEM_PACKAGE_REGEX)
|| recommendedPackages.contains(packageName)) {
if (packageName.equals(BUZZ_BUDDY_PACKAGE)) {
continue;
}
notificationApps.put(packageName, rInfo);
drawableList.add(rInfo);
}
}
new Thread(new Runnable() {
@Override
public void run() {
drawableManager.addAll(drawableList);
}
}).start();
return notificationApps;
}
private boolean isFirstRun() {
final File file = new File(getDatabasePath(DATABASE_FILENAME).getAbsolutePath());
return !file.exists();
}
private void addShortcutToHomeScreen() {
Log.i(TAG, "creating Shortcut!");
final Intent shortcutIntent = new Intent();
shortcutIntent.setComponent(new ComponentName(getPackageName(), "." + HOME_SCREEN_ACTIVITY));
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
final Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.app_name));
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.ic_launcher));
addIntent.setAction(INSTALL_SHORTCUT_INTENT);
sendBroadcast(addIntent);
}
public BuzzDB getDatabase() {
return base;
}
@Override
public void onTerminate() {
drawableManager = null;
base.close();
base = null;
}
@Override
public int compare(final ResolveInfo first, final ResolveInfo second) {
final PackageManager pm = getPackageManager();
final String firstLabel = (String) first.activityInfo.applicationInfo.loadLabel(pm);
final String secondLabel = (String) second.activityInfo.applicationInfo.loadLabel(pm);
return firstLabel.compareToIgnoreCase(secondLabel);
}
public DrawableManager getDrawableManager() {
return drawableManager;
}
}