OSDN Git Service

Various small changes and tweaks
[android-x86/packages-apps-Taskbar.git] / app / src / main / java / com / farmerbb / taskbar / service / TaskbarService.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.service;
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.Service;
24 import android.app.usage.UsageEvents;
25 import android.app.usage.UsageStats;
26 import android.app.usage.UsageStatsManager;
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.content.res.Configuration;
38 import android.graphics.Color;
39 import android.graphics.PixelFormat;
40 import android.graphics.Point;
41 import android.graphics.Rect;
42 import android.graphics.Typeface;
43 import android.graphics.drawable.Drawable;
44 import android.os.Build;
45 import android.os.Handler;
46 import android.os.IBinder;
47 import android.os.PowerManager;
48 import android.os.SystemClock;
49 import android.os.UserHandle;
50 import android.os.UserManager;
51 import android.speech.RecognizerIntent;
52 import android.support.v4.content.ContextCompat;
53 import android.support.v4.graphics.ColorUtils;
54 import android.util.DisplayMetrics;
55 import android.view.Display;
56 import android.view.Gravity;
57 import android.view.LayoutInflater;
58 import android.view.MotionEvent;
59 import android.view.PointerIcon;
60 import android.view.View;
61 import android.view.ViewGroup;
62 import android.view.WindowManager;
63 import android.view.inputmethod.InputMethodManager;
64 import android.widget.Button;
65 import android.widget.FrameLayout;
66 import android.widget.ImageView;
67
68 import java.lang.reflect.Field;
69 import java.util.ArrayList;
70 import java.util.Collections;
71 import java.util.List;
72
73 import android.support.v4.content.LocalBroadcastManager;
74 import android.widget.LinearLayout;
75 import android.widget.Space;
76
77 import com.farmerbb.taskbar.BuildConfig;
78 import com.farmerbb.taskbar.activity.MainActivity;
79 import com.farmerbb.taskbar.R;
80 import com.farmerbb.taskbar.activity.ContextMenuActivity;
81 import com.farmerbb.taskbar.activity.dark.ContextMenuActivityDark;
82 import com.farmerbb.taskbar.activity.HomeActivity;
83 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
84 import com.farmerbb.taskbar.util.AppEntry;
85 import com.farmerbb.taskbar.util.ApplicationType;
86 import com.farmerbb.taskbar.util.FreeformHackHelper;
87 import com.farmerbb.taskbar.util.IconCache;
88 import com.farmerbb.taskbar.util.LauncherHelper;
89 import com.farmerbb.taskbar.util.CompatUtils;
90 import com.farmerbb.taskbar.util.PinnedBlockedApps;
91 import com.farmerbb.taskbar.util.MenuHelper;
92 import com.farmerbb.taskbar.util.U;
93
94 public class TaskbarService extends Service {
95
96     private WindowManager windowManager;
97     private LinearLayout layout;
98     private ImageView startButton;
99     private LinearLayout taskbar;
100     private FrameLayout scrollView;
101     private Button button;
102     private Space space;
103     private FrameLayout dashboardButton;
104     private LinearLayout navbarButtons;
105
106     private Handler handler;
107     private Handler handler2;
108     private Thread thread;
109     private Thread thread2;
110
111     private boolean isShowingRecents = true;
112     private boolean shouldRefreshRecents = true;
113     private boolean taskbarShownTemporarily = false;
114     private boolean taskbarHiddenTemporarily = false;
115     private boolean isRefreshingRecents = false;
116     private boolean isFirstStart = true;
117
118     private boolean startThread2 = false;
119     private boolean stopThread2 = false;
120
121     private int refreshInterval = -1;
122     private long searchInterval = -1;
123     private String sortOrder = "false";
124     private boolean runningAppsOnly = false;
125
126     private int layoutId = R.layout.taskbar_left;
127     private int currentTaskbarPosition = 0;
128     private boolean showHideAutomagically = false;
129     private boolean positionIsVertical = false;
130     private boolean dashboardEnabled = false;
131     private boolean navbarButtonsEnabled = false;
132
133     private List<String> currentTaskbarIds = new ArrayList<>();
134     private int numOfPinnedApps = -1;
135
136     private View.OnClickListener ocl = view -> {
137         Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU");
138         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
139     };
140
141     private BroadcastReceiver showReceiver = new BroadcastReceiver() {
142         @Override
143         public void onReceive(Context context, Intent intent) {
144             showTaskbar(true);
145         }
146     };
147
148     private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
149         @Override
150         public void onReceive(Context context, Intent intent) {
151             hideTaskbar(true);
152         }
153     };
154
155     private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
156         @Override
157         public void onReceive(Context context, Intent intent) {
158             tempShowTaskbar();
159         }
160     };
161
162     private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
163         @Override
164         public void onReceive(Context context, Intent intent) {
165             tempHideTaskbar(false);
166         }
167     };
168
169     private BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
170         @Override
171         public void onReceive(Context context, Intent intent) {
172             if(startButton.getVisibility() == View.GONE
173                     && (!LauncherHelper.getInstance().isOnHomeScreen() || FreeformHackHelper.getInstance().isInFreeformWorkspace()))
174                 layout.setVisibility(View.GONE);
175         }
176     };
177
178     private BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
179         @Override
180         public void onReceive(Context context, Intent intent) {
181             if(startButton.getVisibility() == View.GONE)
182                 layout.setVisibility(View.VISIBLE);
183         }
184     };
185     
186     @Override
187     public IBinder onBind(Intent intent) {
188         return null;
189     }
190
191     @Override
192     public int onStartCommand(Intent intent, int flags, int startId) {
193         return START_STICKY;
194     }
195
196     @TargetApi(Build.VERSION_CODES.M)
197     @Override
198     public void onCreate() {
199         super.onCreate();
200
201         SharedPreferences pref = U.getSharedPreferences(this);
202         if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
203             if(U.canDrawOverlays(this))
204                 drawTaskbar();
205             else {
206                 pref.edit().putBoolean("taskbar_active", false).apply();
207
208                 stopSelf();
209             }
210         } else stopSelf();
211     }
212
213     @SuppressLint("RtlHardcoded")
214     private void drawTaskbar() {
215         IconCache.getInstance(this).clearCache();
216
217         // Initialize layout params
218         windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
219         U.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
220
221         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
222                 WindowManager.LayoutParams.WRAP_CONTENT,
223                 WindowManager.LayoutParams.WRAP_CONTENT,
224                 CompatUtils.getOverlayType(),
225                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
226                 PixelFormat.TRANSLUCENT);
227
228         // Determine where to show the taskbar on screen
229         switch(U.getTaskbarPosition(this)) {
230             case "bottom_left":
231                 layoutId = R.layout.taskbar_left;
232                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
233                 positionIsVertical = false;
234                 break;
235             case "bottom_vertical_left":
236                 layoutId = R.layout.taskbar_vertical;
237                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
238                 positionIsVertical = true;
239                 break;
240             case "bottom_right":
241                 layoutId = R.layout.taskbar_right;
242                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
243                 positionIsVertical = false;
244                 break;
245             case "bottom_vertical_right":
246                 layoutId = R.layout.taskbar_vertical;
247                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
248                 positionIsVertical = true;
249                 break;
250             case "top_left":
251                 layoutId = R.layout.taskbar_left;
252                 params.gravity = Gravity.TOP | Gravity.LEFT;
253                 positionIsVertical = false;
254                 break;
255             case "top_vertical_left":
256                 layoutId = R.layout.taskbar_top_vertical;
257                 params.gravity = Gravity.TOP | Gravity.LEFT;
258                 positionIsVertical = true;
259                 break;
260             case "top_right":
261                 layoutId = R.layout.taskbar_right;
262                 params.gravity = Gravity.TOP | Gravity.RIGHT;
263                 positionIsVertical = false;
264                 break;
265             case "top_vertical_right":
266                 layoutId = R.layout.taskbar_top_vertical;
267                 params.gravity = Gravity.TOP | Gravity.RIGHT;
268                 positionIsVertical = true;
269                 break;
270         }
271
272         // Initialize views
273         SharedPreferences pref = U.getSharedPreferences(this);
274         boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
275
276         layout = (LinearLayout) LayoutInflater.from(U.wrapContext(this)).inflate(layoutId, null);
277         taskbar = U.findViewById(layout, R.id.taskbar);
278         scrollView = U.findViewById(layout, R.id.taskbar_scrollview);
279
280         int backgroundTint = U.getBackgroundTint(this);
281         int accentColor = U.getAccentColor(this);
282
283         if(altButtonConfig) {
284             space = U.findViewById(layout, R.id.space_alt);
285             layout.findViewById(R.id.space).setVisibility(View.GONE);
286         } else {
287             space = U.findViewById(layout, R.id.space);
288             layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
289         }
290
291         space.setOnClickListener(v -> toggleTaskbar());
292
293         startButton = U.findViewById(layout, R.id.start_button);
294         int padding;
295
296         if(pref.getBoolean("app_drawer_icon", false)) {
297             Drawable drawable;
298
299             if(U.isBlissOs(this)) {
300                 drawable = ContextCompat.getDrawable(this, R.drawable.bliss);
301                 drawable.setTint(accentColor);
302             } else
303                 drawable = ContextCompat.getDrawable(this, R.mipmap.ic_launcher);
304
305             startButton.setImageDrawable(drawable);
306             padding = getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
307         } else {
308             startButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.all_apps_button_icon));
309             padding = getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
310         }
311
312         startButton.setPadding(padding, padding, padding, padding);
313         startButton.setOnClickListener(ocl);
314         startButton.setOnLongClickListener(view -> {
315             openContextMenu();
316             return true;
317         });
318
319         startButton.setOnGenericMotionListener((view, motionEvent) -> {
320             if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
321                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
322                 openContextMenu();
323
324             return false;
325         });
326
327         refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000);
328         if(refreshInterval == 0)
329             refreshInterval = 100;
330
331         sortOrder = pref.getString("sort_order", "false");
332         runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only");
333
334         switch(pref.getString("recents_amount", "past_day")) {
335             case "past_day":
336                 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
337                 break;
338             case "app_start":
339                 long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis());
340                 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
341
342                 searchInterval = deviceStartTime > appStartTime ? deviceStartTime : appStartTime;
343                 break;
344             case "show_all":
345                 searchInterval = 0;
346                 break;
347         }
348
349         Intent intent = new Intent("com.farmerbb.taskbar.HIDE_START_MENU");
350         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
351
352         if(altButtonConfig) {
353             button = U.findViewById(layout, R.id.hide_taskbar_button_alt);
354             layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
355         } else {
356             button = U.findViewById(layout, R.id.hide_taskbar_button);
357             layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
358         }
359
360         try {
361             button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
362         } catch (RuntimeException e) { /* Gracefully fail */ }
363
364         updateButton(false);
365         button.setOnClickListener(v -> toggleTaskbar());
366
367         LinearLayout buttonLayout = U.findViewById(layout, altButtonConfig
368                 ? R.id.hide_taskbar_button_layout_alt
369                 : R.id.hide_taskbar_button_layout);
370         if(buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar());
371
372         LinearLayout buttonLayoutToHide = U.findViewById(layout, altButtonConfig
373                 ? R.id.hide_taskbar_button_layout
374                 : R.id.hide_taskbar_button_layout_alt);
375         if(buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE);
376
377         dashboardButton = U.findViewById(layout, R.id.dashboard_button);
378         navbarButtons = U.findViewById(layout, R.id.navbar_buttons);
379
380         dashboardEnabled = pref.getBoolean("dashboard", false);
381         if(dashboardEnabled) {
382             layout.findViewById(R.id.square1).setBackgroundColor(accentColor);
383             layout.findViewById(R.id.square2).setBackgroundColor(accentColor);
384             layout.findViewById(R.id.square3).setBackgroundColor(accentColor);
385             layout.findViewById(R.id.square4).setBackgroundColor(accentColor);
386             layout.findViewById(R.id.square5).setBackgroundColor(accentColor);
387             layout.findViewById(R.id.square6).setBackgroundColor(accentColor);
388
389             dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD")));
390         } else
391             dashboardButton.setVisibility(View.GONE);
392
393         if(pref.getBoolean("button_back", false)) {
394             navbarButtonsEnabled = true;
395
396             ImageView backButton = U.findViewById(layout, R.id.button_back);
397             backButton.setColorFilter(accentColor);
398             backButton.setVisibility(View.VISIBLE);
399             backButton.setOnClickListener(v -> {
400                 U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_BACK);
401                 if(U.shouldCollapse(this, false))
402                     hideTaskbar(true);
403             });
404
405             backButton.setOnLongClickListener(v -> {
406                 InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
407                 imm.showInputMethodPicker();
408
409                 if(U.shouldCollapse(this, false))
410                     hideTaskbar(true);
411
412                 return true;
413             });
414
415             backButton.setOnGenericMotionListener((view13, motionEvent) -> {
416                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
417                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
418                     InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
419                     imm.showInputMethodPicker();
420
421                     if(U.shouldCollapse(this, false))
422                         hideTaskbar(true);
423                 }
424                 return true;
425             });
426         }
427
428         if(pref.getBoolean("button_home", false)) {
429             navbarButtonsEnabled = true;
430
431             ImageView homeButton = U.findViewById(layout, R.id.button_home);
432             homeButton.setColorFilter(accentColor);
433             homeButton.setVisibility(View.VISIBLE);
434             homeButton.setOnClickListener(v -> {
435                 U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_HOME);
436                 if(U.shouldCollapse(this, false))
437                     hideTaskbar(true);
438             });
439
440             homeButton.setOnLongClickListener(v -> {
441                 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
442                 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
443
444                 try {
445                     startActivity(voiceSearchIntent);
446                 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
447
448                 if(U.shouldCollapse(this, false))
449                     hideTaskbar(true);
450
451                 return true;
452             });
453
454             homeButton.setOnGenericMotionListener((view13, motionEvent) -> {
455                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
456                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
457                     Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
458                     voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
459
460                     try {
461                         startActivity(voiceSearchIntent);
462                     } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
463
464                     if(U.shouldCollapse(this, false))
465                         hideTaskbar(true);
466                 }
467                 return true;
468             });
469         }
470
471         if(pref.getBoolean("button_recents", false)) {
472             navbarButtonsEnabled = true;
473
474             ImageView recentsButton = U.findViewById(layout, R.id.button_recents);
475             recentsButton.setColorFilter(accentColor);
476             recentsButton.setVisibility(View.VISIBLE);
477             recentsButton.setOnClickListener(v -> {
478                 U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_RECENTS);
479                 if(U.shouldCollapse(this, false))
480                     hideTaskbar(true);
481             });
482
483             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
484                 recentsButton.setOnLongClickListener(v -> {
485                     U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
486                     if(U.shouldCollapse(this, false))
487                         hideTaskbar(true);
488
489                     return true;
490                 });
491
492                 recentsButton.setOnGenericMotionListener((view13, motionEvent) -> {
493                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
494                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
495                         U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
496                         if(U.shouldCollapse(this, false))
497                             hideTaskbar(true);
498                     }
499                     return true;
500                 });
501             }
502         }
503
504         if(!navbarButtonsEnabled)
505             navbarButtons.setVisibility(View.GONE);
506
507         layout.setBackgroundColor(backgroundTint);
508         layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
509         button.setTextColor(accentColor);
510
511         if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
512             showTaskbar(false);
513         else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
514             toggleTaskbar();
515
516         if(pref.getBoolean("auto_hide_navbar", false))
517             U.showHideNavigationBar(this, false);
518
519         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
520         
521         lbm.unregisterReceiver(showReceiver);
522         lbm.unregisterReceiver(hideReceiver);
523         lbm.unregisterReceiver(tempShowReceiver);
524         lbm.unregisterReceiver(tempHideReceiver);
525         lbm.unregisterReceiver(startMenuAppearReceiver);
526         lbm.unregisterReceiver(startMenuDisappearReceiver);
527
528         lbm.registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR"));
529         lbm.registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR"));
530         lbm.registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
531         lbm.registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
532         lbm.registerReceiver(startMenuAppearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_APPEARING"));
533         lbm.registerReceiver(startMenuDisappearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
534
535         startRefreshingRecents();
536
537         windowManager.addView(layout, params);
538
539         isFirstStart = false;
540     }
541
542     private void startRefreshingRecents() {
543         if(thread != null) thread.interrupt();
544         stopThread2 = true;
545
546         SharedPreferences pref = U.getSharedPreferences(this);
547         showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
548
549         currentTaskbarIds.clear();
550
551         handler = new Handler();
552         thread = new Thread(() -> {
553             updateRecentApps(true);
554
555             if(!isRefreshingRecents) {
556                 isRefreshingRecents = true;
557
558                 while(shouldRefreshRecents) {
559                     SystemClock.sleep(refreshInterval);
560                     updateRecentApps(false);
561
562                     if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
563                         handler.post(() -> {
564                             if(layout != null) {
565                                 int[] location = new int[2];
566                                 layout.getLocationOnScreen(location);
567
568                                 if(location[1] != 0) {
569                                     if(location[1] > currentTaskbarPosition) {
570                                         currentTaskbarPosition = location[1];
571                                     } else if(location[1] < currentTaskbarPosition) {
572                                         if(currentTaskbarPosition - location[1] == getNavBarSize())
573                                             currentTaskbarPosition = location[1];
574                                         else if(!startThread2) {
575                                             startThread2 = true;
576                                             tempHideTaskbar(true);
577                                         }
578                                     }
579                                 }
580                             }
581                         });
582                 }
583
584                 isRefreshingRecents = false;
585             }
586         });
587
588         thread.start();
589     }
590
591     @SuppressWarnings("Convert2streamapi")
592     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
593     private void updateRecentApps(final boolean firstRefresh) {
594         if(isScreenOff()) return;
595
596         SharedPreferences pref = U.getSharedPreferences(this);
597         final PackageManager pm = getPackageManager();
598         final List<AppEntry> entries = new ArrayList<>();
599         List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
600         int maxNumOfEntries = U.getMaxNumOfEntries(this);
601         int realNumOfPinnedApps = 0;
602         boolean fullLength = pref.getBoolean("full_length", false);
603
604         PinnedBlockedApps pba = PinnedBlockedApps.getInstance(this);
605         List<AppEntry> pinnedApps = pba.getPinnedApps();
606         List<AppEntry> blockedApps = pba.getBlockedApps();
607         List<String> applicationIdsToRemove = new ArrayList<>();
608
609         // Filter out anything on the pinned/blocked apps lists
610         if(pinnedApps.size() > 0) {
611             UserManager userManager = (UserManager) getSystemService(USER_SERVICE);
612             LauncherApps launcherApps = (LauncherApps) getSystemService(LAUNCHER_APPS_SERVICE);
613
614             for(AppEntry entry : pinnedApps) {
615                 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
616                         userManager.getUserForSerialNumber(entry.getUserId(this)));
617
618                 if(packageEnabled)
619                     entries.add(entry);
620                 else
621                     realNumOfPinnedApps--;
622
623                 applicationIdsToRemove.add(entry.getPackageName());
624             }
625             
626             realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
627         }
628
629         if(blockedApps.size() > 0) {
630             for(AppEntry entry : blockedApps) {
631                 applicationIdsToRemove.add(entry.getPackageName());
632             }
633         }
634
635         // Get list of all recently used apps
636         List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
637         if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
638             if(realNumOfPinnedApps < maxNumOfEntries) {
639                 List<AppEntry> usageStatsList2 = new ArrayList<>();
640                 List<AppEntry> usageStatsList3 = new ArrayList<>();
641                 List<AppEntry> usageStatsList4 = new ArrayList<>();
642                 List<AppEntry> usageStatsList5 = new ArrayList<>();
643                 List<AppEntry> usageStatsList6;
644
645                 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
646                 homeIntent.addCategory(Intent.CATEGORY_HOME);
647                 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
648
649                 // Filter out apps without a launcher intent
650                 // Also filter out the current launcher, and Taskbar itself
651                 for(AppEntry packageInfo : usageStatsList) {
652                     if(hasLauncherIntent(packageInfo.getPackageName())
653                             && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
654                             && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName))
655                         usageStatsList2.add(packageInfo);
656                 }
657
658                 // Filter out apps that don't fall within our current search interval
659                 for(AppEntry stats : usageStatsList2) {
660                     if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
661                         usageStatsList3.add(stats);
662                 }
663
664                 // Sort apps by either most recently used, or most time used
665                 if(!runningAppsOnly && sortOrder.contains("most_used")) {
666                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
667                 } else {
668                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
669                 }
670
671                 // Filter out any duplicate entries
672                 List<String> applicationIds = new ArrayList<>();
673                 for(AppEntry stats : usageStatsList3) {
674                     if(!applicationIds.contains(stats.getPackageName())) {
675                         usageStatsList4.add(stats);
676                         applicationIds.add(stats.getPackageName());
677                     }
678                 }
679
680                 // Filter out the currently running foreground app, if requested by the user
681                 if(pref.getBoolean("hide_foreground", false)) {
682                     UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(USAGE_STATS_SERVICE);
683                     UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
684                     UsageEvents.Event eventCache = new UsageEvents.Event();
685                     String currentForegroundApp = null;
686
687                     while(events.hasNextEvent()) {
688                         events.getNextEvent(eventCache);
689
690                         if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
691                             if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
692                                     && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
693                                     && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
694                                     && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName())))
695                                 currentForegroundApp = eventCache.getPackageName();
696                         }
697                     }
698
699                     if(!applicationIdsToRemove.contains(currentForegroundApp))
700                         applicationIdsToRemove.add(currentForegroundApp);
701                 }
702
703                 for(AppEntry stats : usageStatsList4) {
704                     if(!applicationIdsToRemove.contains(stats.getPackageName())) {
705                         usageStatsList5.add(stats);
706                     }
707                 }
708
709                 // Truncate list to a maximum length
710                 if(usageStatsList5.size() > maxNumOfEntries)
711                     usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
712                 else
713                     usageStatsList6 = usageStatsList5;
714
715                 // Determine if we need to reverse the order
716                 boolean needToReverseOrder;
717                 switch(U.getTaskbarPosition(this)) {
718                     case "bottom_right":
719                     case "top_right":
720                         needToReverseOrder = sortOrder.contains("false");
721                         break;
722                     default:
723                         needToReverseOrder = sortOrder.contains("true");
724                         break;
725                 }
726
727                 if(needToReverseOrder) {
728                     Collections.reverse(usageStatsList6);
729                 }
730
731                 // Generate the AppEntries for TaskbarAdapter
732                 int number = usageStatsList6.size() == maxNumOfEntries
733                         ? usageStatsList6.size() - realNumOfPinnedApps
734                         : usageStatsList6.size();
735
736                 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
737                 LauncherApps launcherApps = (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE);
738
739                 final List<UserHandle> userHandles = userManager.getUserProfiles();
740
741                 for(int i = 0; i < number; i++) {
742                     for(UserHandle handle : userHandles) {
743                         String packageName = usageStatsList6.get(i).getPackageName();
744                         List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
745                         if(!list.isEmpty()) {
746                             // Google App workaround
747                             if(!packageName.equals("com.google.android.googlequicksearchbox"))
748                                 launcherAppCache.add(list.get(0));
749                             else {
750                                 boolean added = false;
751                                 for(LauncherActivityInfo info : list) {
752                                     if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
753                                         launcherAppCache.add(info);
754                                         added = true;
755                                     }
756                                 }
757
758                                 if(!added) launcherAppCache.add(list.get(0));
759                             }
760
761                             AppEntry newEntry = new AppEntry(
762                                     packageName,
763                                     null,
764                                     null,
765                                     null,
766                                     false
767                             );
768
769                             newEntry.setUserId(userManager.getSerialNumberForUser(handle));
770                             entries.add(newEntry);
771
772                             break;
773                         }
774                     }
775                 }
776             }
777
778             while(entries.size() > maxNumOfEntries) {
779                 try {
780                     entries.remove(entries.size() - 1);
781                     launcherAppCache.remove(launcherAppCache.size() - 1);
782                 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
783             }
784
785             // Determine if we need to reverse the order again
786             if(U.getTaskbarPosition(this).contains("vertical")) {
787                 Collections.reverse(entries);
788                 Collections.reverse(launcherAppCache);
789             }
790
791             // Now that we've generated the list of apps,
792             // we need to determine if we need to redraw the Taskbar or not
793             boolean shouldRedrawTaskbar = firstRefresh;
794
795             List<String> finalApplicationIds = new ArrayList<>();
796             for(AppEntry entry : entries) {
797                 finalApplicationIds.add(entry.getPackageName());
798             }
799
800             if(finalApplicationIds.size() != currentTaskbarIds.size()
801                     || numOfPinnedApps != realNumOfPinnedApps)
802                 shouldRedrawTaskbar = true;
803             else {
804                 for(int i = 0; i < finalApplicationIds.size(); i++) {
805                     if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
806                         shouldRedrawTaskbar = true;
807                         break;
808                     }
809                 }
810             }
811
812             if(shouldRedrawTaskbar) {
813                 currentTaskbarIds = finalApplicationIds;
814                 numOfPinnedApps = realNumOfPinnedApps;
815
816                 UserManager userManager = (UserManager) getSystemService(USER_SERVICE);
817
818                 int launcherAppCachePos = -1;
819                 for(int i = 0; i < entries.size(); i++) {
820                     if(entries.get(i).getComponentName() == null) {
821                         launcherAppCachePos++;
822                         LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
823                         String packageName = entries.get(i).getPackageName();
824
825                         entries.remove(i);
826
827                         AppEntry newEntry = new AppEntry(
828                                 packageName,
829                                 appInfo.getComponentName().flattenToString(),
830                                 appInfo.getLabel().toString(),
831                                 IconCache.getInstance(this).getIcon(this, pm, appInfo),
832                                 false);
833
834                         newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
835                         entries.add(i, newEntry);
836                     }
837                 }
838
839                 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
840
841                 handler.post(() -> {
842                     if(numOfEntries > 0 || fullLength) {
843                         ViewGroup.LayoutParams params = scrollView.getLayoutParams();
844                         DisplayMetrics metrics = U.getRealDisplayMetrics(this);
845                         int recentsSize = getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries;
846                         float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
847
848                         if(U.getTaskbarPosition(this).contains("vertical")) {
849                             int maxScreenSize = metrics.heightPixels
850                                     - U.getStatusBarHeight(this)
851                                     - U.getBaseTaskbarSize(this);
852
853                             params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
854                                     + getResources().getDimensionPixelSize(R.dimen.divider_size);
855
856                             if(fullLength && U.getTaskbarPosition(this).contains("bottom")) {
857                                 try {
858                                     Space whitespace = U.findViewById(layout, R.id.whitespace);
859                                     ViewGroup.LayoutParams params2 = whitespace.getLayoutParams();
860                                     params2.height = maxScreenSize - recentsSize;
861                                     whitespace.setLayoutParams(params2);
862                                 } catch (NullPointerException e) { /* Gracefully fail */ }
863                             }
864                         } else {
865                             int maxScreenSize = metrics.widthPixels
866                                     - U.getBaseTaskbarSize(this);
867
868                             params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
869                                     + getResources().getDimensionPixelSize(R.dimen.divider_size);
870
871                             if(fullLength && U.getTaskbarPosition(this).contains("right")) {
872                                 try {
873                                     Space whitespace = U.findViewById(layout, R.id.whitespace);
874                                     ViewGroup.LayoutParams params2 = whitespace.getLayoutParams();
875                                     params2.width = maxScreenSize - recentsSize;
876                                     whitespace.setLayoutParams(params2);
877                                 } catch (NullPointerException e) { /* Gracefully fail */ }
878                             }
879                         }
880
881                         scrollView.setLayoutParams(params);
882
883                         taskbar.removeAllViews();
884                         for(int i = 0; i < entries.size(); i++) {
885                             taskbar.addView(getView(entries, i));
886                         }
887
888                         isShowingRecents = true;
889                         if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
890                             if(firstRefresh)
891                                 scrollView.setVisibility(View.INVISIBLE);
892                             else
893                                 scrollView.setVisibility(View.VISIBLE);
894                         }
895
896                         if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
897                             new Handler().post(() -> {
898                                 switch(U.getTaskbarPosition(this)) {
899                                     case "bottom_left":
900                                     case "bottom_right":
901                                     case "top_left":
902                                     case "top_right":
903                                         if(sortOrder.contains("false"))
904                                             scrollView.scrollTo(0, 0);
905                                         else if(sortOrder.contains("true"))
906                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
907                                         break;
908                                     case "bottom_vertical_left":
909                                     case "bottom_vertical_right":
910                                     case "top_vertical_left":
911                                     case "top_vertical_right":
912                                         if(sortOrder.contains("false"))
913                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
914                                         else if(sortOrder.contains("true"))
915                                             scrollView.scrollTo(0, 0);
916                                         break;
917                                 }
918
919                                 if(shouldRefreshRecents) {
920                                     scrollView.setVisibility(View.VISIBLE);
921                                 }
922                             });
923                     } else {
924                         isShowingRecents = false;
925                         scrollView.setVisibility(View.GONE);
926                     }
927                 });
928             }
929         } else if(firstRefresh || currentTaskbarIds.size() > 0) {
930             currentTaskbarIds.clear();
931             handler.post(() -> {
932                 isShowingRecents = false;
933                 scrollView.setVisibility(View.GONE);
934             });
935         }
936     }
937
938     private void toggleTaskbar() {
939         if(startButton.getVisibility() == View.GONE)
940             showTaskbar(true);
941         else
942             hideTaskbar(true);
943     }
944
945     private void showTaskbar(boolean clearVariables) {
946         if(clearVariables) {
947             taskbarShownTemporarily = false;
948             taskbarHiddenTemporarily = false;
949         }
950
951         if(startButton.getVisibility() == View.GONE) {
952             startButton.setVisibility(View.VISIBLE);
953             space.setVisibility(View.VISIBLE);
954
955             if(dashboardEnabled)
956                 dashboardButton.setVisibility(View.VISIBLE);
957
958             if(navbarButtonsEnabled)
959                 navbarButtons.setVisibility(View.VISIBLE);
960
961             if(isShowingRecents && scrollView.getVisibility() == View.GONE)
962                 scrollView.setVisibility(View.INVISIBLE);
963
964             shouldRefreshRecents = true;
965             startRefreshingRecents();
966
967             SharedPreferences pref = U.getSharedPreferences(this);
968             pref.edit().putBoolean("collapsed", true).apply();
969
970             updateButton(false);
971
972             new Handler().post(() -> LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
973         }
974     }
975
976     private void hideTaskbar(boolean clearVariables) {
977         if(clearVariables) {
978             taskbarShownTemporarily = false;
979             taskbarHiddenTemporarily = false;
980         }
981
982         if(startButton.getVisibility() == View.VISIBLE) {
983             startButton.setVisibility(View.GONE);
984             space.setVisibility(View.GONE);
985
986             if(dashboardEnabled)
987                 dashboardButton.setVisibility(View.GONE);
988
989             if(navbarButtonsEnabled)
990                 navbarButtons.setVisibility(View.GONE);
991
992             if(isShowingRecents) {
993                 scrollView.setVisibility(View.GONE);
994             }
995
996             shouldRefreshRecents = false;
997             if(thread != null) thread.interrupt();
998
999             SharedPreferences pref = U.getSharedPreferences(this);
1000             pref.edit().putBoolean("collapsed", false).apply();
1001
1002             updateButton(true);
1003
1004             LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
1005             LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD"));
1006
1007             new Handler().post(() -> LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU_SPACE")));
1008         }
1009     }
1010
1011     private void tempShowTaskbar() {
1012         if(!taskbarHiddenTemporarily) {
1013             SharedPreferences pref = U.getSharedPreferences(this);
1014             if(!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true;
1015         }
1016
1017         showTaskbar(false);
1018
1019         if(taskbarHiddenTemporarily)
1020             taskbarHiddenTemporarily = false;
1021     }
1022
1023     private void tempHideTaskbar(boolean monitorPositionChanges) {
1024         if(!taskbarShownTemporarily) {
1025             SharedPreferences pref = U.getSharedPreferences(this);
1026             if(pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true;
1027         }
1028
1029         hideTaskbar(false);
1030
1031         if(taskbarShownTemporarily)
1032             taskbarShownTemporarily = false;
1033
1034         if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1035             if(thread2 != null) thread2.interrupt();
1036
1037             handler2 = new Handler();
1038             thread2 = new Thread(() -> {
1039                 stopThread2 = false;
1040
1041                 while(!stopThread2) {
1042                     SystemClock.sleep(refreshInterval);
1043
1044                     handler2.post(() -> stopThread2 = checkPositionChange());
1045                 }
1046
1047                 startThread2 = false;
1048             });
1049
1050             thread2.start();
1051         }
1052     }
1053
1054     private boolean checkPositionChange() {
1055         if(!isScreenOff() && layout != null) {
1056             int[] location = new int[2];
1057             layout.getLocationOnScreen(location);
1058
1059             if(location[1] == 0) {
1060                 return true;
1061             } else {
1062                 if(location[1] > currentTaskbarPosition) {
1063                     currentTaskbarPosition = location[1];
1064                     if(taskbarHiddenTemporarily) {
1065                         tempShowTaskbar();
1066                         return true;
1067                     }
1068                 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1069                     tempShowTaskbar();
1070                     return true;
1071                 } else if(location[1] < currentTaskbarPosition
1072                         && currentTaskbarPosition - location[1] == getNavBarSize()) {
1073                     currentTaskbarPosition = location[1];
1074                 }
1075             }
1076         }
1077
1078         return false;
1079     }
1080
1081     private int getNavBarSize() {
1082         Point size = new Point();
1083         Point realSize = new Point();
1084
1085         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
1086         Display display = wm.getDefaultDisplay();
1087         display.getSize(size);
1088         display.getRealSize(realSize);
1089
1090         return realSize.y - size.y;
1091     }
1092
1093     @Override
1094     public void onDestroy() {
1095         shouldRefreshRecents = false;
1096
1097         super.onDestroy();
1098         if(layout != null)
1099             try {
1100                 windowManager.removeView(layout);
1101             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1102
1103         SharedPreferences pref = U.getSharedPreferences(this);
1104         if(pref.getBoolean("skip_auto_hide_navbar", false)) {
1105             pref.edit().remove("skip_auto_hide_navbar").apply();
1106         } else if(pref.getBoolean("auto_hide_navbar", false))
1107             U.showHideNavigationBar(this, true);
1108
1109         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
1110
1111         lbm.unregisterReceiver(showReceiver);
1112         lbm.unregisterReceiver(hideReceiver);
1113         lbm.unregisterReceiver(tempShowReceiver);
1114         lbm.unregisterReceiver(tempHideReceiver);
1115         lbm.unregisterReceiver(startMenuAppearReceiver);
1116         lbm.unregisterReceiver(startMenuDisappearReceiver);
1117
1118         isFirstStart = true;
1119     }
1120
1121     @SuppressWarnings("deprecation")
1122     private void openContextMenu() {
1123         SharedPreferences pref = U.getSharedPreferences(this);
1124         Intent intent = null;
1125
1126         switch(pref.getString("theme", "light")) {
1127             case "light":
1128                 intent = new Intent(this, ContextMenuActivity.class);
1129                 break;
1130             case "dark":
1131                 intent = new Intent(this, ContextMenuActivityDark.class);
1132                 break;
1133         }
1134
1135         if(intent != null) {
1136             intent.putExtra("dont_show_quit", LauncherHelper.getInstance().isOnHomeScreen() && !pref.getBoolean("taskbar_active", false));
1137             intent.putExtra("is_start_button", true);
1138             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1139         }
1140
1141         if(U.hasFreeformSupport(this) && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
1142             DisplayMetrics metrics = U.getRealDisplayMetrics(this);
1143
1144             if(intent != null && U.hasBrokenSetLaunchBoundsApi())
1145                 intent.putExtra("context_menu_fix", true);
1146
1147             startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
1148         } else
1149             startActivity(intent);
1150     }
1151
1152     private void updateButton(boolean isCollapsed) {
1153         SharedPreferences pref = U.getSharedPreferences(this);
1154         boolean hide = pref.getBoolean("invisible_button", false);
1155
1156         if(button != null) button.setText(getString(isCollapsed ? R.string.right_arrow : R.string.left_arrow));
1157         if(layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1);
1158     }
1159
1160     @TargetApi(Build.VERSION_CODES.M)
1161     @Override
1162     public void onConfigurationChanged(Configuration newConfig) {
1163         super.onConfigurationChanged(newConfig);
1164
1165         if(layout != null) {
1166             try {
1167                 windowManager.removeView(layout);
1168             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1169
1170             currentTaskbarPosition = 0;
1171
1172             if(U.canDrawOverlays(this))
1173                 drawTaskbar();
1174             else {
1175                 SharedPreferences pref = U.getSharedPreferences(this);
1176                 pref.edit().putBoolean("taskbar_active", false).apply();
1177
1178                 stopSelf();
1179             }
1180         }
1181     }
1182
1183     private View getView(List<AppEntry> list, int position) {
1184         View convertView = View.inflate(this, R.layout.icon, null);
1185
1186         final AppEntry entry = list.get(position);
1187         final SharedPreferences pref = U.getSharedPreferences(this);
1188
1189         ImageView imageView = U.findViewById(convertView, R.id.icon);
1190         ImageView imageView2 = U.findViewById(convertView, R.id.shortcut_icon);
1191         imageView.setImageDrawable(entry.getIcon(this));
1192         imageView2.setBackgroundColor(pref.getInt("accent_color", getResources().getInteger(R.integer.translucent_white)));
1193
1194         String taskbarPosition = U.getTaskbarPosition(this);
1195         if(pref.getBoolean("shortcut_icon", true)) {
1196             boolean shouldShowShortcutIcon;
1197             if(taskbarPosition.contains("vertical"))
1198                 shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps;
1199             else
1200                 shouldShowShortcutIcon = position < numOfPinnedApps;
1201
1202             if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1203         }
1204
1205         if(taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) {
1206             imageView.setRotationY(180);
1207             imageView2.setRotationY(180);
1208         }
1209
1210         FrameLayout layout = U.findViewById(convertView, R.id.entry);
1211         layout.setOnClickListener(view -> U.launchApp(this, entry.getPackageName(), entry.getComponentName(), entry.getUserId(this), null, true, false));
1212
1213         layout.setOnLongClickListener(view -> {
1214             int[] location = new int[2];
1215             view.getLocationOnScreen(location);
1216             openContextMenu(entry, location);
1217             return true;
1218         });
1219
1220         layout.setOnGenericMotionListener((view, motionEvent) -> {
1221             int action = motionEvent.getAction();
1222
1223             if(action == MotionEvent.ACTION_BUTTON_PRESS
1224                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
1225                 int[] location = new int[2];
1226                 view.getLocationOnScreen(location);
1227                 openContextMenu(entry, location);
1228             }
1229
1230             if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true))
1231                 view.setBackgroundColor(0);
1232
1233             return false;
1234         });
1235
1236         if(pref.getBoolean("visual_feedback", true)) {
1237             layout.setOnHoverListener((v, event) -> {
1238                 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
1239                     int accentColor = U.getAccentColor(this);
1240                     accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2);
1241                     v.setBackgroundColor(accentColor);
1242                 }
1243
1244                 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1245                     v.setBackgroundColor(0);
1246
1247                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1248                     v.setPointerIcon(PointerIcon.getSystemIcon(this, PointerIcon.TYPE_DEFAULT));
1249
1250                 return false;
1251             });
1252
1253             layout.setOnTouchListener((v, event) -> {
1254                 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1255                 return false;
1256             });
1257         }
1258
1259         return convertView;
1260     }
1261
1262     @SuppressWarnings("deprecation")
1263     private void openContextMenu(AppEntry entry, int[] location) {
1264         SharedPreferences pref = U.getSharedPreferences(this);
1265         Intent intent = null;
1266
1267         switch(pref.getString("theme", "light")) {
1268             case "light":
1269                 intent = new Intent(this, ContextMenuActivity.class);
1270                 break;
1271             case "dark":
1272                 intent = new Intent(this, ContextMenuActivityDark.class);
1273                 break;
1274         }
1275
1276         if(intent != null) {
1277             intent.putExtra("package_name", entry.getPackageName());
1278             intent.putExtra("app_name", entry.getLabel());
1279             intent.putExtra("component_name", entry.getComponentName());
1280             intent.putExtra("user_id", entry.getUserId(this));
1281             intent.putExtra("x", location[0]);
1282             intent.putExtra("y", location[1]);
1283             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1284         }
1285
1286         if(U.hasFreeformSupport(this) && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
1287             DisplayMetrics metrics = U.getRealDisplayMetrics(this);
1288
1289             if(intent != null && U.hasBrokenSetLaunchBoundsApi())
1290                 intent.putExtra("context_menu_fix", true);
1291
1292             startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
1293         } else
1294             startActivity(intent);
1295     }
1296
1297     private List<AppEntry> getAppEntries() {
1298         SharedPreferences pref = U.getSharedPreferences(this);
1299         if(runningAppsOnly)
1300             return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10")));
1301         else
1302             return getAppEntriesUsingUsageStats();
1303     }
1304
1305     @SuppressWarnings("deprecation")
1306     @TargetApi(Build.VERSION_CODES.M)
1307     private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) {
1308         ActivityManager mActivityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
1309         List<ActivityManager.RecentTaskInfo> usageStatsList = mActivityManager.getRecentTasks(maxNum, 0);
1310         List<AppEntry> entries = new ArrayList<>();
1311
1312         for(int i = 0; i < usageStatsList.size(); i++) {
1313             ActivityManager.RecentTaskInfo recentTaskInfo = usageStatsList.get(i);
1314             if(recentTaskInfo.id != -1) {
1315                 String packageName = recentTaskInfo.baseActivity.getPackageName();
1316                 AppEntry newEntry = new AppEntry(
1317                         packageName,
1318                         null,
1319                         null,
1320                         null,
1321                         false
1322                 );
1323
1324                 try {
1325                     Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1326                     newEntry.setLastTimeUsed(field.getLong(recentTaskInfo));
1327                 } catch (Exception e) {
1328                     newEntry.setLastTimeUsed(i);
1329                 }
1330
1331                 entries.add(newEntry);
1332             }
1333         }
1334
1335         return entries;
1336     }
1337
1338     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
1339     private List<AppEntry> getAppEntriesUsingUsageStats() {
1340         UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(USAGE_STATS_SERVICE);
1341         List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, searchInterval, System.currentTimeMillis());
1342         List<AppEntry> entries = new ArrayList<>();
1343
1344         for(UsageStats usageStats : usageStatsList) {
1345             AppEntry newEntry = new AppEntry(
1346                     usageStats.getPackageName(),
1347                     null,
1348                     null,
1349                     null,
1350                     false
1351             );
1352
1353             newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1354             newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1355             entries.add(newEntry);
1356         }
1357
1358         return entries;
1359     }
1360
1361     private boolean hasLauncherIntent(String packageName) {
1362         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1363         intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1364         intentToResolve.setPackage(packageName);
1365
1366         List<ResolveInfo> ris = getPackageManager().queryIntentActivities(intentToResolve, 0);
1367         return ris != null && ris.size() > 0;
1368     }
1369
1370     private boolean isScreenOff() {
1371         if(U.isChromeOs(this))
1372             return false;
1373
1374         PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
1375         return !pm.isInteractive();
1376     }
1377 }