OSDN Git Service

Fix behavior of running app indicators on Android-x86
[android-x86/packages-apps-Taskbar.git] / app / src / main / java / com / farmerbb / taskbar / ui / TaskbarController.java
1 /* Copyright 2016 Braden Farmer
2  *
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
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 package com.farmerbb.taskbar.ui;
17
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;
63
64 import java.io.File;
65 import java.lang.reflect.Field;
66 import java.util.ArrayList;
67 import java.util.Collections;
68 import java.util.List;
69
70 import android.support.v4.content.LocalBroadcastManager;
71 import android.widget.LinearLayout;
72 import android.widget.Space;
73
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;
88
89 public class TaskbarController implements UIController {
90
91     private Context context;
92     private LinearLayout layout;
93     private ImageView startButton;
94     private LinearLayout taskbar;
95     private FrameLayout scrollView;
96     private Button button;
97     private Space space;
98     private FrameLayout dashboardButton;
99     private LinearLayout navbarButtons;
100
101     private Handler handler;
102     private Handler handler2;
103     private Thread thread;
104     private Thread thread2;
105
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;
112
113     private boolean startThread2 = false;
114     private boolean stopThread2 = false;
115
116     private int refreshInterval = -1;
117     private long searchInterval = -1;
118     private String sortOrder = "false";
119     private boolean runningAppsOnly = false;
120
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;
127
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;
132
133     private View.OnClickListener ocl = view -> {
134         Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU");
135         LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
136     };
137
138     private BroadcastReceiver showReceiver = new BroadcastReceiver() {
139         @Override
140         public void onReceive(Context context, Intent intent) {
141             showTaskbar(true);
142         }
143     };
144
145     private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
146         @Override
147         public void onReceive(Context context, Intent intent) {
148             hideTaskbar(true);
149         }
150     };
151
152     private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
153         @Override
154         public void onReceive(Context context, Intent intent) {
155             tempShowTaskbar();
156         }
157     };
158
159     private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
160         @Override
161         public void onReceive(Context context, Intent intent) {
162             tempHideTaskbar(false);
163         }
164     };
165
166     private BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
167         @Override
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);
172         }
173     };
174
175     private BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
176         @Override
177         public void onReceive(Context context, Intent intent) {
178             if(startButton.getVisibility() == View.GONE)
179                 layout.setVisibility(View.VISIBLE);
180         }
181     };
182
183     public TaskbarController(Context context) {
184         this.context = context;
185     }
186
187     @TargetApi(Build.VERSION_CODES.M)
188     @Override
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))
193                 drawTaskbar(host);
194             else {
195                 pref.edit().putBoolean("taskbar_active", false).apply();
196
197                 host.terminate();
198             }
199         } else host.terminate();
200     }
201
202     @SuppressLint("RtlHardcoded")
203     private void drawTaskbar(UIHost host) {
204         IconCache.getInstance(context).clearCache();
205
206         // Initialize layout params
207         WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
208         U.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
209
210         final ViewParams params = new ViewParams(
211                 WindowManager.LayoutParams.WRAP_CONTENT,
212                 WindowManager.LayoutParams.WRAP_CONTENT,
213                 -1,
214                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
215         );
216
217         // Determine where to show the taskbar on screen
218         switch(U.getTaskbarPosition(context)) {
219             case "bottom_left":
220                 layoutId = R.layout.taskbar_left;
221                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
222                 positionIsVertical = false;
223                 break;
224             case "bottom_vertical_left":
225                 layoutId = R.layout.taskbar_vertical;
226                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
227                 positionIsVertical = true;
228                 break;
229             case "bottom_right":
230                 layoutId = R.layout.taskbar_right;
231                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
232                 positionIsVertical = false;
233                 break;
234             case "bottom_vertical_right":
235                 layoutId = R.layout.taskbar_vertical;
236                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
237                 positionIsVertical = true;
238                 break;
239             case "top_left":
240                 layoutId = R.layout.taskbar_left;
241                 params.gravity = Gravity.TOP | Gravity.LEFT;
242                 positionIsVertical = false;
243                 break;
244             case "top_vertical_left":
245                 layoutId = R.layout.taskbar_top_vertical;
246                 params.gravity = Gravity.TOP | Gravity.LEFT;
247                 positionIsVertical = true;
248                 break;
249             case "top_right":
250                 layoutId = R.layout.taskbar_right;
251                 params.gravity = Gravity.TOP | Gravity.RIGHT;
252                 positionIsVertical = false;
253                 break;
254             case "top_vertical_right":
255                 layoutId = R.layout.taskbar_top_vertical;
256                 params.gravity = Gravity.TOP | Gravity.RIGHT;
257                 positionIsVertical = true;
258                 break;
259         }
260
261         // Initialize views
262         SharedPreferences pref = U.getSharedPreferences(context);
263         boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
264
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);
268
269         int backgroundTint = U.getBackgroundTint(context);
270         int accentColor = U.getAccentColor(context);
271
272         if(altButtonConfig) {
273             space = layout.findViewById(R.id.space_alt);
274             layout.findViewById(R.id.space).setVisibility(View.GONE);
275         } else {
276             space = layout.findViewById(R.id.space);
277             layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
278         }
279
280         space.setOnClickListener(v -> toggleTaskbar(true));
281
282         startButton = layout.findViewById(R.id.start_button);
283         int padding = 0;
284
285         switch(pref.getString("start_button_image", U.getDefaultStartButtonImage(context))) {
286             case "default":
287                 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
288                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
289                 break;
290             case "app_logo":
291                 Drawable drawable;
292
293                 if(U.isBlissOs(context)) {
294                     drawable = ContextCompat.getDrawable(context, R.drawable.bliss);
295                     drawable.setTint(accentColor);
296                 } else
297                     drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher);
298
299                 startButton.setImageDrawable(drawable);
300                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
301                 break;
302             case "custom":
303                 File file = new File(context.getFilesDir() + "/images", "custom_image");
304                 if(file.exists()) {
305                     try {
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));
310                     }
311                 } else
312                     startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
313
314                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
315                 break;
316         }
317
318         startButton.setPadding(padding, padding, padding, padding);
319         startButton.setOnClickListener(ocl);
320         startButton.setOnLongClickListener(view -> {
321             openContextMenu();
322             return true;
323         });
324
325         startButton.setOnGenericMotionListener((view, motionEvent) -> {
326             if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
327                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
328                 openContextMenu();
329
330             return false;
331         });
332
333         refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000);
334         if(refreshInterval == 0)
335             refreshInterval = 100;
336
337         sortOrder = pref.getString("sort_order", "false");
338         runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only");
339
340         switch(pref.getString("recents_amount", "past_day")) {
341             case "past_day":
342                 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
343                 break;
344             case "app_start":
345                 long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis());
346                 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
347
348                 searchInterval = deviceStartTime > appStartTime ? deviceStartTime : appStartTime;
349                 break;
350             case "show_all":
351                 searchInterval = 0;
352                 break;
353         }
354
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"));
358
359         if(altButtonConfig) {
360             button = layout.findViewById(R.id.hide_taskbar_button_alt);
361             layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
362         } else {
363             button = layout.findViewById(R.id.hide_taskbar_button);
364             layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
365         }
366
367         try {
368             button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
369         } catch (RuntimeException e) { /* Gracefully fail */ }
370
371         updateButton(false);
372         button.setOnClickListener(v -> toggleTaskbar(true));
373
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));
378
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);
383
384         dashboardButton = layout.findViewById(R.id.dashboard_button);
385         navbarButtons = layout.findViewById(R.id.navbar_buttons);
386
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);
395
396             dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD")));
397         } else
398             dashboardButton.setVisibility(View.GONE);
399
400         if(pref.getBoolean("button_back", false)) {
401             navbarButtonsEnabled = true;
402
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))
409                     hideTaskbar(true);
410             });
411
412             backButton.setOnLongClickListener(v -> {
413                 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
414                 imm.showInputMethodPicker();
415
416                 if(U.shouldCollapse(context, false))
417                     hideTaskbar(true);
418
419                 return true;
420             });
421
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();
427
428                     if(U.shouldCollapse(context, false))
429                         hideTaskbar(true);
430                 }
431                 return true;
432             });
433         }
434
435         if(pref.getBoolean("button_home", false)) {
436             navbarButtonsEnabled = true;
437
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))
444                     hideTaskbar(true);
445             });
446
447             homeButton.setOnLongClickListener(v -> {
448                 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
449                 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
450
451                 try {
452                     context.startActivity(voiceSearchIntent);
453                 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
454
455                 if(U.shouldCollapse(context, false))
456                     hideTaskbar(true);
457
458                 return true;
459             });
460
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);
466
467                     try {
468                         context.startActivity(voiceSearchIntent);
469                     } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
470
471                     if(U.shouldCollapse(context, false))
472                         hideTaskbar(true);
473                 }
474                 return true;
475             });
476         }
477
478         if(pref.getBoolean("button_recents", false)) {
479             navbarButtonsEnabled = true;
480
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))
487                     hideTaskbar(true);
488             });
489
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))
494                         hideTaskbar(true);
495
496                     return true;
497                 });
498
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))
504                             hideTaskbar(true);
505                     }
506                     return true;
507                 });
508             }
509         }
510
511         if(!navbarButtonsEnabled)
512             navbarButtons.setVisibility(View.GONE);
513
514         layout.setBackgroundColor(backgroundTint);
515         layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
516         button.setTextColor(accentColor);
517
518         if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
519             showTaskbar(false);
520         else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
521             toggleTaskbar(false);
522
523         if(pref.getBoolean("auto_hide_navbar", false))
524             U.showHideNavigationBar(context, false);
525
526         if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
527             lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
528
529             new Handler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
530         }
531
532         lbm.unregisterReceiver(showReceiver);
533         lbm.unregisterReceiver(hideReceiver);
534         lbm.unregisterReceiver(tempShowReceiver);
535         lbm.unregisterReceiver(tempHideReceiver);
536         lbm.unregisterReceiver(startMenuAppearReceiver);
537         lbm.unregisterReceiver(startMenuDisappearReceiver);
538
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"));
545
546         startRefreshingRecents();
547
548         host.addView(layout, params);
549
550         isFirstStart = false;
551     }
552
553     private void startRefreshingRecents() {
554         if(thread != null) thread.interrupt();
555         stopThread2 = true;
556
557         SharedPreferences pref = U.getSharedPreferences(context);
558         showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
559
560         currentTaskbarIds.clear();
561
562         handler = new Handler();
563         thread = new Thread(() -> {
564             updateRecentApps(true);
565
566             if(!isRefreshingRecents) {
567                 isRefreshingRecents = true;
568
569                 while(shouldRefreshRecents) {
570                     SystemClock.sleep(refreshInterval);
571                     updateRecentApps(false);
572
573                     if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
574                         handler.post(() -> {
575                             if(layout != null) {
576                                 int[] location = new int[2];
577                                 layout.getLocationOnScreen(location);
578
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) {
586                                             startThread2 = true;
587                                             tempHideTaskbar(true);
588                                         }
589                                     }
590                                 }
591                             }
592                         });
593                 }
594
595                 isRefreshingRecents = false;
596             }
597         });
598
599         thread.start();
600     }
601
602     @SuppressWarnings("Convert2streamapi")
603     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
604     private void updateRecentApps(final boolean firstRefresh) {
605         if(isScreenOff()) return;
606
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);
614
615         if(runningAppsOnly)
616             currentRunningAppIds.clear();
617
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<>();
622
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);
627
628             for(AppEntry entry : pinnedApps) {
629                 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
630                         userManager.getUserForSerialNumber(entry.getUserId(context)));
631
632                 if(packageEnabled)
633                     entries.add(entry);
634                 else
635                     realNumOfPinnedApps--;
636
637                 applicationIdsToRemove.add(entry.getPackageName());
638             }
639
640             realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
641         }
642
643         if(blockedApps.size() > 0) {
644             for(AppEntry entry : blockedApps) {
645                 applicationIdsToRemove.add(entry.getPackageName());
646             }
647         }
648
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;
658
659                 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
660                 homeIntent.addCategory(Intent.CATEGORY_HOME);
661                 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
662
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);
670                 }
671
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);
676                 }
677
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()));
681                 } else {
682                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
683                 }
684
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());
691                     }
692                 }
693
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;
700
701                     while(events.hasNextEvent()) {
702                         events.getNextEvent(eventCache);
703
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();
710                         }
711                     }
712
713                     if(!applicationIdsToRemove.contains(currentForegroundApp))
714                         applicationIdsToRemove.add(currentForegroundApp);
715                 }
716
717                 for(AppEntry stats : usageStatsList4) {
718                     if(!applicationIdsToRemove.contains(stats.getPackageName())) {
719                         usageStatsList5.add(stats);
720                     }
721                 }
722
723                 // Truncate list to a maximum length
724                 if(usageStatsList5.size() > maxNumOfEntries)
725                     usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
726                 else
727                     usageStatsList6 = usageStatsList5;
728
729                 // Determine if we need to reverse the order
730                 boolean needToReverseOrder;
731                 switch(U.getTaskbarPosition(context)) {
732                     case "bottom_right":
733                     case "top_right":
734                         needToReverseOrder = sortOrder.contains("false");
735                         break;
736                     default:
737                         needToReverseOrder = sortOrder.contains("true");
738                         break;
739                 }
740
741                 if(needToReverseOrder) {
742                     Collections.reverse(usageStatsList6);
743                 }
744
745                 // Generate the AppEntries for the recent apps list
746                 int number = usageStatsList6.size() == maxNumOfEntries
747                         ? usageStatsList6.size() - realNumOfPinnedApps
748                         : usageStatsList6.size();
749
750                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
751                 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
752
753                 final List<UserHandle> userHandles = userManager.getUserProfiles();
754
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));
764                             else {
765                                 boolean added = false;
766                                 for(LauncherActivityInfo info : list) {
767                                     if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
768                                         launcherAppCache.add(info);
769                                         added = true;
770                                     }
771                                 }
772
773                                 if(!added) launcherAppCache.add(list.get(0));
774                             }
775
776                             AppEntry newEntry = new AppEntry(
777                                     packageName,
778                                     null,
779                                     null,
780                                     null,
781                                     false
782                             );
783
784                             newEntry.setUserId(userManager.getSerialNumberForUser(handle));
785                             newEntry.setLastTimeUsed(lastTimeUsed);
786                             entries.add(newEntry);
787
788                             break;
789                         }
790                     }
791                 }
792             }
793
794             while(entries.size() > maxNumOfEntries) {
795                 try {
796                     entries.remove(entries.size() - 1);
797                     launcherAppCache.remove(launcherAppCache.size() - 1);
798                 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
799             }
800
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);
805             }
806
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;
810
811             List<String> finalApplicationIds = new ArrayList<>();
812             for(AppEntry entry : entries) {
813                 finalApplicationIds.add(entry.getPackageName());
814             }
815
816             if(finalApplicationIds.size() != currentTaskbarIds.size()
817                     || (runningAppsOnly && currentRunningAppIds.size() != prevRunningAppIds.size())
818                     || numOfPinnedApps != realNumOfPinnedApps)
819                 shouldRedrawTaskbar = true;
820             else {
821                 for(int i = 0; i < finalApplicationIds.size(); i++) {
822                     if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
823                         shouldRedrawTaskbar = true;
824                         break;
825                     }
826                 }
827
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;
832                             break;
833                         }
834                     }
835                 }
836             }
837
838             if(shouldRedrawTaskbar) {
839                 currentTaskbarIds = finalApplicationIds;
840                 numOfPinnedApps = realNumOfPinnedApps;
841
842                 if(runningAppsOnly) {
843                     prevRunningAppIds.clear();
844                     prevRunningAppIds.addAll(currentRunningAppIds);
845                 }
846
847                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
848
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();
856
857                         entries.remove(i);
858
859                         AppEntry newEntry = new AppEntry(
860                                 packageName,
861                                 appInfo.getComponentName().flattenToString(),
862                                 appInfo.getLabel().toString(),
863                                 IconCache.getInstance(context).getIcon(context, pm, appInfo),
864                                 false);
865
866                         newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
867                         newEntry.setLastTimeUsed(lastTimeUsed);
868                         entries.add(i, newEntry);
869                     }
870                 }
871
872                 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
873
874                 handler.post(() -> {
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;
880
881                         if(U.getTaskbarPosition(context).contains("vertical")) {
882                             int maxScreenSize = display.height
883                                     - U.getStatusBarHeight(context)
884                                     - U.getBaseTaskbarSize(context);
885
886                             params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
887                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
888
889                             if(fullLength) {
890                                 try {
891                                     Space whitespaceTop = layout.findViewById(R.id.whitespace_top);
892                                     Space whitespaceBottom = layout.findViewById(R.id.whitespace_bottom);
893                                     int height = maxScreenSize - recentsSize;
894
895                                     if(pref.getBoolean("centered_icons", false)) {
896                                         ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
897                                         topParams.height = height / 2;
898                                         whitespaceTop.setLayoutParams(topParams);
899
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);
907                                     } else {
908                                         ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
909                                         bottomParams.height = height;
910                                         whitespaceBottom.setLayoutParams(bottomParams);
911                                     }
912                                 } catch (NullPointerException e) { /* Gracefully fail */ }
913                             }
914                         } else {
915                             int maxScreenSize = display.width - U.getBaseTaskbarSize(context);
916
917                             params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
918                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
919
920                             if(fullLength) {
921                                 try {
922                                     Space whitespaceLeft = layout.findViewById(R.id.whitespace_left);
923                                     Space whitespaceRight = layout.findViewById(R.id.whitespace_right);
924                                     int width = maxScreenSize - recentsSize;
925
926                                     if(pref.getBoolean("centered_icons", false)) {
927                                         ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
928                                         leftParams.width = width / 2;
929                                         whitespaceLeft.setLayoutParams(leftParams);
930
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);
938                                     } else {
939                                         ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
940                                         rightParams.width = width;
941                                         whitespaceRight.setLayoutParams(rightParams);
942                                     }
943                                 } catch (NullPointerException e) { /* Gracefully fail */ }
944                             }
945                         }
946
947                         scrollView.setLayoutParams(params);
948
949                         taskbar.removeAllViews();
950                         for(int i = 0; i < entries.size(); i++) {
951                             taskbar.addView(getView(entries, i));
952                         }
953
954                         isShowingRecents = true;
955                         if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
956                             if(firstRefresh)
957                                 scrollView.setVisibility(View.INVISIBLE);
958                             else
959                                 scrollView.setVisibility(View.VISIBLE);
960                         }
961
962                         if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
963                             new Handler().post(() -> {
964                                 switch(U.getTaskbarPosition(context)) {
965                                     case "bottom_left":
966                                     case "bottom_right":
967                                     case "top_left":
968                                     case "top_right":
969                                         if(sortOrder.contains("false"))
970                                             scrollView.scrollTo(0, 0);
971                                         else if(sortOrder.contains("true"))
972                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
973                                         break;
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);
982                                         break;
983                                 }
984
985                                 if(shouldRefreshRecents) {
986                                     scrollView.setVisibility(View.VISIBLE);
987                                 }
988                             });
989                     } else {
990                         isShowingRecents = false;
991                         scrollView.setVisibility(View.GONE);
992                     }
993                 });
994             }
995         } else if(firstRefresh || currentTaskbarIds.size() > 0) {
996             currentTaskbarIds.clear();
997             handler.post(() -> {
998                 isShowingRecents = false;
999                 scrollView.setVisibility(View.GONE);
1000             });
1001         }
1002     }
1003
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();
1010             }
1011         }
1012
1013         if(startButton.getVisibility() == View.GONE)
1014             showTaskbar(true);
1015         else
1016             hideTaskbar(true);
1017     }
1018
1019     private void showTaskbar(boolean clearVariables) {
1020         if(clearVariables) {
1021             taskbarShownTemporarily = false;
1022             taskbarHiddenTemporarily = false;
1023         }
1024
1025         if(startButton.getVisibility() == View.GONE) {
1026             startButton.setVisibility(View.VISIBLE);
1027             space.setVisibility(View.VISIBLE);
1028
1029             if(dashboardEnabled)
1030                 dashboardButton.setVisibility(View.VISIBLE);
1031
1032             if(navbarButtonsEnabled)
1033                 navbarButtons.setVisibility(View.VISIBLE);
1034
1035             if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1036                 scrollView.setVisibility(View.INVISIBLE);
1037
1038             shouldRefreshRecents = true;
1039             startRefreshingRecents();
1040
1041             SharedPreferences pref = U.getSharedPreferences(context);
1042             pref.edit().putBoolean("collapsed", true).apply();
1043
1044             updateButton(false);
1045
1046             new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
1047         }
1048     }
1049
1050     private void hideTaskbar(boolean clearVariables) {
1051         if(clearVariables) {
1052             taskbarShownTemporarily = false;
1053             taskbarHiddenTemporarily = false;
1054         }
1055
1056         if(startButton.getVisibility() == View.VISIBLE) {
1057             startButton.setVisibility(View.GONE);
1058             space.setVisibility(View.GONE);
1059
1060             if(dashboardEnabled)
1061                 dashboardButton.setVisibility(View.GONE);
1062
1063             if(navbarButtonsEnabled)
1064                 navbarButtons.setVisibility(View.GONE);
1065
1066             if(isShowingRecents) {
1067                 scrollView.setVisibility(View.GONE);
1068             }
1069
1070             shouldRefreshRecents = false;
1071             if(thread != null) thread.interrupt();
1072
1073             SharedPreferences pref = U.getSharedPreferences(context);
1074             pref.edit().putBoolean("collapsed", false).apply();
1075
1076             updateButton(true);
1077
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"));
1080
1081             new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU_SPACE")));
1082         }
1083     }
1084
1085     private void tempShowTaskbar() {
1086         if(!taskbarHiddenTemporarily) {
1087             SharedPreferences pref = U.getSharedPreferences(context);
1088             if(!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true;
1089         }
1090
1091         showTaskbar(false);
1092
1093         if(taskbarHiddenTemporarily)
1094             taskbarHiddenTemporarily = false;
1095     }
1096
1097     private void tempHideTaskbar(boolean monitorPositionChanges) {
1098         if(!taskbarShownTemporarily) {
1099             SharedPreferences pref = U.getSharedPreferences(context);
1100             if(pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true;
1101         }
1102
1103         hideTaskbar(false);
1104
1105         if(taskbarShownTemporarily)
1106             taskbarShownTemporarily = false;
1107
1108         if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1109             if(thread2 != null) thread2.interrupt();
1110
1111             handler2 = new Handler();
1112             thread2 = new Thread(() -> {
1113                 stopThread2 = false;
1114
1115                 while(!stopThread2) {
1116                     SystemClock.sleep(refreshInterval);
1117
1118                     handler2.post(() -> stopThread2 = checkPositionChange());
1119                 }
1120
1121                 startThread2 = false;
1122             });
1123
1124             thread2.start();
1125         }
1126     }
1127
1128     private boolean checkPositionChange() {
1129         if(!isScreenOff() && layout != null) {
1130             int[] location = new int[2];
1131             layout.getLocationOnScreen(location);
1132
1133             if(location[1] == 0) {
1134                 return true;
1135             } else {
1136                 if(location[1] > currentTaskbarPosition) {
1137                     currentTaskbarPosition = location[1];
1138                     if(taskbarHiddenTemporarily) {
1139                         tempShowTaskbar();
1140                         return true;
1141                     }
1142                 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1143                     tempShowTaskbar();
1144                     return true;
1145                 } else if(location[1] < currentTaskbarPosition
1146                         && currentTaskbarPosition - location[1] == getNavBarSize()) {
1147                     currentTaskbarPosition = location[1];
1148                 }
1149             }
1150         }
1151
1152         return false;
1153     }
1154
1155     private int getNavBarSize() {
1156         Point size = new Point();
1157         Point realSize = new Point();
1158
1159         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1160         Display display = wm.getDefaultDisplay();
1161         display.getSize(size);
1162         display.getRealSize(realSize);
1163
1164         return realSize.y - size.y;
1165     }
1166
1167     @Override
1168     public void onDestroyHost(UIHost host) {
1169         shouldRefreshRecents = false;
1170
1171         if(layout != null)
1172             try {
1173                 host.removeView(layout);
1174             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1175
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);
1181
1182         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
1183
1184         lbm.unregisterReceiver(showReceiver);
1185         lbm.unregisterReceiver(hideReceiver);
1186         lbm.unregisterReceiver(tempShowReceiver);
1187         lbm.unregisterReceiver(tempHideReceiver);
1188         lbm.unregisterReceiver(startMenuAppearReceiver);
1189         lbm.unregisterReceiver(startMenuDisappearReceiver);
1190
1191         isFirstStart = true;
1192     }
1193
1194     private void openContextMenu() {
1195         SharedPreferences pref = U.getSharedPreferences(context);
1196
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);
1202
1203         U.startContextMenuActivity(context, args);
1204     }
1205
1206     private void updateButton(boolean isCollapsed) {
1207         SharedPreferences pref = U.getSharedPreferences(context);
1208         boolean hide = pref.getBoolean("invisible_button", false);
1209
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);
1212     }
1213
1214     @TargetApi(Build.VERSION_CODES.M)
1215     @Override
1216     public void onRecreateHost(UIHost host) {
1217         if(layout != null) {
1218             try {
1219                 host.removeView(layout);
1220             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1221
1222             currentTaskbarPosition = 0;
1223
1224             if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
1225                 drawTaskbar(host);
1226             else {
1227                 SharedPreferences pref = U.getSharedPreferences(context);
1228                 pref.edit().putBoolean("taskbar_active", false).apply();
1229
1230                 host.terminate();
1231             }
1232         }
1233     }
1234
1235     private View getView(List<AppEntry> list, int position) {
1236         View convertView = View.inflate(context, R.layout.icon, null);
1237
1238         final AppEntry entry = list.get(position);
1239         final SharedPreferences pref = U.getSharedPreferences(context);
1240
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)));
1245
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;
1251             else
1252                 shouldShowShortcutIcon = position < numOfPinnedApps;
1253
1254             if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1255         }
1256
1257         if(taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) {
1258             imageView.setRotationY(180);
1259             imageView2.setRotationY(180);
1260         }
1261
1262         FrameLayout layout = convertView.findViewById(R.id.entry);
1263         layout.setOnClickListener(view -> U.launchApp(
1264                 context,
1265                 entry,
1266                 null,
1267                 true,
1268                 false,
1269                 view
1270         ));
1271
1272         layout.setOnLongClickListener(view -> {
1273             int[] location = new int[2];
1274             view.getLocationOnScreen(location);
1275             openContextMenu(entry, location);
1276             return true;
1277         });
1278
1279         layout.setOnGenericMotionListener((view, motionEvent) -> {
1280             int action = motionEvent.getAction();
1281
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);
1287             }
1288
1289             if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true))
1290                 view.setBackgroundColor(0);
1291
1292             return false;
1293         });
1294
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);
1301                 }
1302
1303                 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1304                     v.setBackgroundColor(0);
1305
1306                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1307                     v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
1308
1309                 return false;
1310             });
1311
1312             layout.setOnTouchListener((v, event) -> {
1313                 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1314                 return false;
1315             });
1316         }
1317
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));
1323             } else
1324                 runningAppIndicator.setVisibility(View.GONE);
1325         }
1326
1327         return convertView;
1328     }
1329
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]);
1335
1336         U.startContextMenuActivity(context, args);
1337     }
1338
1339     private List<AppEntry> getAppEntries() {
1340         SharedPreferences pref = U.getSharedPreferences(context);
1341         if(runningAppsOnly)
1342             return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10")));
1343         else
1344             return getAppEntriesUsingUsageStats();
1345     }
1346
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<>();
1353
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(
1359                         packageName,
1360                         null,
1361                         null,
1362                         null,
1363                         false
1364                 );
1365
1366                 try {
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);
1372                 }
1373
1374                 entries.add(newEntry);
1375             }
1376         }
1377
1378         return entries;
1379     }
1380
1381     @SuppressWarnings("deprecation")
1382     @TargetApi(Build.VERSION_CODES.M)
1383     private List<AppEntry> setTimeLastUsedFor(List<AppEntry> pinnedApps) {
1384         if(!runningAppsOnly || pinnedApps.size() == 0)
1385             return pinnedApps;
1386
1387         ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1388         List<ActivityManager.RecentTaskInfo> recentTasks = mActivityManager.getRecentTasks(Integer.MAX_VALUE, 0);
1389
1390         for(AppEntry entry : pinnedApps) {
1391             for(ActivityManager.RecentTaskInfo task : recentTasks) {
1392                 if(task.id != -1 && task.baseActivity.getPackageName().equals(entry.getPackageName())) {
1393                     try {
1394                         Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1395                         entry.setLastTimeUsed(field.getLong(task));
1396                         currentRunningAppIds.add(entry.getPackageName());
1397                         break;
1398                     } catch (Exception e) { /* Gracefully fail */ }
1399                 }
1400             }
1401         }
1402
1403         return pinnedApps;
1404     }
1405
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<>();
1411
1412         for(UsageStats usageStats : usageStatsList) {
1413             AppEntry newEntry = new AppEntry(
1414                     usageStats.getPackageName(),
1415                     null,
1416                     null,
1417                     null,
1418                     false
1419             );
1420
1421             newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1422             newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1423             entries.add(newEntry);
1424         }
1425
1426         return entries;
1427     }
1428
1429     private boolean hasLauncherIntent(String packageName) {
1430         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1431         intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1432         intentToResolve.setPackage(packageName);
1433
1434         List<ResolveInfo> ris = context.getPackageManager().queryIntentActivities(intentToResolve, 0);
1435         return ris != null && ris.size() > 0;
1436     }
1437
1438     private boolean isScreenOff() {
1439         if(U.isChromeOs(context))
1440             return false;
1441
1442         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1443         return !pm.isInteractive();
1444     }
1445 }