OSDN Git Service

Fixes
[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.bluetooth.BluetoothAdapter;
27 import android.content.ActivityNotFoundException;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.SharedPreferences;
33 import android.content.pm.LauncherActivityInfo;
34 import android.content.pm.LauncherApps;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ResolveInfo;
37 import android.graphics.Color;
38 import android.graphics.Point;
39 import android.graphics.Typeface;
40 import android.graphics.drawable.Drawable;
41 import android.net.ConnectivityManager;
42 import android.net.NetworkInfo;
43 import android.net.Uri;
44 import android.net.wifi.WifiInfo;
45 import android.net.wifi.WifiManager;
46 import android.os.BatteryManager;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.PowerManager;
51 import android.os.SystemClock;
52 import android.os.UserHandle;
53 import android.os.UserManager;
54 import android.provider.Settings;
55 import android.speech.RecognizerIntent;
56 import android.support.v4.content.ContextCompat;
57 import android.support.v4.graphics.ColorUtils;
58 import android.telephony.PhoneStateListener;
59 import android.telephony.SignalStrength;
60 import android.telephony.TelephonyManager;
61 import android.text.format.DateFormat;
62 import android.view.Display;
63 import android.view.Gravity;
64 import android.view.LayoutInflater;
65 import android.view.MotionEvent;
66 import android.view.PointerIcon;
67 import android.view.View;
68 import android.view.ViewGroup;
69 import android.view.WindowManager;
70 import android.view.inputmethod.InputMethodManager;
71 import android.widget.Button;
72 import android.widget.FrameLayout;
73 import android.widget.ImageView;
74
75 import java.io.File;
76 import java.lang.reflect.Field;
77 import java.util.ArrayList;
78 import java.util.Collections;
79 import java.util.Date;
80 import java.util.List;
81
82 import android.support.v4.content.LocalBroadcastManager;
83 import android.widget.LinearLayout;
84 import android.widget.Space;
85 import android.widget.TextView;
86
87 import com.farmerbb.taskbar.BuildConfig;
88 import com.farmerbb.taskbar.activity.HomeActivityDelegate;
89 import com.farmerbb.taskbar.activity.MainActivity;
90 import com.farmerbb.taskbar.R;
91 import com.farmerbb.taskbar.activity.HomeActivity;
92 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
93 import com.farmerbb.taskbar.util.AppEntry;
94 import com.farmerbb.taskbar.util.DisplayInfo;
95 import com.farmerbb.taskbar.util.FreeformHackHelper;
96 import com.farmerbb.taskbar.util.IconCache;
97 import com.farmerbb.taskbar.util.LauncherHelper;
98 import com.farmerbb.taskbar.util.PinnedBlockedApps;
99 import com.farmerbb.taskbar.util.MenuHelper;
100 import com.farmerbb.taskbar.util.U;
101
102 public class TaskbarController implements UIController {
103
104     private Context context;
105     private LinearLayout layout;
106     private ImageView startButton;
107     private LinearLayout taskbar;
108     private FrameLayout scrollView;
109     private Button button;
110     private Space space;
111     private FrameLayout dashboardButton;
112     private LinearLayout navbarButtons;
113     private LinearLayout sysTrayLayout;
114     private FrameLayout sysTrayParentLayout;
115     private TextView time;
116
117     private Handler handler;
118     private Handler handler2;
119     private Thread thread;
120     private Thread thread2;
121
122     private boolean isShowingRecents = true;
123     private boolean shouldRefreshRecents = true;
124     private boolean taskbarShownTemporarily = false;
125     private boolean taskbarHiddenTemporarily = false;
126     private boolean isRefreshingRecents = false;
127     private boolean isFirstStart = true;
128
129     private boolean startThread2 = false;
130     private boolean stopThread2 = false;
131
132     private int refreshInterval = -1;
133     private long searchInterval = -1;
134     private String sortOrder = "false";
135     private boolean runningAppsOnly = false;
136
137     private int layoutId = R.layout.taskbar_left;
138     private int currentTaskbarPosition = 0;
139     private boolean showHideAutomagically = false;
140     private boolean positionIsVertical = false;
141     private boolean dashboardEnabled = false;
142     private boolean navbarButtonsEnabled = false;
143     private boolean sysTrayEnabled = false;
144
145     private List<String> currentTaskbarIds = new ArrayList<>();
146     private List<String> currentRunningAppIds = new ArrayList<>();
147     private List<String> prevRunningAppIds = new ArrayList<>();
148     private int numOfPinnedApps = -1;
149
150     private int cellStrength = -1;
151
152     private View.OnClickListener ocl = view -> {
153         Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU");
154         LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
155     };
156
157     private BroadcastReceiver showReceiver = new BroadcastReceiver() {
158         @Override
159         public void onReceive(Context context, Intent intent) {
160             showTaskbar(true);
161         }
162     };
163
164     private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
165         @Override
166         public void onReceive(Context context, Intent intent) {
167             hideTaskbar(true);
168         }
169     };
170
171     private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
172         @Override
173         public void onReceive(Context context, Intent intent) {
174             tempShowTaskbar();
175         }
176     };
177
178     private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
179         @Override
180         public void onReceive(Context context, Intent intent) {
181             tempHideTaskbar(false);
182         }
183     };
184
185     private BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
186         @Override
187         public void onReceive(Context context, Intent intent) {
188             if(startButton.getVisibility() == View.GONE
189                     && (!LauncherHelper.getInstance().isOnHomeScreen() || FreeformHackHelper.getInstance().isInFreeformWorkspace()))
190                 layout.setVisibility(View.GONE);
191         }
192     };
193
194     private BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
195         @Override
196         public void onReceive(Context context, Intent intent) {
197             if(startButton.getVisibility() == View.GONE)
198                 layout.setVisibility(View.VISIBLE);
199         }
200     };
201
202     @TargetApi(Build.VERSION_CODES.M)
203     private PhoneStateListener listener = new PhoneStateListener() {
204         @Override
205         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
206             cellStrength = signalStrength.getLevel();
207         }
208     };
209
210     public TaskbarController(Context context) {
211         this.context = context;
212     }
213
214     @TargetApi(Build.VERSION_CODES.M)
215     @Override
216     public void onCreateHost(UIHost host) {
217         SharedPreferences pref = U.getSharedPreferences(context);
218         if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
219             if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
220                 drawTaskbar(host);
221             else {
222                 pref.edit().putBoolean("taskbar_active", false).apply();
223
224                 host.terminate();
225             }
226         } else host.terminate();
227     }
228
229     @SuppressLint("RtlHardcoded")
230     private void drawTaskbar(UIHost host) {
231         IconCache.getInstance(context).clearCache();
232
233         // Initialize layout params
234         WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
235         U.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
236
237         final ViewParams params = new ViewParams(
238                 WindowManager.LayoutParams.WRAP_CONTENT,
239                 WindowManager.LayoutParams.WRAP_CONTENT,
240                 -1,
241                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
242         );
243
244         // Determine where to show the taskbar on screen
245         switch(U.getTaskbarPosition(context)) {
246             case "bottom_left":
247                 layoutId = R.layout.taskbar_left;
248                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
249                 positionIsVertical = false;
250                 break;
251             case "bottom_vertical_left":
252                 layoutId = R.layout.taskbar_vertical;
253                 params.gravity = Gravity.BOTTOM | Gravity.LEFT;
254                 positionIsVertical = true;
255                 break;
256             case "bottom_right":
257                 layoutId = R.layout.taskbar_right;
258                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
259                 positionIsVertical = false;
260                 break;
261             case "bottom_vertical_right":
262                 layoutId = R.layout.taskbar_vertical;
263                 params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
264                 positionIsVertical = true;
265                 break;
266             case "top_left":
267                 layoutId = R.layout.taskbar_left;
268                 params.gravity = Gravity.TOP | Gravity.LEFT;
269                 positionIsVertical = false;
270                 break;
271             case "top_vertical_left":
272                 layoutId = R.layout.taskbar_top_vertical;
273                 params.gravity = Gravity.TOP | Gravity.LEFT;
274                 positionIsVertical = true;
275                 break;
276             case "top_right":
277                 layoutId = R.layout.taskbar_right;
278                 params.gravity = Gravity.TOP | Gravity.RIGHT;
279                 positionIsVertical = false;
280                 break;
281             case "top_vertical_right":
282                 layoutId = R.layout.taskbar_top_vertical;
283                 params.gravity = Gravity.TOP | Gravity.RIGHT;
284                 positionIsVertical = true;
285                 break;
286         }
287
288         // Initialize views
289         SharedPreferences pref = U.getSharedPreferences(context);
290         boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
291
292         layout = (LinearLayout) LayoutInflater.from(U.wrapContext(context)).inflate(layoutId, null);
293         taskbar = layout.findViewById(R.id.taskbar);
294         scrollView = layout.findViewById(R.id.taskbar_scrollview);
295
296         int backgroundTint = U.getBackgroundTint(context);
297         int accentColor = U.getAccentColor(context);
298
299         if(altButtonConfig) {
300             space = layout.findViewById(R.id.space_alt);
301             layout.findViewById(R.id.space).setVisibility(View.GONE);
302         } else {
303             space = layout.findViewById(R.id.space);
304             layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
305         }
306
307         space.setOnClickListener(v -> toggleTaskbar(true));
308
309         startButton = layout.findViewById(R.id.start_button);
310         int padding = 0;
311
312         switch(pref.getString("start_button_image", U.getDefaultStartButtonImage(context))) {
313             case "default":
314                 startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
315                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
316                 break;
317             case "app_logo":
318                 Drawable drawable;
319
320                 if(U.isBlissOs(context)) {
321                     drawable = ContextCompat.getDrawable(context, R.drawable.bliss);
322                     drawable.setTint(accentColor);
323                 } else
324                     drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher);
325
326                 startButton.setImageDrawable(drawable);
327                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
328                 break;
329             case "custom":
330                 File file = new File(context.getFilesDir() + "/images", "custom_image");
331                 if(file.exists()) {
332                     try {
333                         startButton.setImageURI(Uri.fromFile(file));
334                     } catch (Exception e) {
335                         U.showToastLong(context, R.string.error_reading_custom_start_image);
336                         startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
337                     }
338                 } else
339                     startButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.all_apps_button_icon));
340
341                 padding = context.getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding);
342                 break;
343         }
344
345         startButton.setPadding(padding, padding, padding, padding);
346         startButton.setOnClickListener(ocl);
347         startButton.setOnLongClickListener(view -> {
348             openContextMenu();
349             return true;
350         });
351
352         startButton.setOnGenericMotionListener((view, motionEvent) -> {
353             if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
354                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
355                 openContextMenu();
356
357             return false;
358         });
359
360         refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000);
361         if(refreshInterval == 0)
362             refreshInterval = 100;
363
364         sortOrder = pref.getString("sort_order", "false");
365         runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only");
366
367         switch(pref.getString("recents_amount", "past_day")) {
368             case "past_day":
369                 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
370                 break;
371             case "app_start":
372                 long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis());
373                 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
374
375                 searchInterval = deviceStartTime > appStartTime ? deviceStartTime : appStartTime;
376                 break;
377             case "show_all":
378                 searchInterval = 0;
379                 break;
380         }
381
382         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
383         lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
384         lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.UPDATE_HOME_SCREEN_MARGINS"));
385
386         if(altButtonConfig) {
387             button = layout.findViewById(R.id.hide_taskbar_button_alt);
388             layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
389         } else {
390             button = layout.findViewById(R.id.hide_taskbar_button);
391             layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
392         }
393
394         try {
395             button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
396         } catch (RuntimeException e) { /* Gracefully fail */ }
397
398         updateButton(false);
399         button.setOnClickListener(v -> toggleTaskbar(true));
400
401         LinearLayout buttonLayout = layout.findViewById(altButtonConfig
402                 ? R.id.hide_taskbar_button_layout_alt
403                 : R.id.hide_taskbar_button_layout);
404         if(buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar(true));
405
406         LinearLayout buttonLayoutToHide = layout.findViewById(altButtonConfig
407                 ? R.id.hide_taskbar_button_layout
408                 : R.id.hide_taskbar_button_layout_alt);
409         if(buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE);
410
411         dashboardButton = layout.findViewById(R.id.dashboard_button);
412         navbarButtons = layout.findViewById(R.id.navbar_buttons);
413
414         dashboardEnabled = pref.getBoolean("dashboard", false);
415         if(dashboardEnabled) {
416             layout.findViewById(R.id.square1).setBackgroundColor(accentColor);
417             layout.findViewById(R.id.square2).setBackgroundColor(accentColor);
418             layout.findViewById(R.id.square3).setBackgroundColor(accentColor);
419             layout.findViewById(R.id.square4).setBackgroundColor(accentColor);
420             layout.findViewById(R.id.square5).setBackgroundColor(accentColor);
421             layout.findViewById(R.id.square6).setBackgroundColor(accentColor);
422
423             dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD")));
424         } else
425             dashboardButton.setVisibility(View.GONE);
426
427         if(pref.getBoolean("button_back", false)) {
428             navbarButtonsEnabled = true;
429
430             ImageView backButton = layout.findViewById(R.id.button_back);
431             backButton.setColorFilter(accentColor);
432             backButton.setVisibility(View.VISIBLE);
433             backButton.setOnClickListener(v -> {
434                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_BACK);
435                 if(U.shouldCollapse(context, false))
436                     hideTaskbar(true);
437             });
438
439             backButton.setOnLongClickListener(v -> {
440                 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
441                 imm.showInputMethodPicker();
442
443                 if(U.shouldCollapse(context, false))
444                     hideTaskbar(true);
445
446                 return true;
447             });
448
449             backButton.setOnGenericMotionListener((view13, motionEvent) -> {
450                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
451                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
452                     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
453                     imm.showInputMethodPicker();
454
455                     if(U.shouldCollapse(context, false))
456                         hideTaskbar(true);
457                 }
458                 return true;
459             });
460         }
461
462         if(pref.getBoolean("button_home", false)) {
463             navbarButtonsEnabled = true;
464
465             ImageView homeButton = layout.findViewById(R.id.button_home);
466             homeButton.setColorFilter(accentColor);
467             homeButton.setVisibility(View.VISIBLE);
468             homeButton.setOnClickListener(v -> {
469                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_HOME);
470                 if(U.shouldCollapse(context, false))
471                     hideTaskbar(true);
472             });
473
474             homeButton.setOnLongClickListener(v -> {
475                 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
476                 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
477
478                 try {
479                     context.startActivity(voiceSearchIntent);
480                 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
481
482                 if(U.shouldCollapse(context, false))
483                     hideTaskbar(true);
484
485                 return true;
486             });
487
488             homeButton.setOnGenericMotionListener((view13, motionEvent) -> {
489                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
490                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
491                     Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
492                     voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
493
494                     try {
495                         context.startActivity(voiceSearchIntent);
496                     } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
497
498                     if(U.shouldCollapse(context, false))
499                         hideTaskbar(true);
500                 }
501                 return true;
502             });
503         }
504
505         if(pref.getBoolean("button_recents", false)) {
506             navbarButtonsEnabled = true;
507
508             ImageView recentsButton = layout.findViewById(R.id.button_recents);
509             recentsButton.setColorFilter(accentColor);
510             recentsButton.setVisibility(View.VISIBLE);
511             recentsButton.setOnClickListener(v -> {
512                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_RECENTS);
513                 if(U.shouldCollapse(context, false))
514                     hideTaskbar(true);
515             });
516
517             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
518                 recentsButton.setOnLongClickListener(v -> {
519                     U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
520                     if(U.shouldCollapse(context, false))
521                         hideTaskbar(true);
522
523                     return true;
524                 });
525
526                 recentsButton.setOnGenericMotionListener((view13, motionEvent) -> {
527                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
528                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
529                         U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
530                         if(U.shouldCollapse(context, false))
531                             hideTaskbar(true);
532                     }
533                     return true;
534                 });
535             }
536         }
537
538         if(!navbarButtonsEnabled)
539             navbarButtons.setVisibility(View.GONE);
540
541         sysTrayEnabled = pref.getBoolean("sys_tray", false)
542                 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
543                 && !positionIsVertical;
544
545         if(sysTrayEnabled) {
546             sysTrayLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.system_tray, null);
547
548             FrameLayout.LayoutParams sysTrayParams = new FrameLayout.LayoutParams(
549                     FrameLayout.LayoutParams.WRAP_CONTENT,
550                     context.getResources().getDimensionPixelSize(R.dimen.icon_size)
551             );
552
553             if(layoutId == R.layout.taskbar_right) {
554                 time = sysTrayLayout.findViewById(R.id.time_left);
555                 sysTrayParams.gravity = Gravity.START;
556             } else {
557                 time = sysTrayLayout.findViewById(R.id.time_right);
558                 sysTrayParams.gravity = Gravity.END;
559             }
560
561             time.setVisibility(View.VISIBLE);
562             sysTrayLayout.setLayoutParams(sysTrayParams);
563
564             sysTrayLayout.setOnClickListener(v -> {
565                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
566                 if(U.shouldCollapse(context, false))
567                     hideTaskbar(true);
568             });
569
570             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
571                 sysTrayLayout.setOnLongClickListener(v -> {
572                     U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
573                     if(U.shouldCollapse(context, false))
574                         hideTaskbar(true);
575
576                     return true;
577                 });
578
579                 sysTrayLayout.setOnGenericMotionListener((view, motionEvent) -> {
580                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
581                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
582                         U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
583                         if(U.shouldCollapse(context, false))
584                             hideTaskbar(true);
585                     }
586                     return true;
587                 });
588             }
589
590             sysTrayParentLayout = layout.findViewById(R.id.add_systray_here);
591             sysTrayParentLayout.setVisibility(View.VISIBLE);
592             sysTrayParentLayout.addView(sysTrayLayout);
593
594             TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
595             manager.listen(listener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
596         }
597
598         layout.setBackgroundColor(backgroundTint);
599         layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
600         button.setTextColor(accentColor);
601
602         if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
603             showTaskbar(false);
604         else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
605             toggleTaskbar(false);
606
607         if(pref.getBoolean("auto_hide_navbar", false))
608             U.showHideNavigationBar(context, false);
609
610         if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
611             lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
612
613             new Handler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
614         }
615
616         lbm.unregisterReceiver(showReceiver);
617         lbm.unregisterReceiver(hideReceiver);
618         lbm.unregisterReceiver(tempShowReceiver);
619         lbm.unregisterReceiver(tempHideReceiver);
620         lbm.unregisterReceiver(startMenuAppearReceiver);
621         lbm.unregisterReceiver(startMenuDisappearReceiver);
622
623         lbm.registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR"));
624         lbm.registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR"));
625         lbm.registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
626         lbm.registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
627         lbm.registerReceiver(startMenuAppearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_APPEARING"));
628         lbm.registerReceiver(startMenuDisappearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
629
630         startRefreshingRecents();
631
632         host.addView(layout, params);
633
634         isFirstStart = false;
635     }
636
637     private void startRefreshingRecents() {
638         if(thread != null) thread.interrupt();
639         stopThread2 = true;
640
641         SharedPreferences pref = U.getSharedPreferences(context);
642         showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
643
644         currentTaskbarIds.clear();
645
646         handler = new Handler();
647         thread = new Thread(() -> {
648             updateSystemTray();
649             updateRecentApps(true);
650
651             if(!isRefreshingRecents) {
652                 isRefreshingRecents = true;
653
654                 while(shouldRefreshRecents) {
655                     SystemClock.sleep(refreshInterval);
656                     updateSystemTray();
657                     updateRecentApps(false);
658
659                     if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
660                         handler.post(() -> {
661                             if(layout != null) {
662                                 int[] location = new int[2];
663                                 layout.getLocationOnScreen(location);
664
665                                 if(location[1] != 0) {
666                                     if(location[1] > currentTaskbarPosition) {
667                                         currentTaskbarPosition = location[1];
668                                     } else if(location[1] < currentTaskbarPosition) {
669                                         if(currentTaskbarPosition - location[1] == getNavBarSize())
670                                             currentTaskbarPosition = location[1];
671                                         else if(!startThread2) {
672                                             startThread2 = true;
673                                             tempHideTaskbar(true);
674                                         }
675                                     }
676                                 }
677                             }
678                         });
679                 }
680
681                 isRefreshingRecents = false;
682             }
683         });
684
685         thread.start();
686     }
687
688     @SuppressWarnings("Convert2streamapi")
689     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
690     private void updateRecentApps(final boolean firstRefresh) {
691         if(isScreenOff()) return;
692
693         SharedPreferences pref = U.getSharedPreferences(context);
694         final PackageManager pm = context.getPackageManager();
695         final List<AppEntry> entries = new ArrayList<>();
696         List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
697         int maxNumOfEntries = U.getMaxNumOfEntries(context);
698         int realNumOfPinnedApps = 0;
699         boolean fullLength = pref.getBoolean("full_length", false);
700
701         if(runningAppsOnly)
702             currentRunningAppIds.clear();
703
704         PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
705         List<AppEntry> pinnedApps = setTimeLastUsedFor(pba.getPinnedApps());
706         List<AppEntry> blockedApps = pba.getBlockedApps();
707         List<String> applicationIdsToRemove = new ArrayList<>();
708
709         // Filter out anything on the pinned/blocked apps lists
710         if(pinnedApps.size() > 0) {
711             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
712             LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
713
714             for(AppEntry entry : pinnedApps) {
715                 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
716                         userManager.getUserForSerialNumber(entry.getUserId(context)));
717
718                 if(packageEnabled)
719                     entries.add(entry);
720                 else
721                     realNumOfPinnedApps--;
722
723                 applicationIdsToRemove.add(entry.getPackageName());
724             }
725
726             realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
727         }
728
729         if(blockedApps.size() > 0) {
730             for(AppEntry entry : blockedApps) {
731                 applicationIdsToRemove.add(entry.getPackageName());
732             }
733         }
734
735         // Get list of all recently used apps
736         List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
737         if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
738             if(realNumOfPinnedApps < maxNumOfEntries) {
739                 List<AppEntry> usageStatsList2 = new ArrayList<>();
740                 List<AppEntry> usageStatsList3 = new ArrayList<>();
741                 List<AppEntry> usageStatsList4 = new ArrayList<>();
742                 List<AppEntry> usageStatsList5 = new ArrayList<>();
743                 List<AppEntry> usageStatsList6;
744
745                 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
746                 homeIntent.addCategory(Intent.CATEGORY_HOME);
747                 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
748
749                 // Filter out apps without a launcher intent
750                 // Also filter out the current launcher, and Taskbar itself
751                 for(AppEntry packageInfo : usageStatsList) {
752                     if(hasLauncherIntent(packageInfo.getPackageName())
753                             && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
754                             && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName))
755                         usageStatsList2.add(packageInfo);
756                 }
757
758                 // Filter out apps that don't fall within our current search interval
759                 for(AppEntry stats : usageStatsList2) {
760                     if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
761                         usageStatsList3.add(stats);
762                 }
763
764                 // Sort apps by either most recently used, or most time used
765                 if(!runningAppsOnly && sortOrder.contains("most_used")) {
766                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
767                 } else {
768                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
769                 }
770
771                 // Filter out any duplicate entries
772                 List<String> applicationIds = new ArrayList<>();
773                 for(AppEntry stats : usageStatsList3) {
774                     if(!applicationIds.contains(stats.getPackageName())) {
775                         usageStatsList4.add(stats);
776                         applicationIds.add(stats.getPackageName());
777                     }
778                 }
779
780                 // Filter out the currently running foreground app, if requested by the user
781                 if(pref.getBoolean("hide_foreground", false)) {
782                     UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
783                     UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
784                     UsageEvents.Event eventCache = new UsageEvents.Event();
785                     String currentForegroundApp = null;
786
787                     while(events.hasNextEvent()) {
788                         events.getNextEvent(eventCache);
789
790                         if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
791                             if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
792                                     && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
793                                     && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
794                                     && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName())))
795                                 currentForegroundApp = eventCache.getPackageName();
796                         }
797                     }
798
799                     if(!applicationIdsToRemove.contains(currentForegroundApp))
800                         applicationIdsToRemove.add(currentForegroundApp);
801                 }
802
803                 for(AppEntry stats : usageStatsList4) {
804                     if(!applicationIdsToRemove.contains(stats.getPackageName())) {
805                         usageStatsList5.add(stats);
806                     }
807                 }
808
809                 // Truncate list to a maximum length
810                 if(usageStatsList5.size() > maxNumOfEntries)
811                     usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
812                 else
813                     usageStatsList6 = usageStatsList5;
814
815                 // Determine if we need to reverse the order
816                 boolean needToReverseOrder;
817                 switch(U.getTaskbarPosition(context)) {
818                     case "bottom_right":
819                     case "top_right":
820                         needToReverseOrder = sortOrder.contains("false");
821                         break;
822                     default:
823                         needToReverseOrder = sortOrder.contains("true");
824                         break;
825                 }
826
827                 if(needToReverseOrder) {
828                     Collections.reverse(usageStatsList6);
829                 }
830
831                 // Generate the AppEntries for the recent apps list
832                 int number = usageStatsList6.size() == maxNumOfEntries
833                         ? usageStatsList6.size() - realNumOfPinnedApps
834                         : usageStatsList6.size();
835
836                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
837                 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
838
839                 final List<UserHandle> userHandles = userManager.getUserProfiles();
840
841                 for(int i = 0; i < number; i++) {
842                     for(UserHandle handle : userHandles) {
843                         String packageName = usageStatsList6.get(i).getPackageName();
844                         long lastTimeUsed = usageStatsList6.get(i).getLastTimeUsed();
845                         List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
846                         if(!list.isEmpty()) {
847                             // Google App workaround
848                             if(!packageName.equals("com.google.android.googlequicksearchbox"))
849                                 launcherAppCache.add(list.get(0));
850                             else {
851                                 boolean added = false;
852                                 for(LauncherActivityInfo info : list) {
853                                     if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
854                                         launcherAppCache.add(info);
855                                         added = true;
856                                     }
857                                 }
858
859                                 if(!added) launcherAppCache.add(list.get(0));
860                             }
861
862                             AppEntry newEntry = new AppEntry(
863                                     packageName,
864                                     null,
865                                     null,
866                                     null,
867                                     false
868                             );
869
870                             newEntry.setUserId(userManager.getSerialNumberForUser(handle));
871                             newEntry.setLastTimeUsed(lastTimeUsed);
872                             entries.add(newEntry);
873
874                             break;
875                         }
876                     }
877                 }
878             }
879
880             while(entries.size() > maxNumOfEntries) {
881                 try {
882                     entries.remove(entries.size() - 1);
883                     launcherAppCache.remove(launcherAppCache.size() - 1);
884                 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
885             }
886
887             // Determine if we need to reverse the order again
888             if(U.getTaskbarPosition(context).contains("vertical")) {
889                 Collections.reverse(entries);
890                 Collections.reverse(launcherAppCache);
891             }
892
893             // Now that we've generated the list of apps,
894             // we need to determine if we need to redraw the Taskbar or not
895             boolean shouldRedrawTaskbar = firstRefresh;
896
897             List<String> finalApplicationIds = new ArrayList<>();
898             for(AppEntry entry : entries) {
899                 finalApplicationIds.add(entry.getPackageName());
900             }
901
902             if(finalApplicationIds.size() != currentTaskbarIds.size()
903                     || (runningAppsOnly && currentRunningAppIds.size() != prevRunningAppIds.size())
904                     || numOfPinnedApps != realNumOfPinnedApps)
905                 shouldRedrawTaskbar = true;
906             else {
907                 for(int i = 0; i < finalApplicationIds.size(); i++) {
908                     if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
909                         shouldRedrawTaskbar = true;
910                         break;
911                     }
912                 }
913
914                 if(!shouldRedrawTaskbar && runningAppsOnly) {
915                     for(int i = 0; i < finalApplicationIds.size(); i++) {
916                         if(!currentRunningAppIds.get(i).equals(prevRunningAppIds.get(i))) {
917                             shouldRedrawTaskbar = true;
918                             break;
919                         }
920                     }
921                 }
922             }
923
924             if(shouldRedrawTaskbar) {
925                 currentTaskbarIds = finalApplicationIds;
926                 numOfPinnedApps = realNumOfPinnedApps;
927
928                 if(runningAppsOnly) {
929                     prevRunningAppIds.clear();
930                     prevRunningAppIds.addAll(currentRunningAppIds);
931                 }
932
933                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
934
935                 int launcherAppCachePos = -1;
936                 for(int i = 0; i < entries.size(); i++) {
937                     if(entries.get(i).getComponentName() == null) {
938                         launcherAppCachePos++;
939                         LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
940                         String packageName = entries.get(i).getPackageName();
941                         long lastTimeUsed = entries.get(i).getLastTimeUsed();
942
943                         entries.remove(i);
944
945                         AppEntry newEntry = new AppEntry(
946                                 packageName,
947                                 appInfo.getComponentName().flattenToString(),
948                                 appInfo.getLabel().toString(),
949                                 IconCache.getInstance(context).getIcon(context, pm, appInfo),
950                                 false);
951
952                         newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
953                         newEntry.setLastTimeUsed(lastTimeUsed);
954                         entries.add(i, newEntry);
955                     }
956                 }
957
958                 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
959
960                 handler.post(() -> {
961                     if(numOfEntries > 0 || fullLength) {
962                         ViewGroup.LayoutParams params = scrollView.getLayoutParams();
963                         DisplayInfo display = U.getDisplayInfo(context, true);
964                         int recentsSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries;
965                         float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
966
967                         if(U.getTaskbarPosition(context).contains("vertical")) {
968                             int maxScreenSize = Math.max(0, display.height
969                                     - U.getStatusBarHeight(context)
970                                     - U.getBaseTaskbarSize(context));
971
972                             params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
973                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
974
975                             if(fullLength) {
976                                 try {
977                                     Space whitespaceTop = layout.findViewById(R.id.whitespace_top);
978                                     Space whitespaceBottom = layout.findViewById(R.id.whitespace_bottom);
979                                     int height = maxScreenSize - recentsSize;
980
981                                     if(pref.getBoolean("centered_icons", false)) {
982                                         ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
983                                         topParams.height = height / 2;
984                                         whitespaceTop.setLayoutParams(topParams);
985
986                                         ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
987                                         bottomParams.height = height / 2;
988                                         whitespaceBottom.setLayoutParams(bottomParams);
989                                     } else if(U.getTaskbarPosition(context).contains("bottom")) {
990                                         ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
991                                         topParams.height = height;
992                                         whitespaceTop.setLayoutParams(topParams);
993                                     } else {
994                                         ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
995                                         bottomParams.height = height;
996                                         whitespaceBottom.setLayoutParams(bottomParams);
997                                     }
998                                 } catch (NullPointerException e) { /* Gracefully fail */ }
999                             }
1000                         } else {
1001                             int maxScreenSize = Math.max(0, display.width - U.getBaseTaskbarSize(context));
1002
1003                             params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
1004                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
1005
1006                             if(fullLength) {
1007                                 try {
1008                                     Space whitespaceLeft = layout.findViewById(R.id.whitespace_left);
1009                                     Space whitespaceRight = layout.findViewById(R.id.whitespace_right);
1010                                     int width = maxScreenSize - recentsSize;
1011
1012                                     if(pref.getBoolean("centered_icons", false)) {
1013                                         ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
1014                                         leftParams.width = width / 2;
1015                                         whitespaceLeft.setLayoutParams(leftParams);
1016
1017                                         ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
1018                                         rightParams.width = width / 2;
1019                                         whitespaceRight.setLayoutParams(rightParams);
1020                                     } else if(U.getTaskbarPosition(context).contains("right")) {
1021                                         ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
1022                                         leftParams.width = width;
1023                                         whitespaceLeft.setLayoutParams(leftParams);
1024                                     } else {
1025                                         ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
1026                                         rightParams.width = width;
1027                                         whitespaceRight.setLayoutParams(rightParams);
1028                                     }
1029                                 } catch (NullPointerException e) { /* Gracefully fail */ }
1030                             }
1031                         }
1032
1033                         scrollView.setLayoutParams(params);
1034
1035                         taskbar.removeAllViews();
1036                         for(int i = 0; i < entries.size(); i++) {
1037                             taskbar.addView(getView(entries, i));
1038                         }
1039
1040                         isShowingRecents = true;
1041                         if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
1042                             if(firstRefresh)
1043                                 scrollView.setVisibility(View.INVISIBLE);
1044                             else
1045                                 scrollView.setVisibility(View.VISIBLE);
1046                         }
1047
1048                         if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
1049                             new Handler().post(() -> {
1050                                 switch(U.getTaskbarPosition(context)) {
1051                                     case "bottom_left":
1052                                     case "bottom_right":
1053                                     case "top_left":
1054                                     case "top_right":
1055                                         if(sortOrder.contains("false"))
1056                                             scrollView.scrollTo(0, 0);
1057                                         else if(sortOrder.contains("true"))
1058                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1059                                         break;
1060                                     case "bottom_vertical_left":
1061                                     case "bottom_vertical_right":
1062                                     case "top_vertical_left":
1063                                     case "top_vertical_right":
1064                                         if(sortOrder.contains("false"))
1065                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1066                                         else if(sortOrder.contains("true"))
1067                                             scrollView.scrollTo(0, 0);
1068                                         break;
1069                                 }
1070
1071                                 if(shouldRefreshRecents) {
1072                                     scrollView.setVisibility(View.VISIBLE);
1073                                 }
1074                             });
1075                     } else {
1076                         isShowingRecents = false;
1077                         scrollView.setVisibility(View.GONE);
1078                     }
1079                 });
1080             }
1081         } else if(firstRefresh || currentTaskbarIds.size() > 0) {
1082             currentTaskbarIds.clear();
1083             handler.post(() -> {
1084                 isShowingRecents = false;
1085                 scrollView.setVisibility(View.GONE);
1086             });
1087         }
1088     }
1089
1090     private void toggleTaskbar(boolean userInitiated) {
1091         if(userInitiated && Build.BRAND.equalsIgnoreCase("essential")) {
1092             SharedPreferences pref = U.getSharedPreferences(context);
1093             if(!pref.getBoolean("grip_rejection_toast_shown", false)) {
1094                 U.showToastLong(context, R.string.essential_phone_grip_rejection);
1095                 pref.edit().putBoolean("grip_rejection_toast_shown", true).apply();
1096             }
1097         }
1098
1099         if(startButton.getVisibility() == View.GONE)
1100             showTaskbar(true);
1101         else
1102             hideTaskbar(true);
1103     }
1104
1105     private void showTaskbar(boolean clearVariables) {
1106         if(clearVariables) {
1107             taskbarShownTemporarily = false;
1108             taskbarHiddenTemporarily = false;
1109         }
1110
1111         if(startButton.getVisibility() == View.GONE) {
1112             startButton.setVisibility(View.VISIBLE);
1113             space.setVisibility(View.VISIBLE);
1114
1115             if(dashboardEnabled)
1116                 dashboardButton.setVisibility(View.VISIBLE);
1117
1118             if(navbarButtonsEnabled)
1119                 navbarButtons.setVisibility(View.VISIBLE);
1120
1121             if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1122                 scrollView.setVisibility(View.INVISIBLE);
1123
1124             if(sysTrayEnabled)
1125                 sysTrayParentLayout.setVisibility(View.VISIBLE);
1126
1127             shouldRefreshRecents = true;
1128             startRefreshingRecents();
1129
1130             SharedPreferences pref = U.getSharedPreferences(context);
1131             pref.edit().putBoolean("collapsed", true).apply();
1132
1133             updateButton(false);
1134
1135             new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
1136         }
1137     }
1138
1139     private void hideTaskbar(boolean clearVariables) {
1140         if(clearVariables) {
1141             taskbarShownTemporarily = false;
1142             taskbarHiddenTemporarily = false;
1143         }
1144
1145         if(startButton.getVisibility() == View.VISIBLE) {
1146             startButton.setVisibility(View.GONE);
1147             space.setVisibility(View.GONE);
1148
1149             if(dashboardEnabled)
1150                 dashboardButton.setVisibility(View.GONE);
1151
1152             if(navbarButtonsEnabled)
1153                 navbarButtons.setVisibility(View.GONE);
1154
1155             if(isShowingRecents)
1156                 scrollView.setVisibility(View.GONE);
1157
1158             if(sysTrayEnabled)
1159                 sysTrayParentLayout.setVisibility(View.GONE);
1160
1161             shouldRefreshRecents = false;
1162             if(thread != null) thread.interrupt();
1163
1164             SharedPreferences pref = U.getSharedPreferences(context);
1165             pref.edit().putBoolean("collapsed", false).apply();
1166
1167             updateButton(true);
1168
1169             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
1170             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD"));
1171
1172             new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU_SPACE")));
1173         }
1174     }
1175
1176     private void tempShowTaskbar() {
1177         if(!taskbarHiddenTemporarily) {
1178             SharedPreferences pref = U.getSharedPreferences(context);
1179             if(!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true;
1180         }
1181
1182         showTaskbar(false);
1183
1184         if(taskbarHiddenTemporarily)
1185             taskbarHiddenTemporarily = false;
1186     }
1187
1188     private void tempHideTaskbar(boolean monitorPositionChanges) {
1189         if(!taskbarShownTemporarily) {
1190             SharedPreferences pref = U.getSharedPreferences(context);
1191             if(pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true;
1192         }
1193
1194         hideTaskbar(false);
1195
1196         if(taskbarShownTemporarily)
1197             taskbarShownTemporarily = false;
1198
1199         if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1200             if(thread2 != null) thread2.interrupt();
1201
1202             handler2 = new Handler();
1203             thread2 = new Thread(() -> {
1204                 stopThread2 = false;
1205
1206                 while(!stopThread2) {
1207                     SystemClock.sleep(refreshInterval);
1208
1209                     handler2.post(() -> stopThread2 = checkPositionChange());
1210                 }
1211
1212                 startThread2 = false;
1213             });
1214
1215             thread2.start();
1216         }
1217     }
1218
1219     private boolean checkPositionChange() {
1220         if(!isScreenOff() && layout != null) {
1221             int[] location = new int[2];
1222             layout.getLocationOnScreen(location);
1223
1224             if(location[1] == 0) {
1225                 return true;
1226             } else {
1227                 if(location[1] > currentTaskbarPosition) {
1228                     currentTaskbarPosition = location[1];
1229                     if(taskbarHiddenTemporarily) {
1230                         tempShowTaskbar();
1231                         return true;
1232                     }
1233                 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1234                     tempShowTaskbar();
1235                     return true;
1236                 } else if(location[1] < currentTaskbarPosition
1237                         && currentTaskbarPosition - location[1] == getNavBarSize()) {
1238                     currentTaskbarPosition = location[1];
1239                 }
1240             }
1241         }
1242
1243         return false;
1244     }
1245
1246     private int getNavBarSize() {
1247         Point size = new Point();
1248         Point realSize = new Point();
1249
1250         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1251         Display display = wm.getDefaultDisplay();
1252         display.getSize(size);
1253         display.getRealSize(realSize);
1254
1255         return realSize.y - size.y;
1256     }
1257
1258     @Override
1259     public void onDestroyHost(UIHost host) {
1260         shouldRefreshRecents = false;
1261
1262         if(layout != null)
1263             try {
1264                 host.removeView(layout);
1265             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1266
1267         SharedPreferences pref = U.getSharedPreferences(context);
1268         if(pref.getBoolean("skip_auto_hide_navbar", false)) {
1269             pref.edit().remove("skip_auto_hide_navbar").apply();
1270         } else if(pref.getBoolean("auto_hide_navbar", false))
1271             U.showHideNavigationBar(context, true);
1272
1273         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
1274
1275         lbm.unregisterReceiver(showReceiver);
1276         lbm.unregisterReceiver(hideReceiver);
1277         lbm.unregisterReceiver(tempShowReceiver);
1278         lbm.unregisterReceiver(tempHideReceiver);
1279         lbm.unregisterReceiver(startMenuAppearReceiver);
1280         lbm.unregisterReceiver(startMenuDisappearReceiver);
1281
1282         if(sysTrayEnabled) {
1283             TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1284             manager.listen(listener, PhoneStateListener.LISTEN_NONE);
1285         }
1286
1287         isFirstStart = true;
1288     }
1289
1290     private void openContextMenu() {
1291         SharedPreferences pref = U.getSharedPreferences(context);
1292
1293         Bundle args = new Bundle();
1294         args.putBoolean("dont_show_quit",
1295                 LauncherHelper.getInstance().isOnHomeScreen()
1296                         && !pref.getBoolean("taskbar_active", false));
1297         args.putBoolean("is_start_button", true);
1298
1299         U.startContextMenuActivity(context, args);
1300     }
1301
1302     private void updateButton(boolean isCollapsed) {
1303         SharedPreferences pref = U.getSharedPreferences(context);
1304         boolean hide = pref.getBoolean("invisible_button", false);
1305
1306         if(button != null) button.setText(context.getString(isCollapsed ? R.string.right_arrow : R.string.left_arrow));
1307         if(layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1);
1308     }
1309
1310     @TargetApi(Build.VERSION_CODES.M)
1311     @Override
1312     public void onRecreateHost(UIHost host) {
1313         if(layout != null) {
1314             try {
1315                 host.removeView(layout);
1316             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
1317
1318             currentTaskbarPosition = 0;
1319
1320             if(U.canDrawOverlays(context, host instanceof HomeActivityDelegate))
1321                 drawTaskbar(host);
1322             else {
1323                 SharedPreferences pref = U.getSharedPreferences(context);
1324                 pref.edit().putBoolean("taskbar_active", false).apply();
1325
1326                 host.terminate();
1327             }
1328         }
1329     }
1330
1331     private View getView(List<AppEntry> list, int position) {
1332         View convertView = View.inflate(context, R.layout.icon, null);
1333
1334         final AppEntry entry = list.get(position);
1335         final SharedPreferences pref = U.getSharedPreferences(context);
1336
1337         ImageView imageView = convertView.findViewById(R.id.icon);
1338         ImageView imageView2 = convertView.findViewById(R.id.shortcut_icon);
1339         imageView.setImageDrawable(entry.getIcon(context));
1340         imageView2.setBackgroundColor(pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white)));
1341
1342         String taskbarPosition = U.getTaskbarPosition(context);
1343         if(pref.getBoolean("shortcut_icon", true)) {
1344             boolean shouldShowShortcutIcon;
1345             if(taskbarPosition.contains("vertical"))
1346                 shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps;
1347             else
1348                 shouldShowShortcutIcon = position < numOfPinnedApps;
1349
1350             if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1351         }
1352
1353         if(taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) {
1354             imageView.setRotationY(180);
1355             imageView2.setRotationY(180);
1356         }
1357
1358         FrameLayout layout = convertView.findViewById(R.id.entry);
1359         layout.setOnClickListener(view -> U.launchApp(
1360                 context,
1361                 entry,
1362                 null,
1363                 true,
1364                 false,
1365                 view
1366         ));
1367
1368         layout.setOnLongClickListener(view -> {
1369             int[] location = new int[2];
1370             view.getLocationOnScreen(location);
1371             openContextMenu(entry, location);
1372             return true;
1373         });
1374
1375         layout.setOnGenericMotionListener((view, motionEvent) -> {
1376             int action = motionEvent.getAction();
1377
1378             if(action == MotionEvent.ACTION_BUTTON_PRESS
1379                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
1380                 int[] location = new int[2];
1381                 view.getLocationOnScreen(location);
1382                 openContextMenu(entry, location);
1383             }
1384
1385             if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true))
1386                 view.setBackgroundColor(0);
1387
1388             return false;
1389         });
1390
1391         if(pref.getBoolean("visual_feedback", true)) {
1392             layout.setOnHoverListener((v, event) -> {
1393                 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
1394                     int accentColor = U.getAccentColor(context);
1395                     accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2);
1396                     v.setBackgroundColor(accentColor);
1397                 }
1398
1399                 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1400                     v.setBackgroundColor(0);
1401
1402                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1403                     v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
1404
1405                 return false;
1406             });
1407
1408             layout.setOnTouchListener((v, event) -> {
1409                 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1410                 return false;
1411             });
1412         }
1413
1414         if(runningAppsOnly) {
1415             ImageView runningAppIndicator = convertView.findViewById(R.id.running_app_indicator);
1416             if(entry.getLastTimeUsed() > 0) {
1417                 runningAppIndicator.setVisibility(View.VISIBLE);
1418                 runningAppIndicator.setColorFilter(U.getAccentColor(context));
1419             } else
1420                 runningAppIndicator.setVisibility(View.GONE);
1421         }
1422
1423         return convertView;
1424     }
1425
1426     private void openContextMenu(AppEntry entry, int[] location) {
1427         Bundle args = new Bundle();
1428         args.putSerializable("app_entry", entry);
1429         args.putInt("x", location[0]);
1430         args.putInt("y", location[1]);
1431
1432         U.startContextMenuActivity(context, args);
1433     }
1434
1435     private List<AppEntry> getAppEntries() {
1436         SharedPreferences pref = U.getSharedPreferences(context);
1437         if(runningAppsOnly)
1438             return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10")));
1439         else
1440             return getAppEntriesUsingUsageStats();
1441     }
1442
1443     @SuppressWarnings("deprecation")
1444     @TargetApi(Build.VERSION_CODES.M)
1445     private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) {
1446         ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1447         List<ActivityManager.RecentTaskInfo> usageStatsList = mActivityManager.getRecentTasks(maxNum, 0);
1448         List<AppEntry> entries = new ArrayList<>();
1449
1450         for(int i = 0; i < usageStatsList.size(); i++) {
1451             ActivityManager.RecentTaskInfo recentTaskInfo = usageStatsList.get(i);
1452             if(recentTaskInfo.id != -1) {
1453                 String packageName = recentTaskInfo.baseActivity.getPackageName();
1454                 AppEntry newEntry = new AppEntry(
1455                         packageName,
1456                         null,
1457                         null,
1458                         null,
1459                         false
1460                 );
1461
1462                 try {
1463                     Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1464                     newEntry.setLastTimeUsed(field.getLong(recentTaskInfo));
1465                     currentRunningAppIds.add(packageName);
1466                 } catch (Exception e) {
1467                     newEntry.setLastTimeUsed(i);
1468                 }
1469
1470                 entries.add(newEntry);
1471             }
1472         }
1473
1474         return entries;
1475     }
1476
1477     @SuppressWarnings("deprecation")
1478     @TargetApi(Build.VERSION_CODES.M)
1479     private List<AppEntry> setTimeLastUsedFor(List<AppEntry> pinnedApps) {
1480         if(!runningAppsOnly || pinnedApps.size() == 0)
1481             return pinnedApps;
1482
1483         ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1484         List<ActivityManager.RecentTaskInfo> recentTasks = mActivityManager.getRecentTasks(Integer.MAX_VALUE, 0);
1485
1486         for(AppEntry entry : pinnedApps) {
1487             for(ActivityManager.RecentTaskInfo task : recentTasks) {
1488                 if(task.id != -1 && task.baseActivity.getPackageName().equals(entry.getPackageName())) {
1489                     try {
1490                         Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1491                         entry.setLastTimeUsed(field.getLong(task));
1492                         currentRunningAppIds.add(entry.getPackageName());
1493                         break;
1494                     } catch (Exception e) { /* Gracefully fail */ }
1495                 }
1496             }
1497         }
1498
1499         return pinnedApps;
1500     }
1501
1502     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
1503     private List<AppEntry> getAppEntriesUsingUsageStats() {
1504         UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
1505         List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, searchInterval, System.currentTimeMillis());
1506         List<AppEntry> entries = new ArrayList<>();
1507
1508         for(UsageStats usageStats : usageStatsList) {
1509             AppEntry newEntry = new AppEntry(
1510                     usageStats.getPackageName(),
1511                     null,
1512                     null,
1513                     null,
1514                     false
1515             );
1516
1517             newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1518             newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1519             entries.add(newEntry);
1520         }
1521
1522         return entries;
1523     }
1524
1525     private boolean hasLauncherIntent(String packageName) {
1526         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1527         intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1528         intentToResolve.setPackage(packageName);
1529
1530         List<ResolveInfo> ris = context.getPackageManager().queryIntentActivities(intentToResolve, 0);
1531         return ris != null && ris.size() > 0;
1532     }
1533
1534     private boolean isScreenOff() {
1535         if(U.isChromeOs(context))
1536             return false;
1537
1538         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1539         return !pm.isInteractive();
1540     }
1541
1542     private void updateSystemTray() {
1543         if(!sysTrayEnabled || isScreenOff()) return;
1544
1545         handler.post(() -> {
1546             ImageView battery = sysTrayLayout.findViewById(R.id.battery);
1547             battery.setImageDrawable(getBatteryDrawable());
1548
1549             ImageView wifi = sysTrayLayout.findViewById(R.id.wifi);
1550             wifi.setImageDrawable(getWifiDrawable());
1551
1552             ImageView bluetooth = sysTrayLayout.findViewById(R.id.bluetooth);
1553             bluetooth.setImageDrawable(getBluetoothDrawable());
1554
1555             ImageView cellular = sysTrayLayout.findViewById(R.id.cellular);
1556             cellular.setImageDrawable(getCellularDrawable());
1557
1558             time.setText(context.getString(R.string.systray_clock,
1559                     DateFormat.getTimeFormat(context).format(new Date()),
1560                     DateFormat.getDateFormat(context).format(new Date())));
1561             time.setTextColor(U.getAccentColor(context));
1562         });
1563     }
1564
1565     @TargetApi(Build.VERSION_CODES.M)
1566     private Drawable getBatteryDrawable() {
1567         BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
1568         int batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
1569         boolean isCharging = bm.isCharging();
1570
1571         if(batLevel == Integer.MIN_VALUE)
1572             return null;
1573
1574         String batDrawable;
1575         if(batLevel <= 10 && !isCharging)
1576             batDrawable = "alert";
1577         else if(batLevel <= 20)
1578             batDrawable = "20";
1579         else if(batLevel <= 30)
1580             batDrawable = "30";
1581         else if(batLevel <= 50)
1582             batDrawable = "50";
1583         else if(batLevel <= 60)
1584             batDrawable = "60";
1585         else if(batLevel <= 80)
1586             batDrawable = "80";
1587         else if(batLevel <= 90)
1588             batDrawable = "90";
1589         else
1590             batDrawable = "full";
1591
1592         String charging;
1593         if(isCharging)
1594             charging = "charging_";
1595         else
1596             charging = "";
1597
1598         String batRes = "ic_battery_" + charging + batDrawable + "_black_24dp";
1599         int id = context.getResources().getIdentifier(batRes, "drawable", BuildConfig.APPLICATION_ID);
1600
1601         return applyTintTo(ContextCompat.getDrawable(context, id));
1602     }
1603
1604     @TargetApi(Build.VERSION_CODES.M)
1605     private Drawable getWifiDrawable() {
1606         ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1607
1608         NetworkInfo ethernet = manager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
1609         if(ethernet != null && ethernet.isConnected())
1610             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_settings_ethernet_black_24dp));
1611
1612         NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
1613         if(wifi == null || !wifi.isConnected())
1614             return null;
1615
1616         WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
1617         int numberOfLevels = 5;
1618
1619         WifiInfo wifiInfo = wifiManager.getConnectionInfo();
1620         int level = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), numberOfLevels);
1621
1622         String wifiRes = "ic_signal_wifi_" + level + "_bar_black_24dp";
1623         int id = context.getResources().getIdentifier(wifiRes, "drawable", BuildConfig.APPLICATION_ID);
1624
1625         return applyTintTo(ContextCompat.getDrawable(context, id));
1626     }
1627
1628     private Drawable getBluetoothDrawable() {
1629         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1630         if(adapter != null && adapter.isEnabled())
1631             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_bluetooth_black_24dp));
1632
1633         return null;
1634     }
1635
1636     @TargetApi(Build.VERSION_CODES.M)
1637     private Drawable getCellularDrawable() {
1638         if(Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0)
1639             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_airplanemode_active_black_24dp));
1640
1641         if(cellStrength == -1)
1642             return null;
1643
1644         String cellRes = "ic_signal_cellular_" + cellStrength + "_bar_black_24dp";
1645         int id = context.getResources().getIdentifier(cellRes, "drawable", BuildConfig.APPLICATION_ID);
1646
1647         return applyTintTo(ContextCompat.getDrawable(context, id));
1648     }
1649     
1650     private Drawable applyTintTo(Drawable drawable) {
1651         if(drawable == null) return null;
1652
1653         drawable.setTint(U.getAccentColor(context));
1654         return drawable;
1655     }
1656 }