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.bluetooth.BluetoothAdapter;
27 import android.content.ActivityNotFoundException;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.SharedPreferences;
33 import android.content.pm.LauncherActivityInfo;
34 import android.content.pm.LauncherApps;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ResolveInfo;
37 import android.graphics.Color;
38 import android.graphics.Point;
39 import android.graphics.Typeface;
40 import android.graphics.drawable.Drawable;
41 import android.net.ConnectivityManager;
42 import android.net.NetworkInfo;
43 import android.net.Uri;
44 import android.net.wifi.WifiInfo;
45 import android.net.wifi.WifiManager;
46 import android.os.BatteryManager;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.PowerManager;
51 import android.os.SystemClock;
52 import android.os.UserHandle;
53 import android.os.UserManager;
54 import android.provider.Settings;
55 import android.speech.RecognizerIntent;
56 import android.support.v4.content.ContextCompat;
57 import android.support.v4.graphics.ColorUtils;
58 import android.telephony.PhoneStateListener;
59 import android.telephony.SignalStrength;
60 import android.telephony.TelephonyManager;
61 import android.text.format.DateFormat;
62 import android.view.Display;
63 import android.view.Gravity;
64 import android.view.LayoutInflater;
65 import android.view.MotionEvent;
66 import android.view.PointerIcon;
67 import android.view.View;
68 import android.view.ViewGroup;
69 import android.view.WindowManager;
70 import android.view.inputmethod.InputMethodManager;
71 import android.widget.Button;
72 import android.widget.FrameLayout;
73 import android.widget.ImageView;
76 import java.lang.reflect.Field;
77 import java.util.ArrayList;
78 import java.util.Collections;
79 import java.util.Date;
80 import java.util.List;
82 import android.support.v4.content.LocalBroadcastManager;
83 import android.widget.LinearLayout;
84 import android.widget.Space;
85 import android.widget.TextView;
87 import com.farmerbb.taskbar.BuildConfig;
88 import com.farmerbb.taskbar.activity.HomeActivityDelegate;
89 import com.farmerbb.taskbar.activity.MainActivity;
90 import com.farmerbb.taskbar.R;
91 import com.farmerbb.taskbar.activity.HomeActivity;
92 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
93 import com.farmerbb.taskbar.util.AppEntry;
94 import com.farmerbb.taskbar.util.DisplayInfo;
95 import com.farmerbb.taskbar.util.FeatureFlags;
96 import com.farmerbb.taskbar.util.FreeformHackHelper;
97 import com.farmerbb.taskbar.util.IconCache;
98 import com.farmerbb.taskbar.util.LauncherHelper;
99 import com.farmerbb.taskbar.util.PinnedBlockedApps;
100 import com.farmerbb.taskbar.util.MenuHelper;
101 import com.farmerbb.taskbar.util.U;
103 public class TaskbarController implements UIController {
105 private Context context;
106 private LinearLayout layout;
107 private ImageView startButton;
108 private LinearLayout taskbar;
109 private FrameLayout scrollView;
110 private Button button;
112 private FrameLayout dashboardButton;
113 private LinearLayout navbarButtons;
114 private LinearLayout sysTrayLayout;
116 private Handler handler;
117 private Handler handler2;
118 private Thread thread;
119 private Thread thread2;
121 private boolean isShowingRecents = true;
122 private boolean shouldRefreshRecents = true;
123 private boolean taskbarShownTemporarily = false;
124 private boolean taskbarHiddenTemporarily = false;
125 private boolean isRefreshingRecents = false;
126 private boolean isFirstStart = true;
128 private boolean startThread2 = false;
129 private boolean stopThread2 = false;
131 private int refreshInterval = -1;
132 private long searchInterval = -1;
133 private String sortOrder = "false";
134 private boolean runningAppsOnly = false;
136 private int layoutId = R.layout.taskbar_left;
137 private int currentTaskbarPosition = 0;
138 private boolean showHideAutomagically = false;
139 private boolean positionIsVertical = false;
140 private boolean dashboardEnabled = false;
141 private boolean navbarButtonsEnabled = false;
142 private boolean sysTrayEnabled = false;
144 private List<String> currentTaskbarIds = new ArrayList<>();
145 private List<String> currentRunningAppIds = new ArrayList<>();
146 private List<String> prevRunningAppIds = new ArrayList<>();
147 private int numOfPinnedApps = -1;
149 private int cellStrength = -1;
151 private View.OnClickListener ocl = view -> {
152 Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU");
153 LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
156 private BroadcastReceiver showReceiver = new BroadcastReceiver() {
158 public void onReceive(Context context, Intent intent) {
163 private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
165 public void onReceive(Context context, Intent intent) {
170 private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
172 public void onReceive(Context context, Intent intent) {
177 private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
179 public void onReceive(Context context, Intent intent) {
180 tempHideTaskbar(false);
184 private BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
186 public void onReceive(Context context, Intent intent) {
187 if(startButton.getVisibility() == View.GONE
188 && (!LauncherHelper.getInstance().isOnHomeScreen() || FreeformHackHelper.getInstance().isInFreeformWorkspace()))
189 layout.setVisibility(View.GONE);
193 private BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
195 public void onReceive(Context context, Intent intent) {
196 if(startButton.getVisibility() == View.GONE)
197 layout.setVisibility(View.VISIBLE);
201 @TargetApi(Build.VERSION_CODES.M)
202 private PhoneStateListener listener = new PhoneStateListener() {
204 public void onSignalStrengthsChanged(SignalStrength signalStrength) {
205 cellStrength = signalStrength.getLevel();
209 public TaskbarController(Context context) {
210 this.context = context;
213 @TargetApi(Build.VERSION_CODES.M)
215 public void onCreateHost(UIHost host) {
216 SharedPreferences pref = U.getSharedPreferences(context);
217 if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
218 if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
221 pref.edit().putBoolean("taskbar_active", false).apply();
225 } else host.terminate();
228 @SuppressLint("RtlHardcoded")
229 private void drawTaskbar(UIHost host) {
230 IconCache.getInstance(context).clearCache();
232 // Initialize layout params
233 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
234 U.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
236 final ViewParams params = new ViewParams(
237 WindowManager.LayoutParams.WRAP_CONTENT,
238 WindowManager.LayoutParams.WRAP_CONTENT,
240 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
243 // Determine where to show the taskbar on screen
244 switch(U.getTaskbarPosition(context)) {
246 layoutId = R.layout.taskbar_left;
247 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
248 positionIsVertical = false;
250 case "bottom_vertical_left":
251 layoutId = R.layout.taskbar_vertical;
252 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
253 positionIsVertical = true;
256 layoutId = R.layout.taskbar_right;
257 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
258 positionIsVertical = false;
260 case "bottom_vertical_right":
261 layoutId = R.layout.taskbar_vertical;
262 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
263 positionIsVertical = true;
266 layoutId = R.layout.taskbar_left;
267 params.gravity = Gravity.TOP | Gravity.LEFT;
268 positionIsVertical = false;
270 case "top_vertical_left":
271 layoutId = R.layout.taskbar_top_vertical;
272 params.gravity = Gravity.TOP | Gravity.LEFT;
273 positionIsVertical = true;
276 layoutId = R.layout.taskbar_right;
277 params.gravity = Gravity.TOP | Gravity.RIGHT;
278 positionIsVertical = false;
280 case "top_vertical_right":
281 layoutId = R.layout.taskbar_top_vertical;
282 params.gravity = Gravity.TOP | Gravity.RIGHT;
283 positionIsVertical = true;
288 SharedPreferences pref = U.getSharedPreferences(context);
289 boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
291 layout = (LinearLayout) LayoutInflater.from(U.wrapContext(context)).inflate(layoutId, null);
292 taskbar = layout.findViewById(R.id.taskbar);
293 scrollView = layout.findViewById(R.id.taskbar_scrollview);
295 int backgroundTint = U.getBackgroundTint(context);
296 int accentColor = U.getAccentColor(context);
298 if(altButtonConfig) {
299 space = layout.findViewById(R.id.space_alt);
300 layout.findViewById(R.id.space).setVisibility(View.GONE);
302 space = layout.findViewById(R.id.space);
303 layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
306 space.setOnClickListener(v -> toggleTaskbar(true));
308 startButton = layout.findViewById(R.id.start_button);
311 switch(pref.getString("start_button_image", U.getDefaultStartButtonImage(context))) {
313 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
314 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
319 if(U.isBlissOs(context)) {
320 drawable = ContextCompat.getDrawable(context, R.drawable.bliss);
321 drawable.setTint(accentColor);
323 drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher);
325 startButton.setImageDrawable(drawable);
326 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
329 File file = new File(context.getFilesDir() + "/images", "custom_image");
332 startButton.setImageURI(Uri.fromFile(file));
333 } catch (Exception e) {
334 U.showToastLong(context, R.string.error_reading_custom_start_image);
335 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
338 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
340 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
344 startButton.setPadding(padding, padding, padding, padding);
345 startButton.setOnClickListener(ocl);
346 startButton.setOnLongClickListener(view -> {
351 startButton.setOnGenericMotionListener((view, motionEvent) -> {
352 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
353 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
359 refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000);
360 if(refreshInterval == 0)
361 refreshInterval = 100;
363 sortOrder = pref.getString("sort_order", "false");
364 runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only");
366 switch(pref.getString("recents_amount", "past_day")) {
368 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
371 long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis());
372 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
374 searchInterval = deviceStartTime > appStartTime ? deviceStartTime : appStartTime;
381 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
382 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
383 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.UPDATE_HOME_SCREEN_MARGINS"));
385 if(altButtonConfig) {
386 button = layout.findViewById(R.id.hide_taskbar_button_alt);
387 layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
389 button = layout.findViewById(R.id.hide_taskbar_button);
390 layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
394 button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
395 } catch (RuntimeException e) { /* Gracefully fail */ }
398 button.setOnClickListener(v -> toggleTaskbar(true));
400 LinearLayout buttonLayout = layout.findViewById(altButtonConfig
401 ? R.id.hide_taskbar_button_layout_alt
402 : R.id.hide_taskbar_button_layout);
403 if(buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar(true));
405 LinearLayout buttonLayoutToHide = layout.findViewById(altButtonConfig
406 ? R.id.hide_taskbar_button_layout
407 : R.id.hide_taskbar_button_layout_alt);
408 if(buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE);
410 dashboardButton = layout.findViewById(R.id.dashboard_button);
411 navbarButtons = layout.findViewById(R.id.navbar_buttons);
413 dashboardEnabled = pref.getBoolean("dashboard", false);
414 if(dashboardEnabled) {
415 layout.findViewById(R.id.square1).setBackgroundColor(accentColor);
416 layout.findViewById(R.id.square2).setBackgroundColor(accentColor);
417 layout.findViewById(R.id.square3).setBackgroundColor(accentColor);
418 layout.findViewById(R.id.square4).setBackgroundColor(accentColor);
419 layout.findViewById(R.id.square5).setBackgroundColor(accentColor);
420 layout.findViewById(R.id.square6).setBackgroundColor(accentColor);
422 dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD")));
424 dashboardButton.setVisibility(View.GONE);
426 if(pref.getBoolean("button_back", false)) {
427 navbarButtonsEnabled = true;
429 ImageView backButton = layout.findViewById(R.id.button_back);
430 backButton.setColorFilter(accentColor);
431 backButton.setVisibility(View.VISIBLE);
432 backButton.setOnClickListener(v -> {
433 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_BACK);
434 if(U.shouldCollapse(context, false))
438 backButton.setOnLongClickListener(v -> {
439 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
440 imm.showInputMethodPicker();
442 if(U.shouldCollapse(context, false))
448 backButton.setOnGenericMotionListener((view13, motionEvent) -> {
449 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
450 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
451 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
452 imm.showInputMethodPicker();
454 if(U.shouldCollapse(context, false))
461 if(pref.getBoolean("button_home", false)) {
462 navbarButtonsEnabled = true;
464 ImageView homeButton = layout.findViewById(R.id.button_home);
465 homeButton.setColorFilter(accentColor);
466 homeButton.setVisibility(View.VISIBLE);
467 homeButton.setOnClickListener(v -> {
468 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_HOME);
469 if(U.shouldCollapse(context, false))
473 homeButton.setOnLongClickListener(v -> {
474 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
475 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
478 context.startActivity(voiceSearchIntent);
479 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
481 if(U.shouldCollapse(context, false))
487 homeButton.setOnGenericMotionListener((view13, motionEvent) -> {
488 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
489 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
490 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
491 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
494 context.startActivity(voiceSearchIntent);
495 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
497 if(U.shouldCollapse(context, false))
504 if(pref.getBoolean("button_recents", false)) {
505 navbarButtonsEnabled = true;
507 ImageView recentsButton = layout.findViewById(R.id.button_recents);
508 recentsButton.setColorFilter(accentColor);
509 recentsButton.setVisibility(View.VISIBLE);
510 recentsButton.setOnClickListener(v -> {
511 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_RECENTS);
512 if(U.shouldCollapse(context, false))
516 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
517 recentsButton.setOnLongClickListener(v -> {
518 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
519 if(U.shouldCollapse(context, false))
525 recentsButton.setOnGenericMotionListener((view13, motionEvent) -> {
526 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
527 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
528 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
529 if(U.shouldCollapse(context, false))
537 if(!navbarButtonsEnabled)
538 navbarButtons.setVisibility(View.GONE);
540 sysTrayEnabled = FeatureFlags.SYSTEM_TRAY && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !positionIsVertical;
543 sysTrayLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.system_tray, null);
544 sysTrayLayout.setLayoutParams(new FrameLayout.LayoutParams(
545 FrameLayout.LayoutParams.WRAP_CONTENT,
546 context.getResources().getDimensionPixelSize(R.dimen.icon_size)
549 ((FrameLayout) layout.findViewById(R.id.add_systray_here)).addView(sysTrayLayout);
551 TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
552 manager.listen(listener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
555 layout.setBackgroundColor(backgroundTint);
556 layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
557 button.setTextColor(accentColor);
559 if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
561 else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
562 toggleTaskbar(false);
564 if(pref.getBoolean("auto_hide_navbar", false))
565 U.showHideNavigationBar(context, false);
567 if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
568 lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
570 new Handler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
573 lbm.unregisterReceiver(showReceiver);
574 lbm.unregisterReceiver(hideReceiver);
575 lbm.unregisterReceiver(tempShowReceiver);
576 lbm.unregisterReceiver(tempHideReceiver);
577 lbm.unregisterReceiver(startMenuAppearReceiver);
578 lbm.unregisterReceiver(startMenuDisappearReceiver);
580 lbm.registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR"));
581 lbm.registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR"));
582 lbm.registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
583 lbm.registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
584 lbm.registerReceiver(startMenuAppearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_APPEARING"));
585 lbm.registerReceiver(startMenuDisappearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
587 startRefreshingRecents();
589 host.addView(layout, params);
591 isFirstStart = false;
594 private void startRefreshingRecents() {
595 if(thread != null) thread.interrupt();
598 SharedPreferences pref = U.getSharedPreferences(context);
599 showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
601 currentTaskbarIds.clear();
603 handler = new Handler();
604 thread = new Thread(() -> {
606 updateRecentApps(true);
608 if(!isRefreshingRecents) {
609 isRefreshingRecents = true;
611 while(shouldRefreshRecents) {
612 SystemClock.sleep(refreshInterval);
614 updateRecentApps(false);
616 if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
619 int[] location = new int[2];
620 layout.getLocationOnScreen(location);
622 if(location[1] != 0) {
623 if(location[1] > currentTaskbarPosition) {
624 currentTaskbarPosition = location[1];
625 } else if(location[1] < currentTaskbarPosition) {
626 if(currentTaskbarPosition - location[1] == getNavBarSize())
627 currentTaskbarPosition = location[1];
628 else if(!startThread2) {
630 tempHideTaskbar(true);
638 isRefreshingRecents = false;
645 @SuppressWarnings("Convert2streamapi")
646 @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
647 private void updateRecentApps(final boolean firstRefresh) {
648 if(isScreenOff()) return;
650 SharedPreferences pref = U.getSharedPreferences(context);
651 final PackageManager pm = context.getPackageManager();
652 final List<AppEntry> entries = new ArrayList<>();
653 List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
654 int maxNumOfEntries = U.getMaxNumOfEntries(context);
655 int realNumOfPinnedApps = 0;
656 boolean fullLength = pref.getBoolean("full_length", false);
659 currentRunningAppIds.clear();
661 PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
662 List<AppEntry> pinnedApps = setTimeLastUsedFor(pba.getPinnedApps());
663 List<AppEntry> blockedApps = pba.getBlockedApps();
664 List<String> applicationIdsToRemove = new ArrayList<>();
666 // Filter out anything on the pinned/blocked apps lists
667 if(pinnedApps.size() > 0) {
668 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
669 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
671 for(AppEntry entry : pinnedApps) {
672 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
673 userManager.getUserForSerialNumber(entry.getUserId(context)));
678 realNumOfPinnedApps--;
680 applicationIdsToRemove.add(entry.getPackageName());
683 realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
686 if(blockedApps.size() > 0) {
687 for(AppEntry entry : blockedApps) {
688 applicationIdsToRemove.add(entry.getPackageName());
692 // Get list of all recently used apps
693 List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
694 if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
695 if(realNumOfPinnedApps < maxNumOfEntries) {
696 List<AppEntry> usageStatsList2 = new ArrayList<>();
697 List<AppEntry> usageStatsList3 = new ArrayList<>();
698 List<AppEntry> usageStatsList4 = new ArrayList<>();
699 List<AppEntry> usageStatsList5 = new ArrayList<>();
700 List<AppEntry> usageStatsList6;
702 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
703 homeIntent.addCategory(Intent.CATEGORY_HOME);
704 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
706 // Filter out apps without a launcher intent
707 // Also filter out the current launcher, and Taskbar itself
708 for(AppEntry packageInfo : usageStatsList) {
709 if(hasLauncherIntent(packageInfo.getPackageName())
710 && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
711 && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName))
712 usageStatsList2.add(packageInfo);
715 // Filter out apps that don't fall within our current search interval
716 for(AppEntry stats : usageStatsList2) {
717 if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
718 usageStatsList3.add(stats);
721 // Sort apps by either most recently used, or most time used
722 if(!runningAppsOnly && sortOrder.contains("most_used")) {
723 Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
725 Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
728 // Filter out any duplicate entries
729 List<String> applicationIds = new ArrayList<>();
730 for(AppEntry stats : usageStatsList3) {
731 if(!applicationIds.contains(stats.getPackageName())) {
732 usageStatsList4.add(stats);
733 applicationIds.add(stats.getPackageName());
737 // Filter out the currently running foreground app, if requested by the user
738 if(pref.getBoolean("hide_foreground", false)) {
739 UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
740 UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
741 UsageEvents.Event eventCache = new UsageEvents.Event();
742 String currentForegroundApp = null;
744 while(events.hasNextEvent()) {
745 events.getNextEvent(eventCache);
747 if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
748 if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
749 && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
750 && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
751 && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName())))
752 currentForegroundApp = eventCache.getPackageName();
756 if(!applicationIdsToRemove.contains(currentForegroundApp))
757 applicationIdsToRemove.add(currentForegroundApp);
760 for(AppEntry stats : usageStatsList4) {
761 if(!applicationIdsToRemove.contains(stats.getPackageName())) {
762 usageStatsList5.add(stats);
766 // Truncate list to a maximum length
767 if(usageStatsList5.size() > maxNumOfEntries)
768 usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
770 usageStatsList6 = usageStatsList5;
772 // Determine if we need to reverse the order
773 boolean needToReverseOrder;
774 switch(U.getTaskbarPosition(context)) {
777 needToReverseOrder = sortOrder.contains("false");
780 needToReverseOrder = sortOrder.contains("true");
784 if(needToReverseOrder) {
785 Collections.reverse(usageStatsList6);
788 // Generate the AppEntries for the recent apps list
789 int number = usageStatsList6.size() == maxNumOfEntries
790 ? usageStatsList6.size() - realNumOfPinnedApps
791 : usageStatsList6.size();
793 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
794 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
796 final List<UserHandle> userHandles = userManager.getUserProfiles();
798 for(int i = 0; i < number; i++) {
799 for(UserHandle handle : userHandles) {
800 String packageName = usageStatsList6.get(i).getPackageName();
801 long lastTimeUsed = usageStatsList6.get(i).getLastTimeUsed();
802 List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
803 if(!list.isEmpty()) {
804 // Google App workaround
805 if(!packageName.equals("com.google.android.googlequicksearchbox"))
806 launcherAppCache.add(list.get(0));
808 boolean added = false;
809 for(LauncherActivityInfo info : list) {
810 if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
811 launcherAppCache.add(info);
816 if(!added) launcherAppCache.add(list.get(0));
819 AppEntry newEntry = new AppEntry(
827 newEntry.setUserId(userManager.getSerialNumberForUser(handle));
828 newEntry.setLastTimeUsed(lastTimeUsed);
829 entries.add(newEntry);
837 while(entries.size() > maxNumOfEntries) {
839 entries.remove(entries.size() - 1);
840 launcherAppCache.remove(launcherAppCache.size() - 1);
841 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
844 // Determine if we need to reverse the order again
845 if(U.getTaskbarPosition(context).contains("vertical")) {
846 Collections.reverse(entries);
847 Collections.reverse(launcherAppCache);
850 // Now that we've generated the list of apps,
851 // we need to determine if we need to redraw the Taskbar or not
852 boolean shouldRedrawTaskbar = firstRefresh;
854 List<String> finalApplicationIds = new ArrayList<>();
855 for(AppEntry entry : entries) {
856 finalApplicationIds.add(entry.getPackageName());
859 if(finalApplicationIds.size() != currentTaskbarIds.size()
860 || (runningAppsOnly && currentRunningAppIds.size() != prevRunningAppIds.size())
861 || numOfPinnedApps != realNumOfPinnedApps)
862 shouldRedrawTaskbar = true;
864 for(int i = 0; i < finalApplicationIds.size(); i++) {
865 if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
866 shouldRedrawTaskbar = true;
871 if(!shouldRedrawTaskbar && runningAppsOnly) {
872 for(int i = 0; i < finalApplicationIds.size(); i++) {
873 if(!currentRunningAppIds.get(i).equals(prevRunningAppIds.get(i))) {
874 shouldRedrawTaskbar = true;
881 if(shouldRedrawTaskbar) {
882 currentTaskbarIds = finalApplicationIds;
883 numOfPinnedApps = realNumOfPinnedApps;
885 if(runningAppsOnly) {
886 prevRunningAppIds.clear();
887 prevRunningAppIds.addAll(currentRunningAppIds);
890 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
892 int launcherAppCachePos = -1;
893 for(int i = 0; i < entries.size(); i++) {
894 if(entries.get(i).getComponentName() == null) {
895 launcherAppCachePos++;
896 LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
897 String packageName = entries.get(i).getPackageName();
898 long lastTimeUsed = entries.get(i).getLastTimeUsed();
902 AppEntry newEntry = new AppEntry(
904 appInfo.getComponentName().flattenToString(),
905 appInfo.getLabel().toString(),
906 IconCache.getInstance(context).getIcon(context, pm, appInfo),
909 newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
910 newEntry.setLastTimeUsed(lastTimeUsed);
911 entries.add(i, newEntry);
915 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
918 if(numOfEntries > 0 || fullLength) {
919 ViewGroup.LayoutParams params = scrollView.getLayoutParams();
920 DisplayInfo display = U.getDisplayInfo(context, true);
921 int recentsSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries;
922 float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
924 if(U.getTaskbarPosition(context).contains("vertical")) {
925 int maxScreenSize = display.height
926 - U.getStatusBarHeight(context)
927 - U.getBaseTaskbarSize(context);
929 params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
930 + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
934 Space whitespaceTop = layout.findViewById(R.id.whitespace_top);
935 Space whitespaceBottom = layout.findViewById(R.id.whitespace_bottom);
936 int height = maxScreenSize - recentsSize;
938 if(pref.getBoolean("centered_icons", false)) {
939 ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
940 topParams.height = height / 2;
941 whitespaceTop.setLayoutParams(topParams);
943 ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
944 bottomParams.height = height / 2;
945 whitespaceBottom.setLayoutParams(bottomParams);
946 } else if(U.getTaskbarPosition(context).contains("bottom")) {
947 ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
948 topParams.height = height;
949 whitespaceTop.setLayoutParams(topParams);
951 ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
952 bottomParams.height = height;
953 whitespaceBottom.setLayoutParams(bottomParams);
955 } catch (NullPointerException e) { /* Gracefully fail */ }
958 int maxScreenSize = display.width - U.getBaseTaskbarSize(context);
960 params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
961 + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
965 Space whitespaceLeft = layout.findViewById(R.id.whitespace_left);
966 Space whitespaceRight = layout.findViewById(R.id.whitespace_right);
967 int width = maxScreenSize - recentsSize;
969 if(pref.getBoolean("centered_icons", false)) {
970 ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
971 leftParams.width = width / 2;
972 whitespaceLeft.setLayoutParams(leftParams);
974 ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
975 rightParams.width = width / 2;
976 whitespaceRight.setLayoutParams(rightParams);
977 } else if(U.getTaskbarPosition(context).contains("right")) {
978 ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
979 leftParams.width = width;
980 whitespaceLeft.setLayoutParams(leftParams);
982 ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
983 rightParams.width = width;
984 whitespaceRight.setLayoutParams(rightParams);
986 } catch (NullPointerException e) { /* Gracefully fail */ }
990 scrollView.setLayoutParams(params);
992 taskbar.removeAllViews();
993 for(int i = 0; i < entries.size(); i++) {
994 taskbar.addView(getView(entries, i));
997 isShowingRecents = true;
998 if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
1000 scrollView.setVisibility(View.INVISIBLE);
1002 scrollView.setVisibility(View.VISIBLE);
1005 if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
1006 new Handler().post(() -> {
1007 switch(U.getTaskbarPosition(context)) {
1009 case "bottom_right":
1012 if(sortOrder.contains("false"))
1013 scrollView.scrollTo(0, 0);
1014 else if(sortOrder.contains("true"))
1015 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1017 case "bottom_vertical_left":
1018 case "bottom_vertical_right":
1019 case "top_vertical_left":
1020 case "top_vertical_right":
1021 if(sortOrder.contains("false"))
1022 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1023 else if(sortOrder.contains("true"))
1024 scrollView.scrollTo(0, 0);
1028 if(shouldRefreshRecents) {
1029 scrollView.setVisibility(View.VISIBLE);
1033 isShowingRecents = false;
1034 scrollView.setVisibility(View.GONE);
1038 } else if(firstRefresh || currentTaskbarIds.size() > 0) {
1039 currentTaskbarIds.clear();
1040 handler.post(() -> {
1041 isShowingRecents = false;
1042 scrollView.setVisibility(View.GONE);
1047 private void toggleTaskbar(boolean userInitiated) {
1048 if(userInitiated && Build.BRAND.equalsIgnoreCase("essential")) {
1049 SharedPreferences pref = U.getSharedPreferences(context);
1050 if(!pref.getBoolean("grip_rejection_toast_shown", false)) {
1051 U.showToastLong(context, R.string.essential_phone_grip_rejection);
1052 pref.edit().putBoolean("grip_rejection_toast_shown", true).apply();
1056 if(startButton.getVisibility() == View.GONE)
1062 private void showTaskbar(boolean clearVariables) {
1063 if(clearVariables) {
1064 taskbarShownTemporarily = false;
1065 taskbarHiddenTemporarily = false;
1068 if(startButton.getVisibility() == View.GONE) {
1069 startButton.setVisibility(View.VISIBLE);
1070 space.setVisibility(View.VISIBLE);
1072 if(dashboardEnabled)
1073 dashboardButton.setVisibility(View.VISIBLE);
1075 if(navbarButtonsEnabled)
1076 navbarButtons.setVisibility(View.VISIBLE);
1078 if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1079 scrollView.setVisibility(View.INVISIBLE);
1082 sysTrayLayout.setVisibility(View.VISIBLE);
1084 shouldRefreshRecents = true;
1085 startRefreshingRecents();
1087 SharedPreferences pref = U.getSharedPreferences(context);
1088 pref.edit().putBoolean("collapsed", true).apply();
1090 updateButton(false);
1092 new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
1096 private void hideTaskbar(boolean clearVariables) {
1097 if(clearVariables) {
1098 taskbarShownTemporarily = false;
1099 taskbarHiddenTemporarily = false;
1102 if(startButton.getVisibility() == View.VISIBLE) {
1103 startButton.setVisibility(View.GONE);
1104 space.setVisibility(View.GONE);
1106 if(dashboardEnabled)
1107 dashboardButton.setVisibility(View.GONE);
1109 if(navbarButtonsEnabled)
1110 navbarButtons.setVisibility(View.GONE);
1112 if(isShowingRecents)
1113 scrollView.setVisibility(View.GONE);
1116 sysTrayLayout.setVisibility(View.GONE);
1118 shouldRefreshRecents = false;
1119 if(thread != null) thread.interrupt();
1121 SharedPreferences pref = U.getSharedPreferences(context);
1122 pref.edit().putBoolean("collapsed", false).apply();
1126 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
1127 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD"));
1129 new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU_SPACE")));
1133 private void tempShowTaskbar() {
1134 if(!taskbarHiddenTemporarily) {
1135 SharedPreferences pref = U.getSharedPreferences(context);
1136 if(!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true;
1141 if(taskbarHiddenTemporarily)
1142 taskbarHiddenTemporarily = false;
1145 private void tempHideTaskbar(boolean monitorPositionChanges) {
1146 if(!taskbarShownTemporarily) {
1147 SharedPreferences pref = U.getSharedPreferences(context);
1148 if(pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true;
1153 if(taskbarShownTemporarily)
1154 taskbarShownTemporarily = false;
1156 if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1157 if(thread2 != null) thread2.interrupt();
1159 handler2 = new Handler();
1160 thread2 = new Thread(() -> {
1161 stopThread2 = false;
1163 while(!stopThread2) {
1164 SystemClock.sleep(refreshInterval);
1166 handler2.post(() -> stopThread2 = checkPositionChange());
1169 startThread2 = false;
1176 private boolean checkPositionChange() {
1177 if(!isScreenOff() && layout != null) {
1178 int[] location = new int[2];
1179 layout.getLocationOnScreen(location);
1181 if(location[1] == 0) {
1184 if(location[1] > currentTaskbarPosition) {
1185 currentTaskbarPosition = location[1];
1186 if(taskbarHiddenTemporarily) {
1190 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1193 } else if(location[1] < currentTaskbarPosition
1194 && currentTaskbarPosition - location[1] == getNavBarSize()) {
1195 currentTaskbarPosition = location[1];
1203 private int getNavBarSize() {
1204 Point size = new Point();
1205 Point realSize = new Point();
1207 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1208 Display display = wm.getDefaultDisplay();
1209 display.getSize(size);
1210 display.getRealSize(realSize);
1212 return realSize.y - size.y;
1216 public void onDestroyHost(UIHost host) {
1217 shouldRefreshRecents = false;
1221 host.removeView(layout);
1222 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1224 SharedPreferences pref = U.getSharedPreferences(context);
1225 if(pref.getBoolean("skip_auto_hide_navbar", false)) {
1226 pref.edit().remove("skip_auto_hide_navbar").apply();
1227 } else if(pref.getBoolean("auto_hide_navbar", false))
1228 U.showHideNavigationBar(context, true);
1230 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
1232 lbm.unregisterReceiver(showReceiver);
1233 lbm.unregisterReceiver(hideReceiver);
1234 lbm.unregisterReceiver(tempShowReceiver);
1235 lbm.unregisterReceiver(tempHideReceiver);
1236 lbm.unregisterReceiver(startMenuAppearReceiver);
1237 lbm.unregisterReceiver(startMenuDisappearReceiver);
1239 if(sysTrayEnabled) {
1240 TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1241 manager.listen(listener, PhoneStateListener.LISTEN_NONE);
1244 isFirstStart = true;
1247 private void openContextMenu() {
1248 SharedPreferences pref = U.getSharedPreferences(context);
1250 Bundle args = new Bundle();
1251 args.putBoolean("dont_show_quit",
1252 LauncherHelper.getInstance().isOnHomeScreen()
1253 && !pref.getBoolean("taskbar_active", false));
1254 args.putBoolean("is_start_button", true);
1256 U.startContextMenuActivity(context, args);
1259 private void updateButton(boolean isCollapsed) {
1260 SharedPreferences pref = U.getSharedPreferences(context);
1261 boolean hide = pref.getBoolean("invisible_button", false);
1263 if(button != null) button.setText(context.getString(isCollapsed ? R.string.right_arrow : R.string.left_arrow));
1264 if(layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1);
1267 @TargetApi(Build.VERSION_CODES.M)
1269 public void onRecreateHost(UIHost host) {
1270 if(layout != null) {
1272 host.removeView(layout);
1273 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1275 currentTaskbarPosition = 0;
1277 if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
1280 SharedPreferences pref = U.getSharedPreferences(context);
1281 pref.edit().putBoolean("taskbar_active", false).apply();
1288 private View getView(List<AppEntry> list, int position) {
1289 View convertView = View.inflate(context, R.layout.icon, null);
1291 final AppEntry entry = list.get(position);
1292 final SharedPreferences pref = U.getSharedPreferences(context);
1294 ImageView imageView = convertView.findViewById(R.id.icon);
1295 ImageView imageView2 = convertView.findViewById(R.id.shortcut_icon);
1296 imageView.setImageDrawable(entry.getIcon(context));
1297 imageView2.setBackgroundColor(pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white)));
1299 String taskbarPosition = U.getTaskbarPosition(context);
1300 if(pref.getBoolean("shortcut_icon", true)) {
1301 boolean shouldShowShortcutIcon;
1302 if(taskbarPosition.contains("vertical"))
1303 shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps;
1305 shouldShowShortcutIcon = position < numOfPinnedApps;
1307 if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1310 if(taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) {
1311 imageView.setRotationY(180);
1312 imageView2.setRotationY(180);
1315 FrameLayout layout = convertView.findViewById(R.id.entry);
1316 layout.setOnClickListener(view -> U.launchApp(
1325 layout.setOnLongClickListener(view -> {
1326 int[] location = new int[2];
1327 view.getLocationOnScreen(location);
1328 openContextMenu(entry, location);
1332 layout.setOnGenericMotionListener((view, motionEvent) -> {
1333 int action = motionEvent.getAction();
1335 if(action == MotionEvent.ACTION_BUTTON_PRESS
1336 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
1337 int[] location = new int[2];
1338 view.getLocationOnScreen(location);
1339 openContextMenu(entry, location);
1342 if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true))
1343 view.setBackgroundColor(0);
1348 if(pref.getBoolean("visual_feedback", true)) {
1349 layout.setOnHoverListener((v, event) -> {
1350 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
1351 int accentColor = U.getAccentColor(context);
1352 accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2);
1353 v.setBackgroundColor(accentColor);
1356 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1357 v.setBackgroundColor(0);
1359 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1360 v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
1365 layout.setOnTouchListener((v, event) -> {
1366 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1371 if(runningAppsOnly) {
1372 ImageView runningAppIndicator = convertView.findViewById(R.id.running_app_indicator);
1373 if(entry.getLastTimeUsed() > 0) {
1374 runningAppIndicator.setVisibility(View.VISIBLE);
1375 runningAppIndicator.setColorFilter(U.getAccentColor(context));
1377 runningAppIndicator.setVisibility(View.GONE);
1383 private void openContextMenu(AppEntry entry, int[] location) {
1384 Bundle args = new Bundle();
1385 args.putSerializable("app_entry", entry);
1386 args.putInt("x", location[0]);
1387 args.putInt("y", location[1]);
1389 U.startContextMenuActivity(context, args);
1392 private List<AppEntry> getAppEntries() {
1393 SharedPreferences pref = U.getSharedPreferences(context);
1395 return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10")));
1397 return getAppEntriesUsingUsageStats();
1400 @SuppressWarnings("deprecation")
1401 @TargetApi(Build.VERSION_CODES.M)
1402 private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) {
1403 ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1404 List<ActivityManager.RecentTaskInfo> usageStatsList = mActivityManager.getRecentTasks(maxNum, 0);
1405 List<AppEntry> entries = new ArrayList<>();
1407 for(int i = 0; i < usageStatsList.size(); i++) {
1408 ActivityManager.RecentTaskInfo recentTaskInfo = usageStatsList.get(i);
1409 if(recentTaskInfo.id != -1) {
1410 String packageName = recentTaskInfo.baseActivity.getPackageName();
1411 AppEntry newEntry = new AppEntry(
1420 Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1421 newEntry.setLastTimeUsed(field.getLong(recentTaskInfo));
1422 currentRunningAppIds.add(packageName);
1423 } catch (Exception e) {
1424 newEntry.setLastTimeUsed(i);
1427 entries.add(newEntry);
1434 @SuppressWarnings("deprecation")
1435 @TargetApi(Build.VERSION_CODES.M)
1436 private List<AppEntry> setTimeLastUsedFor(List<AppEntry> pinnedApps) {
1437 if(!runningAppsOnly || pinnedApps.size() == 0)
1440 ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1441 List<ActivityManager.RecentTaskInfo> recentTasks = mActivityManager.getRecentTasks(Integer.MAX_VALUE, 0);
1443 for(AppEntry entry : pinnedApps) {
1444 for(ActivityManager.RecentTaskInfo task : recentTasks) {
1445 if(task.id != -1 && task.baseActivity.getPackageName().equals(entry.getPackageName())) {
1447 Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1448 entry.setLastTimeUsed(field.getLong(task));
1449 currentRunningAppIds.add(entry.getPackageName());
1451 } catch (Exception e) { /* Gracefully fail */ }
1459 @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
1460 private List<AppEntry> getAppEntriesUsingUsageStats() {
1461 UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
1462 List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, searchInterval, System.currentTimeMillis());
1463 List<AppEntry> entries = new ArrayList<>();
1465 for(UsageStats usageStats : usageStatsList) {
1466 AppEntry newEntry = new AppEntry(
1467 usageStats.getPackageName(),
1474 newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1475 newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1476 entries.add(newEntry);
1482 private boolean hasLauncherIntent(String packageName) {
1483 Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1484 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1485 intentToResolve.setPackage(packageName);
1487 List<ResolveInfo> ris = context.getPackageManager().queryIntentActivities(intentToResolve, 0);
1488 return ris != null && ris.size() > 0;
1491 private boolean isScreenOff() {
1492 if(U.isChromeOs(context))
1495 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1496 return !pm.isInteractive();
1499 private void updateSystemTray() {
1500 if(sysTrayLayout == null || isScreenOff()) return;
1502 int accentColor = U.getAccentColor(context);
1504 handler.post(() -> {
1505 ImageView battery = sysTrayLayout.findViewById(R.id.battery);
1506 battery.setImageDrawable(getBatteryDrawable());
1507 battery.setColorFilter(accentColor);
1509 ImageView wifi = sysTrayLayout.findViewById(R.id.wifi);
1510 wifi.setImageDrawable(getWifiDrawable());
1511 wifi.setColorFilter(accentColor);
1513 ImageView bluetooth = sysTrayLayout.findViewById(R.id.bluetooth);
1514 bluetooth.setImageDrawable(getBluetoothDrawable());
1515 bluetooth.setColorFilter(accentColor);
1517 ImageView cellular = sysTrayLayout.findViewById(R.id.cellular);
1518 cellular.setImageDrawable(getCellularDrawable());
1519 cellular.setColorFilter(accentColor);
1521 TextView time = sysTrayLayout.findViewById(R.id.time);
1522 time.setText(context.getString(R.string.systray_clock,
1523 DateFormat.getTimeFormat(context).format(new Date()),
1524 DateFormat.getDateFormat(context).format(new Date())));
1525 time.setTextColor(accentColor);
1529 @TargetApi(Build.VERSION_CODES.M)
1530 private Drawable getBatteryDrawable() {
1531 BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
1532 int batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
1536 batDrawable = "alert";
1537 else if(batLevel <= 20)
1539 else if(batLevel <= 30)
1541 else if(batLevel <= 50)
1543 else if(batLevel <= 60)
1545 else if(batLevel <= 80)
1547 else if(batLevel <= 90)
1550 batDrawable = "full";
1554 charging = "charging_";
1558 String batRes = "ic_battery_" + charging + batDrawable + "_black_24dp";
1559 int id = context.getResources().getIdentifier(batRes, "drawable", BuildConfig.APPLICATION_ID);
1561 return ContextCompat.getDrawable(context, id);
1564 @TargetApi(Build.VERSION_CODES.M)
1565 private Drawable getWifiDrawable() {
1566 ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1568 NetworkInfo ethernet = manager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
1569 if(ethernet != null && ethernet.isConnected())
1570 return ContextCompat.getDrawable(context, R.drawable.ic_settings_ethernet_black_24dp);
1572 NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
1573 if(wifi == null || !wifi.isConnected())
1576 WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
1577 int numberOfLevels = 5;
1579 WifiInfo wifiInfo = wifiManager.getConnectionInfo();
1580 int level = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), numberOfLevels);
1582 String wifiRes = "ic_signal_wifi_" + level + "_bar_black_24dp";
1583 int id = context.getResources().getIdentifier(wifiRes, "drawable", BuildConfig.APPLICATION_ID);
1585 return ContextCompat.getDrawable(context, id);
1588 private Drawable getBluetoothDrawable() {
1589 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1590 if(adapter != null && adapter.isEnabled())
1591 return ContextCompat.getDrawable(context, R.drawable.ic_bluetooth_black_24dp);
1596 @TargetApi(Build.VERSION_CODES.M)
1597 private Drawable getCellularDrawable() {
1598 if(Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0)
1599 return ContextCompat.getDrawable(context, R.drawable.ic_airplanemode_active_black_24dp);
1601 if(cellStrength == -1)
1604 String cellRes = "ic_signal_cellular_" + cellStrength + "_bar_black_24dp";
1605 int id = context.getResources().getIdentifier(cellRes, "drawable", BuildConfig.APPLICATION_ID);
1607 return ContextCompat.getDrawable(context, id);