/* * Copyright © 2014 Jeff Corcoran * * This file is part of Hangar. * * Hangar is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Hangar 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 GNU General Public License * along with Hangar. If not, see <http://www.gnu.org/licenses/>. * */ package ca.mimic.apphangar; import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.app.usage.UsageStats; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; import android.widget.RemoteViews; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import ca.mimic.apphangar.Tools.TaskInfo; import ca.mimic.apphangar.Tools.LollipopTaskInfo; public class WatchfulService extends Service { TasksDataSource db; SharedPreferences prefs; SharedPreferences widgetPrefs; PackageManager pkgm; PowerManager pm; static int failCount; static TaskInfo runningTask; static ArrayList<TaskInfo> pinnedList; static ArrayList<TaskInfo> taskList; static ArrayList<String> notificationTasks; static LollipopTaskInfo lollipopTaskInfo; // createNotification variables String taskPackage; int contLayout; int rowLayout; int imageButtonLayout; int imageContLayout; int numOfApps; int setPriority; boolean secondRow; boolean moreApps; int moreAppsPage = 1; int moreAppsPages; int pinnedCount; int iconSize; int itemLayout; String mIcon; String notificationBg; String launcherPackage = null; boolean isNotificationRunning; final int MAX_RUNNING_TASKS = 20; final int LOOP_SECONDS = 3; final int ICON_SIZE_SMALL = 0; final int ICON_SIZE_LARGE = 2; protected static final String BCAST_CONFIGCHANGED = "android.intent.action.CONFIGURATION_CHANGED"; Map<String, Integer> iconMap; Handler handler = new Handler(); @Override public IBinder onBind(Intent intent) { return new IWatchfulService.Stub() { @Override public void createNotification() { WatchfulService.this.createNotification(); } @Override public void destroyNotification() { WatchfulService.this.destroyNotification(); } @Override public void buildTasks() { WatchfulService.this.buildTasks(); } @Override public void buildReorderAndLaunch() { pinnedList = null; notificationTasks = null; moreAppsPage = 1; synchronized (WatchfulService.this) { WatchfulService.this.buildReorderAndLaunch(true); } } }; } @Override public void onCreate() { super.onCreate(); if (db == null) { db = TasksDataSource.getInstance(this); db.open(); failCount = 0; } else { return; } Tools.HangarLog("starting up.. "); prefs = getSharedPreferences(getPackageName(), MODE_MULTI_PROCESS); widgetPrefs = getSharedPreferences("AppsWidget", Context.MODE_MULTI_PROCESS); taskPackage = this.getPackageName(); imageButtonLayout = getResources().getIdentifier("imageButton", "id", taskPackage); imageContLayout = getResources().getIdentifier("imageCont", "id", taskPackage); IntentFilter filter = new IntentFilter(); filter.addAction(BCAST_CONFIGCHANGED); registerReceiver(mBroadcastReceiver, filter); pm = (PowerManager) getSystemService(Context.POWER_SERVICE); iconMap = new HashMap<String, Integer>(); iconMap.put(Settings.STATUSBAR_ICON_WHITE_WARM, R.drawable.ic_apps_warm); iconMap.put(Settings.STATUSBAR_ICON_WHITE_COLD, R.drawable.ic_apps_cold); iconMap.put(Settings.STATUSBAR_ICON_WHITE_BLUE, R.drawable.ic_apps_blue); iconMap.put(Settings.STATUSBAR_ICON_WHITE, R.drawable.ic_apps_white); iconMap.put(Settings.STATUSBAR_ICON_BLACK_WARM, R.drawable.ic_apps_warm_black); iconMap.put(Settings.STATUSBAR_ICON_BLACK_COLD, R.drawable.ic_apps_cold_black); iconMap.put(Settings.STATUSBAR_ICON_BLACK_BLUE, R.drawable.ic_apps_blue_black); iconMap.put(Settings.STATUSBAR_ICON_TRANSPARENT, R.drawable.ic_apps_transparent); setRefreshAlarm(getApplicationContext()); } public static void setRefreshAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, BootStart.class); intent.setAction(Tools.REFRESH_ACTION); PendingIntent pi = PendingIntent.getBroadcast(context, 1339, intent, PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.setRepeating( AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + Tools.AWAKE_REFRESH, Tools.AWAKE_REFRESH, pi); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Check if action is a Multiple page trigger if (intent != null && intent.getAction() != null && intent.getAction().equals(Settings.MORE_APPS_ACTION)) { moreAppsPage = moreAppsPage + 1; createNotification(); return START_STICKY; } prefs = getSharedPreferences(getPackageName(), MODE_MULTI_PROCESS); widgetPrefs = getSharedPreferences("AppsWidget", Context.MODE_MULTI_PROCESS); pkgm = getPackageManager(); launcherPackage = Tools.getLauncher(getApplicationContext()); IntentFilter filter = new IntentFilter(); filter.addAction(BCAST_CONFIGCHANGED); registerReceiver(mBroadcastReceiver, filter); handler.removeCallbacks(scanApps); handler.post(scanApps); return START_STICKY; } @Override public void onDestroy() { Tools.HangarLog("onDestroy service.."); handler.removeCallbacks(scanApps); db.close(); unregisterReceiver(mBroadcastReceiver); super.onDestroy(); } protected void buildReorderAndLaunch(boolean isToggled) { if (isToggled) { Tools.HangarLog("buildReorderAndLaunch isToggled"); // Grab new taskList and check if this is a new install taskList = Tools.buildTaskList(getApplicationContext(), db, Settings.TASKLIST_QUEUE_LIMIT); Tools.HangarLog("BaseTask 0: " + taskList.get(0).packageName); Tools.HangarLog("BaseTask size: " + taskList.size()); // TODO: This needs to be more elegant for L... if (taskList.size() == 0 || (taskList.size() == 1 && (taskList.get(0).packageName.equals(getPackageName()) || taskList.get(0).packageName.equals("com.android.settings")))) { if (Tools.isLollipop(false)) { buildLBaseTasks(); } else { buildBaseTasks(); } taskList = Tools.buildTaskList(getApplicationContext(), db, Settings.TASKLIST_QUEUE_LIMIT); } reorderAndLaunch(); } } protected String getClassName(Context context, String taskPackage) { String className = null; ResolveInfo resolveInfo; try { resolveInfo = new Tools().cachedImageResolveInfo(context, taskPackage); className = resolveInfo.activityInfo.name; } catch (Exception e) { } return className; } @TargetApi(21) protected void buildLBaseTasks() { Context context = getApplicationContext(); List<UsageStats> stats = Tools.getUsageStats(context); for (UsageStats task : stats) { String taskPackage = task.getPackageName(); String taskClass = getClassName(context, taskPackage); Tools.HangarLog("buildLBaseTask: package: " + taskPackage + " class: " + taskClass); buildTaskInfo(taskClass, taskPackage); } } protected void buildBaseTasks() { // taskList is blank! Populating db from apps in memory. final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); final List<ActivityManager.RunningTaskInfo> recentTasks = activityManager.getRunningTasks(MAX_RUNNING_TASKS); if (recentTasks != null && recentTasks.size() > 0) { for (ActivityManager.RunningTaskInfo recentTask : recentTasks) { ComponentName task = recentTask.baseActivity; try { String taskClass = task.getClassName(); String taskPackage = task.getPackageName(); buildTaskInfo(taskClass, taskPackage); } catch (NullPointerException e) { } } } } protected void buildTaskInfo(String className, String packageName) { boolean isTaskBlacklisted = Tools.isBlacklistedOrBad(packageName, getApplicationContext(), db); if (className == null || className.equals("com.android.internal.app.ResolverActivity") || isTaskBlacklisted || packageName.equals(launcherPackage)) { Tools.HangarLog("buildTaskInfo -- task [" + packageName + "] is bad? Bailing!"); return; } runningTask = new TaskInfo(packageName); runningTask.className = className; try { ApplicationInfo appInfo = pkgm.getApplicationInfo(packageName, 0); runningTask.appName = appInfo.loadLabel(pkgm).toString(); if (runningTask.appName.isEmpty()) { Tools.HangarLog("Can't add task [" + packageName + "] to db -- appName is blank!"); return; } updateOrAdd(runningTask); } catch (Exception e) { Tools.HangarLog("NPE taskPackage: " + packageName); e.printStackTrace(); } } protected void buildTasks() { Runnable runnable = new Runnable() { @Override public void run() { try { boolean isLollipop; boolean newActivity = false; boolean recentTasksEmpty = true; boolean isToggled = prefs.getBoolean(Settings.TOGGLE_PREFERENCE, Settings.TOGGLE_DEFAULT); boolean smartNotification = prefs.getBoolean(Settings.SMART_NOTIFICATION_PREFERENCE, Settings.SMART_NOTIFICATION_DEFAULT); final Context context = getApplicationContext(); String taskClass = ""; String taskPackage = ""; String lTaskClass = ""; String lTaskPackage = ""; // TODO: This whole thing needs major refactoring. Needs <=KK and =>L methods isLollipop = Tools.isLollipop(false); db = TasksDataSource.getInstance(context); db.open(); pm = (PowerManager) getSystemService(Context.POWER_SERVICE); final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); final List<ActivityManager.RunningTaskInfo> recentTasks = activityManager.getRunningTasks(MAX_RUNNING_TASKS); if (recentTasks != null && recentTasks.size() > 0) { recentTasksEmpty = false; ComponentName task = recentTasks.get(0).baseActivity; taskPackage = task.getPackageName(); taskClass = task.getClassName(); } if (isLollipop) { String oldPackage = ""; String newPackage; if (lollipopTaskInfo != null) oldPackage = lollipopTaskInfo.packageName; List<UsageStats> listStats = Tools.getUsageStats(context); if (listStats.size() == 0) { // Either no permission or nothing new. Move along return; } else { if (lollipopTaskInfo == null) { // listStats has been 0 up until now, force newActivity Tools.HangarLog("newActivity being set to True"); newActivity = true; } } lollipopTaskInfo = Tools.parseUsageStats(listStats, lollipopTaskInfo); if (listStats.size() < 2 && listStats.size() > 0) { newPackage = Tools.firstPackage(listStats); } else { newPackage = lollipopTaskInfo.packageName; } lTaskPackage = lollipopTaskInfo.lastPackageName; boolean isTaskBlacklisted = Tools.isBlacklistedOrBad(lTaskPackage, context, db); if (!isTaskBlacklisted) { lTaskClass = getClassName(context, lTaskPackage); newActivity = !oldPackage.equals(newPackage) && (lTaskClass != null); } if (!newActivity) { return; } } if (!recentTasksEmpty) { if (isLollipop && taskPackage.equals(lollipopTaskInfo.lastRecentPackageName)) { Tools.HangarLog("blanking taskPackage and taskClass (runningTask: " + taskPackage + ")"); taskPackage = ""; taskClass = ""; } if (isLollipop) lollipopTaskInfo.lastRecentPackageName = taskPackage; } if (launcherPackage != null && !taskPackage.isEmpty() && taskPackage.equals(launcherPackage)) { boolean runningTaskLauncher = runningTask == null || !runningTask.packageName.equals(taskPackage); boolean runningTaskLauncherL = false; if (isLollipop) runningTaskLauncherL = lollipopTaskInfo.lastRecentPackageName.equals(taskPackage); if (runningTaskLauncher || (isLollipop && runningTaskLauncherL)) { if (!isToggled && isAppsWidget()) { taskList = Tools.buildTaskList(getApplicationContext(), db, Settings.TASKLIST_QUEUE_LIMIT); reorderAndLaunch(true); } // First time in launcher? Update the widget! Tools.HangarLog("Found launcher -- Calling updateWidget!"); Tools.updateWidget(context); runningTask = new TaskInfo(taskPackage); buildReorderAndLaunch(isToggled & !isNotificationRunning); } if (!isLollipop) { return; } } boolean isTaskBlacklisted = Tools.isBlacklistedOrBad(taskPackage, context, db); if (taskClass.equals("com.android.internal.app.ResolverActivity") || isTaskBlacklisted) { buildReorderAndLaunch(isToggled & !isNotificationRunning); if (!isLollipop) { return; } } if (runningTask != null && runningTask.packageName.equals(isLollipop ? lTaskPackage : taskPackage)) { if (isLollipop) { return; } if (pm.isScreenOn()) { runningTask.seconds += LOOP_SECONDS; if (runningTask.seconds >= LOOP_SECONDS * 5) { db.addSeconds(taskPackage, runningTask.seconds); runningTask.totalseconds += runningTask.seconds; runningTask.seconds = 0; } } return; } buildTaskInfo(isLollipop ? lTaskClass : taskClass, isLollipop ? lTaskPackage : taskPackage); if (isLollipop) { if (newActivity) { int activityDelta = (int) Math.ceil(lollipopTaskInfo.timeInFGDelta / 1000); Tools.HangarLog("New activity found, seconds in old: " + activityDelta); if (activityDelta > 0) { db.addSeconds(lollipopTaskInfo.lastPackageName, activityDelta); } } } if (taskClass.equals(getPackageName())) { buildReorderAndLaunch(isToggled & !isNotificationRunning); return; } // If task is showing we do not need to update the notification drawer. if (smartNotification && isToggled) { if (notificationTasks != null && new Tools().isInArray(notificationTasks, isLollipop ? lTaskPackage : taskPackage)) { buildReorderAndLaunch(!isNotificationRunning); return; } else if (notificationTasks == null) { moreAppsPage = 1; } } if (new Tools().isPinned(context, isLollipop ? lTaskPackage : taskPackage)) { buildReorderAndLaunch(isToggled & !isNotificationRunning); return; } buildReorderAndLaunch(isToggled); } catch (Exception e) { if (failCount >= 2) { e.printStackTrace(); Tools.HangarLog("failCount reached limit. Giving up!"); } else { failCount++; e.printStackTrace(); Tools.HangarLog("Exception hit! Restarting buildTasks.. [" + failCount + "] exception: " + e); WatchfulService.this.buildTasks(); } } } }; new Thread(runnable).start(); } protected final Runnable scanApps = new Runnable(){ public void run(){ // Tools.HangarLog("scanApps running.."); buildTasks(); handler.postDelayed(this, LOOP_SECONDS * 1000); } }; public synchronized int updateOrAdd(TaskInfo newInfo) { int rows = db.updateTaskTimestamp(newInfo.packageName); if (rows > 0) { Tools.HangarLog("Updated task [" + newInfo.appName + "] with new Timestamp"); return db.increaseLaunch(newInfo.packageName); } else { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); Tools.HangarLog("Added task [" + newInfo.appName + "] to database date=[" + dateFormatter.format(date) + "]"); db.createTask(newInfo.appName, newInfo.packageName, newInfo.className, dateFormatter.format(date)); return 1; } } public void destroyNotification() { Tools.HangarLog("DESTROY"); isNotificationRunning = false; runningTask = null; pinnedList = null; notificationTasks = null; moreAppsPage = 1; stopForeground(true); } protected boolean isAppsWidget() { try { int ids[] = AppWidgetManager.getInstance(this).getAppWidgetIds(new ComponentName(this, AppsWidget.class)); if (ids.length > 0) return true; } catch (Exception e) { e.printStackTrace(); } return false; } protected void reorderAndLaunch(boolean isWidget) { Tools.HangarLog("reorderAndLaunch taskList.size(): " + taskList.size() + " isWidget: " + isWidget); boolean weightedRecents = prefs.getBoolean(Settings.WEIGHTED_RECENTS_PREFERENCE, Settings.WEIGHTED_RECENTS_DEFAULT); boolean isToggled = prefs.getBoolean(Settings.TOGGLE_PREFERENCE, Settings.TOGGLE_DEFAULT); int weightPriority = Integer.parseInt(prefs.getString(Settings.WEIGHT_PRIORITY_PREFERENCE, Integer.toString(Settings.WEIGHT_PRIORITY_DEFAULT))); if (weightedRecents) { taskList = new Tools().reorderTasks(taskList, db, weightPriority); } if (isToggled) createNotification(); if (isWidget) Tools.reorderWidgetTasks(db, getApplicationContext()); } protected void reorderAndLaunch() { reorderAndLaunch(false); } public void updatePrefs() { contLayout = prefs.getBoolean(Settings.ROW_DIVIDER_PREFERENCE, Settings.ROW_DIVIDER_DEFAULT) ? getResources().getIdentifier("notification", "layout", taskPackage) : getResources().getIdentifier("notification_no_dividers", "layout", taskPackage); rowLayout = prefs.getBoolean(Settings.DIVIDER_PREFERENCE, Settings.DIVIDER_DEFAULT) ? getResources().getIdentifier("notification_row", "layout", taskPackage) : getResources().getIdentifier("notification_row_no_dividers", "layout", taskPackage); numOfApps = Integer.parseInt(prefs.getString(Settings.APPSNO_PREFERENCE, Integer.toString(Settings.APPSNO_DEFAULT))); if (Tools.isLollipop(true)) { setPriority = Settings.PRIORITY_ON_L_DEFAULT; } else { setPriority = Integer.parseInt(prefs.getString(Settings.PRIORITY_PREFERENCE, Integer.toString(Settings.PRIORITY_DEFAULT))); } secondRow = prefs.getBoolean(Settings.SECOND_ROW_PREFERENCE, Settings.SECOND_ROW_DEFAULT); moreApps = prefs.getBoolean(Settings.MORE_APPS_PREFERENCE, Settings.MORE_APPS_DEFAULT); moreAppsPages = Integer.parseInt(prefs.getString(Settings.MORE_APPS_PAGES_PREFERENCE, Integer.toString(Settings.MORE_APPS_PAGES_DEFAULT))); iconSize = Integer.parseInt(prefs.getString(Settings.ICON_SIZE_PREFERENCE, Integer.toString(Settings.ICON_SIZE_DEFAULT))); notificationBg = prefs.getString(Settings.NOTIFICATION_BG_PREFERENCE, Settings.NOTIFICATION_BG_DEFAULT_VALUE); itemLayout = R.layout.notification_item; if (iconSize == ICON_SIZE_SMALL) { itemLayout = R.layout.notification_item_small; } else if (iconSize == ICON_SIZE_LARGE) { itemLayout = R.layout.notification_item_large; } mIcon = prefs.getString(Settings.STATUSBAR_ICON_PREFERENCE, Settings.STATUSBAR_ICON_DEFAULT); Tools.HangarLog("mIcon: " + mIcon); } public ArrayList<TaskInfo> getPageTasks(int pageNum, int count) { ArrayList<TaskInfo> copyList = new ArrayList<TaskInfo>(); if (taskList != null) copyList = new ArrayList<TaskInfo>(taskList); ArrayList<TaskInfo> tmpList = new ArrayList<TaskInfo>(); if (pageNum > moreAppsPages) return null; try { int start = (count * (pageNum - 1)) - pinnedCount - pageNum + 1; int end = (count * pageNum) - pinnedCount - pageNum + 1; Tools.HangarLog("getPageTasks i = " + start + " ; i < " + end); if (start < 0) { // This is if pinned brings us into the negative. We always need the right amount! int diff = start * -1; start = 0; end = end + diff; } if (copyList.size() < start) { Tools.HangarLog("copyList.size() == " + copyList.size() + " < start(" + start + " )"); return null; // return getPageTasks(moreAppsPage, count); } if (copyList.size() < end) { end = copyList.size(); } else if (copyList.size() == end) { end = copyList.size() - 1; } for (int i = start; i < end; i++) { tmpList.add(copyList.get(i)); } return tmpList; } catch (Exception e) { e.printStackTrace(); return null; } } public synchronized void createNotification() { int filledConts = 0; int maxButtons; boolean filledSecondRow = false; Context mContext = getApplicationContext(); if (moreAppsPage == 1) updatePrefs(); RemoteViews customNotifView = new RemoteViews(taskPackage, contLayout); RemoteViews customNotifBigView = customNotifView; // Create new AppDrawer row AppDrawer appDrawer = new AppDrawer(taskPackage); appDrawer.createRow(rowLayout, R.id.notifRow); appDrawer.setImageLayouts(imageButtonLayout, imageContLayout); appDrawer.setPrefs(prefs); appDrawer.setContext(mContext); maxButtons = numOfApps; int iconCacheCount = (maxButtons * (secondRow ? 2 : 1)); appDrawer.setCount(iconCacheCount, Settings.CACHED_NOTIFICATION_ICON_LIMIT, secondRow); ArrayList<TaskInfo> pageList; if (moreAppsPage == 1) { if (pinnedList == null) { Tools.HangarLog("pinnedList is null"); pinnedList = Tools.buildPinnedList(mContext, db); pinnedCount = pinnedList.size(); } if (taskList != null) { pageList = new ArrayList<TaskInfo>(taskList); } else { pageList = new ArrayList<TaskInfo>(); } pageList = new Tools().getPinnedTasks(mContext, pinnedList, pageList, iconCacheCount, moreApps); } else { if (pinnedCount > iconCacheCount) pinnedCount = iconCacheCount - 1; pageList = getPageTasks(moreAppsPage, iconCacheCount); if (pageList == null) { moreAppsPage = 1; createNotification(); return; } pageList = new Tools().getPinnedTasks(mContext, null, pageList, iconCacheCount, moreApps); if (pageList.size() == 1) { moreAppsPage = 1; return; } } // Tools.HangarLog("taskList: " + taskList + " pageList: " + pageList + " realmaxbuttons: " + numOfApps + " maxbuttons: " + maxButtons + " moreAppsPage: " + moreAppsPage); // Tools.HangarLog("taskList.size(): " + taskList.size() + " pageList.size(): " + pageList.size() + " realmaxbuttons: " + numOfApps + " maxbuttons: " + maxButtons + " moreAppsPage: " + moreAppsPage); customNotifBigView.removeAllViews(R.id.notifContainer); notificationTasks = new ArrayList<String>(); for (int i=0; i <= pageList.size(); i++) { boolean wrapItUp = false; if (i == pageList.size()) wrapItUp = true; if (filledConts == maxButtons || wrapItUp) { if (filledSecondRow) { filledSecondRow = false; customNotifBigView = customNotifView; customNotifBigView.addView(R.id.notifContainer, appDrawer.getRow()); break; } else { customNotifView.addView(R.id.notifContainer, appDrawer.getRow()); filledSecondRow = true; filledConts = 0; appDrawer.createRow(rowLayout, R.id.notifRow); appDrawer.setImageLayouts(imageButtonLayout, imageContLayout); } } if (!wrapItUp) { if (appDrawer.newItem(pageList.get(i), itemLayout)) { appDrawer.addItem(); notificationTasks.add(pageList.get(i).packageName); filledConts++; } } } if (!notificationBg.equals(Settings.NOTIFICATION_BG_DEFAULT_VALUE)) { customNotifView.setInt(R.id.notifContainer, "setBackgroundColor", Color.parseColor(notificationBg)); } if (filledSecondRow && secondRow) { Tools.HangarLog("Second row is not full -- adding expanded row anyway!"); // Second row is not full :( customNotifBigView = customNotifView; customNotifBigView.addView(R.id.notifContainer, appDrawer.getRow()); } // Set statusbar icon int smallIcon = iconMap.get(Settings.STATUSBAR_ICON_WHITE); try { smallIcon = iconMap.get(mIcon); } catch (NullPointerException e) { e.printStackTrace(); } Notification notification; NotificationCompat.Builder builder = new NotificationCompat.Builder(WatchfulService.this). setContentTitle(getResources().getString(R.string.app_name)) .setContentText(getResources().getString(R.string.app_name)) .setSmallIcon(smallIcon) .setContent(customNotifView) .setOngoing(true) .setWhen(System.currentTimeMillis()) .setPriority(setPriority); if (Tools.isLollipop(false)) lollipopNotificationSettings(builder); notification = builder.build(); if (secondRow) { notification.bigContentView = customNotifBigView; } Tools.HangarLog("isNotificationRunning: " + isNotificationRunning); if (isNotificationRunning) { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(1337, notification); } else { startForeground(1337, notification); } if (moreAppsPage > 1) { notificationTasks = null; pinnedList = null; } isNotificationRunning = true; } @TargetApi(21) public void lollipopNotificationSettings(NotificationCompat.Builder builder) { if (Tools.isLollipop(false)) { builder.setVisibility(Notification.VISIBILITY_PUBLIC); } } public BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction() != null && intent.getAction().equals(BCAST_CONFIGCHANGED) && runningTask != null && launcherPackage != null) { Tools.HangarLog("runningTask: " + runningTask.packageName + " launcherPackage: " + launcherPackage); if (runningTask.packageName.equals(launcherPackage)) { Tools.updateWidget(context); } } } }; }