1 /* Copyright 2016 Braden Farmer
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 package com.farmerbb.taskbar.ui;
18 import android.accessibilityservice.AccessibilityService;
19 import android.annotation.SuppressLint;
20 import android.annotation.TargetApi;
21 import android.app.ActivityManager;
22 import android.app.AlarmManager;
23 import android.app.usage.UsageEvents;
24 import android.app.usage.UsageStats;
25 import android.app.usage.UsageStatsManager;
26 import android.content.ActivityNotFoundException;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.SharedPreferences;
32 import android.content.pm.LauncherActivityInfo;
33 import android.content.pm.LauncherApps;
34 import android.content.pm.PackageManager;
35 import android.content.pm.ResolveInfo;
36 import android.graphics.Color;
37 import android.graphics.Point;
38 import android.graphics.Typeface;
39 import android.graphics.drawable.Drawable;
40 import android.net.Uri;
41 import android.os.Build;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.os.PowerManager;
45 import android.os.SystemClock;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.speech.RecognizerIntent;
49 import android.support.v4.content.ContextCompat;
50 import android.support.v4.graphics.ColorUtils;
51 import android.view.Display;
52 import android.view.Gravity;
53 import android.view.LayoutInflater;
54 import android.view.MotionEvent;
55 import android.view.PointerIcon;
56 import android.view.View;
57 import android.view.ViewGroup;
58 import android.view.WindowManager;
59 import android.view.inputmethod.InputMethodManager;
60 import android.widget.Button;
61 import android.widget.FrameLayout;
62 import android.widget.ImageView;
65 import java.lang.reflect.Field;
66 import java.util.ArrayList;
67 import java.util.Collections;
68 import java.util.List;
70 import android.support.v4.content.LocalBroadcastManager;
71 import android.widget.LinearLayout;
72 import android.widget.Space;
74 import com.farmerbb.taskbar.BuildConfig;
75 import com.farmerbb.taskbar.activity.HomeActivityDelegate;
76 import com.farmerbb.taskbar.activity.MainActivity;
77 import com.farmerbb.taskbar.R;
78 import com.farmerbb.taskbar.activity.HomeActivity;
79 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
80 import com.farmerbb.taskbar.util.AppEntry;
81 import com.farmerbb.taskbar.util.DisplayInfo;
82 import com.farmerbb.taskbar.util.FreeformHackHelper;
83 import com.farmerbb.taskbar.util.IconCache;
84 import com.farmerbb.taskbar.util.LauncherHelper;
85 import com.farmerbb.taskbar.util.PinnedBlockedApps;
86 import com.farmerbb.taskbar.util.MenuHelper;
87 import com.farmerbb.taskbar.util.U;
89 public class TaskbarController implements UIController {
91 private Context context;
92 private LinearLayout layout;
93 private ImageView startButton;
94 private LinearLayout taskbar;
95 private FrameLayout scrollView;
96 private Button button;
98 private FrameLayout dashboardButton;
99 private LinearLayout navbarButtons;
101 private Handler handler;
102 private Handler handler2;
103 private Thread thread;
104 private Thread thread2;
106 private boolean isShowingRecents = true;
107 private boolean shouldRefreshRecents = true;
108 private boolean taskbarShownTemporarily = false;
109 private boolean taskbarHiddenTemporarily = false;
110 private boolean isRefreshingRecents = false;
111 private boolean isFirstStart = true;
113 private boolean startThread2 = false;
114 private boolean stopThread2 = false;
116 private int refreshInterval = -1;
117 private long searchInterval = -1;
118 private String sortOrder = "false";
119 private boolean runningAppsOnly = false;
121 private int layoutId = R.layout.taskbar_left;
122 private int currentTaskbarPosition = 0;
123 private boolean showHideAutomagically = false;
124 private boolean positionIsVertical = false;
125 private boolean dashboardEnabled = false;
126 private boolean navbarButtonsEnabled = false;
128 private List<String> currentTaskbarIds = new ArrayList<>();
129 private List<String> currentRunningAppIds = new ArrayList<>();
130 private List<String> prevRunningAppIds = new ArrayList<>();
131 private int numOfPinnedApps = -1;
133 private View.OnClickListener ocl = view -> {
134 Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU");
135 LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
138 private BroadcastReceiver showReceiver = new BroadcastReceiver() {
140 public void onReceive(Context context, Intent intent) {
145 private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
147 public void onReceive(Context context, Intent intent) {
152 private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
154 public void onReceive(Context context, Intent intent) {
159 private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
161 public void onReceive(Context context, Intent intent) {
162 tempHideTaskbar(false);
166 private BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
168 public void onReceive(Context context, Intent intent) {
169 if(startButton.getVisibility() == View.GONE
170 && (!LauncherHelper.getInstance().isOnHomeScreen() || FreeformHackHelper.getInstance().isInFreeformWorkspace()))
171 layout.setVisibility(View.GONE);
175 private BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
177 public void onReceive(Context context, Intent intent) {
178 if(startButton.getVisibility() == View.GONE)
179 layout.setVisibility(View.VISIBLE);
183 public TaskbarController(Context context) {
184 this.context = context;
187 @TargetApi(Build.VERSION_CODES.M)
189 public void onCreateHost(UIHost host) {
190 SharedPreferences pref = U.getSharedPreferences(context);
191 if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
192 if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
195 pref.edit().putBoolean("taskbar_active", false).apply();
199 } else host.terminate();
202 @SuppressLint("RtlHardcoded")
203 private void drawTaskbar(UIHost host) {
204 IconCache.getInstance(context).clearCache();
206 // Initialize layout params
207 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
208 U.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
210 final ViewParams params = new ViewParams(
211 WindowManager.LayoutParams.WRAP_CONTENT,
212 WindowManager.LayoutParams.WRAP_CONTENT,
214 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
217 // Determine where to show the taskbar on screen
218 switch(U.getTaskbarPosition(context)) {
220 layoutId = R.layout.taskbar_left;
221 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
222 positionIsVertical = false;
224 case "bottom_vertical_left":
225 layoutId = R.layout.taskbar_vertical;
226 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
227 positionIsVertical = true;
230 layoutId = R.layout.taskbar_right;
231 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
232 positionIsVertical = false;
234 case "bottom_vertical_right":
235 layoutId = R.layout.taskbar_vertical;
236 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
237 positionIsVertical = true;
240 layoutId = R.layout.taskbar_left;
241 params.gravity = Gravity.TOP | Gravity.LEFT;
242 positionIsVertical = false;
244 case "top_vertical_left":
245 layoutId = R.layout.taskbar_top_vertical;
246 params.gravity = Gravity.TOP | Gravity.LEFT;
247 positionIsVertical = true;
250 layoutId = R.layout.taskbar_right;
251 params.gravity = Gravity.TOP | Gravity.RIGHT;
252 positionIsVertical = false;
254 case "top_vertical_right":
255 layoutId = R.layout.taskbar_top_vertical;
256 params.gravity = Gravity.TOP | Gravity.RIGHT;
257 positionIsVertical = true;
262 SharedPreferences pref = U.getSharedPreferences(context);
263 boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
265 layout = (LinearLayout) LayoutInflater.from(U.wrapContext(context)).inflate(layoutId, null);
266 taskbar = layout.findViewById(R.id.taskbar);
267 scrollView = layout.findViewById(R.id.taskbar_scrollview);
269 int backgroundTint = U.getBackgroundTint(context);
270 int accentColor = U.getAccentColor(context);
272 if(altButtonConfig) {
273 space = layout.findViewById(R.id.space_alt);
274 layout.findViewById(R.id.space).setVisibility(View.GONE);
276 space = layout.findViewById(R.id.space);
277 layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
280 space.setOnClickListener(v -> toggleTaskbar(true));
282 startButton = layout.findViewById(R.id.start_button);
285 switch(pref.getString("start_button_image", U.getDefaultStartButtonImage(context))) {
287 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
288 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
293 if(U.isBlissOs(context)) {
294 drawable = ContextCompat.getDrawable(context, R.drawable.bliss);
295 drawable.setTint(accentColor);
297 drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher);
299 startButton.setImageDrawable(drawable);
300 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
303 File file = new File(context.getFilesDir() + "/images", "custom_image");
306 startButton.setImageURI(Uri.fromFile(file));
307 } catch (Exception e) {
308 U.showToastLong(context, R.string.error_reading_custom_start_image);
309 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
312 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
314 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
318 startButton.setPadding(padding, padding, padding, padding);
319 startButton.setOnClickListener(ocl);
320 startButton.setOnLongClickListener(view -> {
325 startButton.setOnGenericMotionListener((view, motionEvent) -> {
326 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
327 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
333 refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000);
334 if(refreshInterval == 0)
335 refreshInterval = 100;
337 sortOrder = pref.getString("sort_order", "false");
338 runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only");
340 switch(pref.getString("recents_amount", "past_day")) {
342 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
345 long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis());
346 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
348 searchInterval = deviceStartTime > appStartTime ? deviceStartTime : appStartTime;
355 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
356 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
357 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.UPDATE_HOME_SCREEN_MARGINS"));
359 if(altButtonConfig) {
360 button = layout.findViewById(R.id.hide_taskbar_button_alt);
361 layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
363 button = layout.findViewById(R.id.hide_taskbar_button);
364 layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
368 button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
369 } catch (RuntimeException e) { /* Gracefully fail */ }
372 button.setOnClickListener(v -> toggleTaskbar(true));
374 LinearLayout buttonLayout = layout.findViewById(altButtonConfig
375 ? R.id.hide_taskbar_button_layout_alt
376 : R.id.hide_taskbar_button_layout);
377 if(buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar(true));
379 LinearLayout buttonLayoutToHide = layout.findViewById(altButtonConfig
380 ? R.id.hide_taskbar_button_layout
381 : R.id.hide_taskbar_button_layout_alt);
382 if(buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE);
384 dashboardButton = layout.findViewById(R.id.dashboard_button);
385 navbarButtons = layout.findViewById(R.id.navbar_buttons);
387 dashboardEnabled = pref.getBoolean("dashboard", false);
388 if(dashboardEnabled) {
389 layout.findViewById(R.id.square1).setBackgroundColor(accentColor);
390 layout.findViewById(R.id.square2).setBackgroundColor(accentColor);
391 layout.findViewById(R.id.square3).setBackgroundColor(accentColor);
392 layout.findViewById(R.id.square4).setBackgroundColor(accentColor);
393 layout.findViewById(R.id.square5).setBackgroundColor(accentColor);
394 layout.findViewById(R.id.square6).setBackgroundColor(accentColor);
396 dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD")));
398 dashboardButton.setVisibility(View.GONE);
400 if(pref.getBoolean("button_back", false)) {
401 navbarButtonsEnabled = true;
403 ImageView backButton = layout.findViewById(R.id.button_back);
404 backButton.setColorFilter(accentColor);
405 backButton.setVisibility(View.VISIBLE);
406 backButton.setOnClickListener(v -> {
407 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_BACK);
408 if(U.shouldCollapse(context, false))
412 backButton.setOnLongClickListener(v -> {
413 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
414 imm.showInputMethodPicker();
416 if(U.shouldCollapse(context, false))
422 backButton.setOnGenericMotionListener((view13, motionEvent) -> {
423 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
424 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
425 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
426 imm.showInputMethodPicker();
428 if(U.shouldCollapse(context, false))
435 if(pref.getBoolean("button_home", false)) {
436 navbarButtonsEnabled = true;
438 ImageView homeButton = layout.findViewById(R.id.button_home);
439 homeButton.setColorFilter(accentColor);
440 homeButton.setVisibility(View.VISIBLE);
441 homeButton.setOnClickListener(v -> {
442 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_HOME);
443 if(U.shouldCollapse(context, false))
447 homeButton.setOnLongClickListener(v -> {
448 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
449 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
452 context.startActivity(voiceSearchIntent);
453 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
455 if(U.shouldCollapse(context, false))
461 homeButton.setOnGenericMotionListener((view13, motionEvent) -> {
462 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
463 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
464 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
465 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
468 context.startActivity(voiceSearchIntent);
469 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
471 if(U.shouldCollapse(context, false))
478 if(pref.getBoolean("button_recents", false)) {
479 navbarButtonsEnabled = true;
481 ImageView recentsButton = layout.findViewById(R.id.button_recents);
482 recentsButton.setColorFilter(accentColor);
483 recentsButton.setVisibility(View.VISIBLE);
484 recentsButton.setOnClickListener(v -> {
485 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_RECENTS);
486 if(U.shouldCollapse(context, false))
490 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
491 recentsButton.setOnLongClickListener(v -> {
492 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
493 if(U.shouldCollapse(context, false))
499 recentsButton.setOnGenericMotionListener((view13, motionEvent) -> {
500 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
501 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
502 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
503 if(U.shouldCollapse(context, false))
511 if(!navbarButtonsEnabled)
512 navbarButtons.setVisibility(View.GONE);
514 layout.setBackgroundColor(backgroundTint);
515 layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
516 button.setTextColor(accentColor);
518 if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
520 else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
521 toggleTaskbar(false);
523 if(pref.getBoolean("auto_hide_navbar", false))
524 U.showHideNavigationBar(context, false);
526 if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
527 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
529 new Handler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
532 lbm.unregisterReceiver(showReceiver);
533 lbm.unregisterReceiver(hideReceiver);
534 lbm.unregisterReceiver(tempShowReceiver);
535 lbm.unregisterReceiver(tempHideReceiver);
536 lbm.unregisterReceiver(startMenuAppearReceiver);
537 lbm.unregisterReceiver(startMenuDisappearReceiver);
539 lbm.registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR"));
540 lbm.registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR"));
541 lbm.registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
542 lbm.registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
543 lbm.registerReceiver(startMenuAppearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_APPEARING"));
544 lbm.registerReceiver(startMenuDisappearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
546 startRefreshingRecents();
548 host.addView(layout, params);
550 isFirstStart = false;
553 private void startRefreshingRecents() {
554 if(thread != null) thread.interrupt();
557 SharedPreferences pref = U.getSharedPreferences(context);
558 showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
560 currentTaskbarIds.clear();
562 handler = new Handler();
563 thread = new Thread(() -> {
564 updateRecentApps(true);
566 if(!isRefreshingRecents) {
567 isRefreshingRecents = true;
569 while(shouldRefreshRecents) {
570 SystemClock.sleep(refreshInterval);
571 updateRecentApps(false);
573 if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
576 int[] location = new int[2];
577 layout.getLocationOnScreen(location);
579 if(location[1] != 0) {
580 if(location[1] > currentTaskbarPosition) {
581 currentTaskbarPosition = location[1];
582 } else if(location[1] < currentTaskbarPosition) {
583 if(currentTaskbarPosition - location[1] == getNavBarSize())
584 currentTaskbarPosition = location[1];
585 else if(!startThread2) {
587 tempHideTaskbar(true);
595 isRefreshingRecents = false;
602 @SuppressWarnings("Convert2streamapi")
603 @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
604 private void updateRecentApps(final boolean firstRefresh) {
605 if(isScreenOff()) return;
607 SharedPreferences pref = U.getSharedPreferences(context);
608 final PackageManager pm = context.getPackageManager();
609 final List<AppEntry> entries = new ArrayList<>();
610 List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
611 int maxNumOfEntries = U.getMaxNumOfEntries(context);
612 int realNumOfPinnedApps = 0;
613 boolean fullLength = pref.getBoolean("full_length", false);
616 currentRunningAppIds.clear();
618 PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
619 List<AppEntry> pinnedApps = setTimeLastUsedFor(pba.getPinnedApps());
620 List<AppEntry> blockedApps = pba.getBlockedApps();
621 List<String> applicationIdsToRemove = new ArrayList<>();
623 // Filter out anything on the pinned/blocked apps lists
624 if(pinnedApps.size() > 0) {
625 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
626 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
628 for(AppEntry entry : pinnedApps) {
629 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
630 userManager.getUserForSerialNumber(entry.getUserId(context)));
635 realNumOfPinnedApps--;
637 applicationIdsToRemove.add(entry.getPackageName());
640 realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
643 if(blockedApps.size() > 0) {
644 for(AppEntry entry : blockedApps) {
645 applicationIdsToRemove.add(entry.getPackageName());
649 // Get list of all recently used apps
650 List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
651 if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
652 if(realNumOfPinnedApps < maxNumOfEntries) {
653 List<AppEntry> usageStatsList2 = new ArrayList<>();
654 List<AppEntry> usageStatsList3 = new ArrayList<>();
655 List<AppEntry> usageStatsList4 = new ArrayList<>();
656 List<AppEntry> usageStatsList5 = new ArrayList<>();
657 List<AppEntry> usageStatsList6;
659 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
660 homeIntent.addCategory(Intent.CATEGORY_HOME);
661 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
663 // Filter out apps without a launcher intent
664 // Also filter out the current launcher, and Taskbar itself
665 for(AppEntry packageInfo : usageStatsList) {
666 if(hasLauncherIntent(packageInfo.getPackageName())
667 && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
668 && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName))
669 usageStatsList2.add(packageInfo);
672 // Filter out apps that don't fall within our current search interval
673 for(AppEntry stats : usageStatsList2) {
674 if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
675 usageStatsList3.add(stats);
678 // Sort apps by either most recently used, or most time used
679 if(!runningAppsOnly && sortOrder.contains("most_used")) {
680 Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
682 Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
685 // Filter out any duplicate entries
686 List<String> applicationIds = new ArrayList<>();
687 for(AppEntry stats : usageStatsList3) {
688 if(!applicationIds.contains(stats.getPackageName())) {
689 usageStatsList4.add(stats);
690 applicationIds.add(stats.getPackageName());
694 // Filter out the currently running foreground app, if requested by the user
695 if(pref.getBoolean("hide_foreground", false)) {
696 UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
697 UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
698 UsageEvents.Event eventCache = new UsageEvents.Event();
699 String currentForegroundApp = null;
701 while(events.hasNextEvent()) {
702 events.getNextEvent(eventCache);
704 if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
705 if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
706 && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
707 && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
708 && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName())))
709 currentForegroundApp = eventCache.getPackageName();
713 if(!applicationIdsToRemove.contains(currentForegroundApp))
714 applicationIdsToRemove.add(currentForegroundApp);
717 for(AppEntry stats : usageStatsList4) {
718 if(!applicationIdsToRemove.contains(stats.getPackageName())) {
719 usageStatsList5.add(stats);
723 // Truncate list to a maximum length
724 if(usageStatsList5.size() > maxNumOfEntries)
725 usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
727 usageStatsList6 = usageStatsList5;
729 // Determine if we need to reverse the order
730 boolean needToReverseOrder;
731 switch(U.getTaskbarPosition(context)) {
734 needToReverseOrder = sortOrder.contains("false");
737 needToReverseOrder = sortOrder.contains("true");
741 if(needToReverseOrder) {
742 Collections.reverse(usageStatsList6);
745 // Generate the AppEntries for the recent apps list
746 int number = usageStatsList6.size() == maxNumOfEntries
747 ? usageStatsList6.size() - realNumOfPinnedApps
748 : usageStatsList6.size();
750 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
751 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
753 final List<UserHandle> userHandles = userManager.getUserProfiles();
755 for(int i = 0; i < number; i++) {
756 for(UserHandle handle : userHandles) {
757 String packageName = usageStatsList6.get(i).getPackageName();
758 long lastTimeUsed = usageStatsList6.get(i).getLastTimeUsed();
759 List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
760 if(!list.isEmpty()) {
761 // Google App workaround
762 if(!packageName.equals("com.google.android.googlequicksearchbox"))
763 launcherAppCache.add(list.get(0));
765 boolean added = false;
766 for(LauncherActivityInfo info : list) {
767 if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
768 launcherAppCache.add(info);
773 if(!added) launcherAppCache.add(list.get(0));
776 AppEntry newEntry = new AppEntry(
784 newEntry.setUserId(userManager.getSerialNumberForUser(handle));
785 newEntry.setLastTimeUsed(lastTimeUsed);
786 entries.add(newEntry);
794 while(entries.size() > maxNumOfEntries) {
796 entries.remove(entries.size() - 1);
797 launcherAppCache.remove(launcherAppCache.size() - 1);
798 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
801 // Determine if we need to reverse the order again
802 if(U.getTaskbarPosition(context).contains("vertical")) {
803 Collections.reverse(entries);
804 Collections.reverse(launcherAppCache);
807 // Now that we've generated the list of apps,
808 // we need to determine if we need to redraw the Taskbar or not
809 boolean shouldRedrawTaskbar = firstRefresh;
811 List<String> finalApplicationIds = new ArrayList<>();
812 for(AppEntry entry : entries) {
813 finalApplicationIds.add(entry.getPackageName());
816 if(finalApplicationIds.size() != currentTaskbarIds.size()
817 || (runningAppsOnly && currentRunningAppIds.size() != prevRunningAppIds.size())
818 || numOfPinnedApps != realNumOfPinnedApps)
819 shouldRedrawTaskbar = true;
821 for(int i = 0; i < finalApplicationIds.size(); i++) {
822 if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
823 shouldRedrawTaskbar = true;
828 if(!shouldRedrawTaskbar && runningAppsOnly) {
829 for(int i = 0; i < finalApplicationIds.size(); i++) {
830 if(!currentRunningAppIds.get(i).equals(prevRunningAppIds.get(i))) {
831 shouldRedrawTaskbar = true;
838 if(shouldRedrawTaskbar) {
839 currentTaskbarIds = finalApplicationIds;
840 numOfPinnedApps = realNumOfPinnedApps;
842 if(runningAppsOnly) {
843 prevRunningAppIds.clear();
844 prevRunningAppIds.addAll(currentRunningAppIds);
847 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
849 int launcherAppCachePos = -1;
850 for(int i = 0; i < entries.size(); i++) {
851 if(entries.get(i).getComponentName() == null) {
852 launcherAppCachePos++;
853 LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
854 String packageName = entries.get(i).getPackageName();
855 long lastTimeUsed = entries.get(i).getLastTimeUsed();
859 AppEntry newEntry = new AppEntry(
861 appInfo.getComponentName().flattenToString(),
862 appInfo.getLabel().toString(),
863 IconCache.getInstance(context).getIcon(context, pm, appInfo),
866 newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
867 newEntry.setLastTimeUsed(lastTimeUsed);
868 entries.add(i, newEntry);
872 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
875 if(numOfEntries > 0 || fullLength) {
876 ViewGroup.LayoutParams params = scrollView.getLayoutParams();
877 DisplayInfo display = U.getDisplayInfo(context, true);
878 int recentsSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries;
879 float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
881 if(U.getTaskbarPosition(context).contains("vertical")) {
882 int maxScreenSize = display.height
883 - U.getStatusBarHeight(context)
884 - U.getBaseTaskbarSize(context);
886 params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
887 + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
891 Space whitespaceTop = layout.findViewById(R.id.whitespace_top);
892 Space whitespaceBottom = layout.findViewById(R.id.whitespace_bottom);
893 int height = maxScreenSize - recentsSize;
895 if(pref.getBoolean("centered_icons", false)) {
896 ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
897 topParams.height = height / 2;
898 whitespaceTop.setLayoutParams(topParams);
900 ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
901 bottomParams.height = height / 2;
902 whitespaceBottom.setLayoutParams(bottomParams);
903 } else if(U.getTaskbarPosition(context).contains("bottom")) {
904 ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
905 topParams.height = height;
906 whitespaceTop.setLayoutParams(topParams);
908 ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
909 bottomParams.height = height;
910 whitespaceBottom.setLayoutParams(bottomParams);
912 } catch (NullPointerException e) { /* Gracefully fail */ }
915 int maxScreenSize = display.width - U.getBaseTaskbarSize(context);
917 params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
918 + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
922 Space whitespaceLeft = layout.findViewById(R.id.whitespace_left);
923 Space whitespaceRight = layout.findViewById(R.id.whitespace_right);
924 int width = maxScreenSize - recentsSize;
926 if(pref.getBoolean("centered_icons", false)) {
927 ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
928 leftParams.width = width / 2;
929 whitespaceLeft.setLayoutParams(leftParams);
931 ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
932 rightParams.width = width / 2;
933 whitespaceRight.setLayoutParams(rightParams);
934 } else if(U.getTaskbarPosition(context).contains("right")) {
935 ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
936 leftParams.width = width;
937 whitespaceLeft.setLayoutParams(leftParams);
939 ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
940 rightParams.width = width;
941 whitespaceRight.setLayoutParams(rightParams);
943 } catch (NullPointerException e) { /* Gracefully fail */ }
947 scrollView.setLayoutParams(params);
949 taskbar.removeAllViews();
950 for(int i = 0; i < entries.size(); i++) {
951 taskbar.addView(getView(entries, i));
954 isShowingRecents = true;
955 if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
957 scrollView.setVisibility(View.INVISIBLE);
959 scrollView.setVisibility(View.VISIBLE);
962 if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
963 new Handler().post(() -> {
964 switch(U.getTaskbarPosition(context)) {
969 if(sortOrder.contains("false"))
970 scrollView.scrollTo(0, 0);
971 else if(sortOrder.contains("true"))
972 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
974 case "bottom_vertical_left":
975 case "bottom_vertical_right":
976 case "top_vertical_left":
977 case "top_vertical_right":
978 if(sortOrder.contains("false"))
979 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
980 else if(sortOrder.contains("true"))
981 scrollView.scrollTo(0, 0);
985 if(shouldRefreshRecents) {
986 scrollView.setVisibility(View.VISIBLE);
990 isShowingRecents = false;
991 scrollView.setVisibility(View.GONE);
995 } else if(firstRefresh || currentTaskbarIds.size() > 0) {
996 currentTaskbarIds.clear();
998 isShowingRecents = false;
999 scrollView.setVisibility(View.GONE);
1004 private void toggleTaskbar(boolean userInitiated) {
1005 if(userInitiated && Build.BRAND.equalsIgnoreCase("essential")) {
1006 SharedPreferences pref = U.getSharedPreferences(context);
1007 if(!pref.getBoolean("grip_rejection_toast_shown", false)) {
1008 U.showToastLong(context, R.string.essential_phone_grip_rejection);
1009 pref.edit().putBoolean("grip_rejection_toast_shown", true).apply();
1013 if(startButton.getVisibility() == View.GONE)
1019 private void showTaskbar(boolean clearVariables) {
1020 if(clearVariables) {
1021 taskbarShownTemporarily = false;
1022 taskbarHiddenTemporarily = false;
1025 if(startButton.getVisibility() == View.GONE) {
1026 startButton.setVisibility(View.VISIBLE);
1027 space.setVisibility(View.VISIBLE);
1029 if(dashboardEnabled)
1030 dashboardButton.setVisibility(View.VISIBLE);
1032 if(navbarButtonsEnabled)
1033 navbarButtons.setVisibility(View.VISIBLE);
1035 if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1036 scrollView.setVisibility(View.INVISIBLE);
1038 shouldRefreshRecents = true;
1039 startRefreshingRecents();
1041 SharedPreferences pref = U.getSharedPreferences(context);
1042 pref.edit().putBoolean("collapsed", true).apply();
1044 updateButton(false);
1046 new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
1050 private void hideTaskbar(boolean clearVariables) {
1051 if(clearVariables) {
1052 taskbarShownTemporarily = false;
1053 taskbarHiddenTemporarily = false;
1056 if(startButton.getVisibility() == View.VISIBLE) {
1057 startButton.setVisibility(View.GONE);
1058 space.setVisibility(View.GONE);
1060 if(dashboardEnabled)
1061 dashboardButton.setVisibility(View.GONE);
1063 if(navbarButtonsEnabled)
1064 navbarButtons.setVisibility(View.GONE);
1066 if(isShowingRecents) {
1067 scrollView.setVisibility(View.GONE);
1070 shouldRefreshRecents = false;
1071 if(thread != null) thread.interrupt();
1073 SharedPreferences pref = U.getSharedPreferences(context);
1074 pref.edit().putBoolean("collapsed", false).apply();
1078 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
1079 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD"));
1081 new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU_SPACE")));
1085 private void tempShowTaskbar() {
1086 if(!taskbarHiddenTemporarily) {
1087 SharedPreferences pref = U.getSharedPreferences(context);
1088 if(!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true;
1093 if(taskbarHiddenTemporarily)
1094 taskbarHiddenTemporarily = false;
1097 private void tempHideTaskbar(boolean monitorPositionChanges) {
1098 if(!taskbarShownTemporarily) {
1099 SharedPreferences pref = U.getSharedPreferences(context);
1100 if(pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true;
1105 if(taskbarShownTemporarily)
1106 taskbarShownTemporarily = false;
1108 if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1109 if(thread2 != null) thread2.interrupt();
1111 handler2 = new Handler();
1112 thread2 = new Thread(() -> {
1113 stopThread2 = false;
1115 while(!stopThread2) {
1116 SystemClock.sleep(refreshInterval);
1118 handler2.post(() -> stopThread2 = checkPositionChange());
1121 startThread2 = false;
1128 private boolean checkPositionChange() {
1129 if(!isScreenOff() && layout != null) {
1130 int[] location = new int[2];
1131 layout.getLocationOnScreen(location);
1133 if(location[1] == 0) {
1136 if(location[1] > currentTaskbarPosition) {
1137 currentTaskbarPosition = location[1];
1138 if(taskbarHiddenTemporarily) {
1142 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1145 } else if(location[1] < currentTaskbarPosition
1146 && currentTaskbarPosition - location[1] == getNavBarSize()) {
1147 currentTaskbarPosition = location[1];
1155 private int getNavBarSize() {
1156 Point size = new Point();
1157 Point realSize = new Point();
1159 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1160 Display display = wm.getDefaultDisplay();
1161 display.getSize(size);
1162 display.getRealSize(realSize);
1164 return realSize.y - size.y;
1168 public void onDestroyHost(UIHost host) {
1169 shouldRefreshRecents = false;
1173 host.removeView(layout);
1174 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1176 SharedPreferences pref = U.getSharedPreferences(context);
1177 if(pref.getBoolean("skip_auto_hide_navbar", false)) {
1178 pref.edit().remove("skip_auto_hide_navbar").apply();
1179 } else if(pref.getBoolean("auto_hide_navbar", false))
1180 U.showHideNavigationBar(context, true);
1182 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
1184 lbm.unregisterReceiver(showReceiver);
1185 lbm.unregisterReceiver(hideReceiver);
1186 lbm.unregisterReceiver(tempShowReceiver);
1187 lbm.unregisterReceiver(tempHideReceiver);
1188 lbm.unregisterReceiver(startMenuAppearReceiver);
1189 lbm.unregisterReceiver(startMenuDisappearReceiver);
1191 isFirstStart = true;
1194 private void openContextMenu() {
1195 SharedPreferences pref = U.getSharedPreferences(context);
1197 Bundle args = new Bundle();
1198 args.putBoolean("dont_show_quit",
1199 LauncherHelper.getInstance().isOnHomeScreen()
1200 && !pref.getBoolean("taskbar_active", false));
1201 args.putBoolean("is_start_button", true);
1203 U.startContextMenuActivity(context, args);
1206 private void updateButton(boolean isCollapsed) {
1207 SharedPreferences pref = U.getSharedPreferences(context);
1208 boolean hide = pref.getBoolean("invisible_button", false);
1210 if(button != null) button.setText(context.getString(isCollapsed ? R.string.right_arrow : R.string.left_arrow));
1211 if(layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1);
1214 @TargetApi(Build.VERSION_CODES.M)
1216 public void onRecreateHost(UIHost host) {
1217 if(layout != null) {
1219 host.removeView(layout);
1220 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1222 currentTaskbarPosition = 0;
1224 if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
1227 SharedPreferences pref = U.getSharedPreferences(context);
1228 pref.edit().putBoolean("taskbar_active", false).apply();
1235 private View getView(List<AppEntry> list, int position) {
1236 View convertView = View.inflate(context, R.layout.icon, null);
1238 final AppEntry entry = list.get(position);
1239 final SharedPreferences pref = U.getSharedPreferences(context);
1241 ImageView imageView = convertView.findViewById(R.id.icon);
1242 ImageView imageView2 = convertView.findViewById(R.id.shortcut_icon);
1243 imageView.setImageDrawable(entry.getIcon(context));
1244 imageView2.setBackgroundColor(pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white)));
1246 String taskbarPosition = U.getTaskbarPosition(context);
1247 if(pref.getBoolean("shortcut_icon", true)) {
1248 boolean shouldShowShortcutIcon;
1249 if(taskbarPosition.contains("vertical"))
1250 shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps;
1252 shouldShowShortcutIcon = position < numOfPinnedApps;
1254 if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1257 if(taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) {
1258 imageView.setRotationY(180);
1259 imageView2.setRotationY(180);
1262 FrameLayout layout = convertView.findViewById(R.id.entry);
1263 layout.setOnClickListener(view -> U.launchApp(
1272 layout.setOnLongClickListener(view -> {
1273 int[] location = new int[2];
1274 view.getLocationOnScreen(location);
1275 openContextMenu(entry, location);
1279 layout.setOnGenericMotionListener((view, motionEvent) -> {
1280 int action = motionEvent.getAction();
1282 if(action == MotionEvent.ACTION_BUTTON_PRESS
1283 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
1284 int[] location = new int[2];
1285 view.getLocationOnScreen(location);
1286 openContextMenu(entry, location);
1289 if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true))
1290 view.setBackgroundColor(0);
1295 if(pref.getBoolean("visual_feedback", true)) {
1296 layout.setOnHoverListener((v, event) -> {
1297 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
1298 int accentColor = U.getAccentColor(context);
1299 accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2);
1300 v.setBackgroundColor(accentColor);
1303 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1304 v.setBackgroundColor(0);
1306 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1307 v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
1312 layout.setOnTouchListener((v, event) -> {
1313 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1318 if(runningAppsOnly) {
1319 ImageView runningAppIndicator = convertView.findViewById(R.id.running_app_indicator);
1320 if(entry.getLastTimeUsed() > 0) {
1321 runningAppIndicator.setVisibility(View.VISIBLE);
1322 runningAppIndicator.setColorFilter(U.getAccentColor(context));
1324 runningAppIndicator.setVisibility(View.GONE);
1330 private void openContextMenu(AppEntry entry, int[] location) {
1331 Bundle args = new Bundle();
1332 args.putSerializable("app_entry", entry);
1333 args.putInt("x", location[0]);
1334 args.putInt("y", location[1]);
1336 U.startContextMenuActivity(context, args);
1339 private List<AppEntry> getAppEntries() {
1340 SharedPreferences pref = U.getSharedPreferences(context);
1342 return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10")));
1344 return getAppEntriesUsingUsageStats();
1347 @SuppressWarnings("deprecation")
1348 @TargetApi(Build.VERSION_CODES.M)
1349 private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) {
1350 ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1351 List<ActivityManager.RecentTaskInfo> usageStatsList = mActivityManager.getRecentTasks(maxNum, 0);
1352 List<AppEntry> entries = new ArrayList<>();
1354 for(int i = 0; i < usageStatsList.size(); i++) {
1355 ActivityManager.RecentTaskInfo recentTaskInfo = usageStatsList.get(i);
1356 if(recentTaskInfo.id != -1) {
1357 String packageName = recentTaskInfo.baseActivity.getPackageName();
1358 AppEntry newEntry = new AppEntry(
1367 Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1368 newEntry.setLastTimeUsed(field.getLong(recentTaskInfo));
1369 currentRunningAppIds.add(packageName);
1370 } catch (Exception e) {
1371 newEntry.setLastTimeUsed(i);
1374 entries.add(newEntry);
1381 @SuppressWarnings("deprecation")
1382 @TargetApi(Build.VERSION_CODES.M)
1383 private List<AppEntry> setTimeLastUsedFor(List<AppEntry> pinnedApps) {
1384 if(!runningAppsOnly || pinnedApps.size() == 0)
1387 ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1388 List<ActivityManager.RecentTaskInfo> recentTasks = mActivityManager.getRecentTasks(Integer.MAX_VALUE, 0);
1390 for(AppEntry entry : pinnedApps) {
1391 for(ActivityManager.RecentTaskInfo task : recentTasks) {
1392 if(task.id != -1 && task.baseActivity.getPackageName().equals(entry.getPackageName())) {
1394 Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1395 entry.setLastTimeUsed(field.getLong(task));
1396 currentRunningAppIds.add(entry.getPackageName());
1398 } catch (Exception e) { /* Gracefully fail */ }
1406 @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
1407 private List<AppEntry> getAppEntriesUsingUsageStats() {
1408 UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
1409 List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, searchInterval, System.currentTimeMillis());
1410 List<AppEntry> entries = new ArrayList<>();
1412 for(UsageStats usageStats : usageStatsList) {
1413 AppEntry newEntry = new AppEntry(
1414 usageStats.getPackageName(),
1421 newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1422 newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1423 entries.add(newEntry);
1429 private boolean hasLauncherIntent(String packageName) {
1430 Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1431 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1432 intentToResolve.setPackage(packageName);
1434 List<ResolveInfo> ris = context.getPackageManager().queryIntentActivities(intentToResolve, 0);
1435 return ris != null && ris.size() > 0;
1438 private boolean isScreenOff() {
1439 if(U.isChromeOs(context))
1442 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1443 return !pm.isInteractive();