OSDN Git Service

Don't hide dashboard or start menu if temp hiding Taskbar
[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 = U.isSystemTrayEnabled(context);
542
543         if(sysTrayEnabled) {
544             sysTrayLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.system_tray, null);
545
546             FrameLayout.LayoutParams sysTrayParams = new FrameLayout.LayoutParams(
547                     FrameLayout.LayoutParams.WRAP_CONTENT,
548                     context.getResources().getDimensionPixelSize(R.dimen.icon_size)
549             );
550
551             if(layoutId == R.layout.taskbar_right) {
552                 time = sysTrayLayout.findViewById(R.id.time_left);
553                 sysTrayParams.gravity = Gravity.START;
554             } else {
555                 time = sysTrayLayout.findViewById(R.id.time_right);
556                 sysTrayParams.gravity = Gravity.END;
557             }
558
559             time.setVisibility(View.VISIBLE);
560             sysTrayLayout.setLayoutParams(sysTrayParams);
561
562             sysTrayLayout.setOnClickListener(v -> {
563                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
564                 if(U.shouldCollapse(context, false))
565                     hideTaskbar(true);
566             });
567
568             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
569                 sysTrayLayout.setOnLongClickListener(v -> {
570                     U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
571                     if(U.shouldCollapse(context, false))
572                         hideTaskbar(true);
573
574                     return true;
575                 });
576
577                 sysTrayLayout.setOnGenericMotionListener((view, motionEvent) -> {
578                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
579                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
580                         U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
581                         if(U.shouldCollapse(context, false))
582                             hideTaskbar(true);
583                     }
584                     return true;
585                 });
586             }
587
588             sysTrayParentLayout = layout.findViewById(R.id.add_systray_here);
589             sysTrayParentLayout.setVisibility(View.VISIBLE);
590             sysTrayParentLayout.addView(sysTrayLayout);
591
592             TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
593             manager.listen(listener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
594         }
595
596         layout.setBackgroundColor(backgroundTint);
597         layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
598         button.setTextColor(accentColor);
599
600         if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
601             showTaskbar(false);
602         else if(!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false))
603             toggleTaskbar(false);
604
605         if(pref.getBoolean("auto_hide_navbar", false))
606             U.showHideNavigationBar(context, false);
607
608         if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
609             lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
610
611             new Handler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
612         }
613
614         lbm.unregisterReceiver(showReceiver);
615         lbm.unregisterReceiver(hideReceiver);
616         lbm.unregisterReceiver(tempShowReceiver);
617         lbm.unregisterReceiver(tempHideReceiver);
618         lbm.unregisterReceiver(startMenuAppearReceiver);
619         lbm.unregisterReceiver(startMenuDisappearReceiver);
620
621         lbm.registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR"));
622         lbm.registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR"));
623         lbm.registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
624         lbm.registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
625         lbm.registerReceiver(startMenuAppearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_APPEARING"));
626         lbm.registerReceiver(startMenuDisappearReceiver, new IntentFilter("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
627
628         startRefreshingRecents();
629
630         host.addView(layout, params);
631
632         isFirstStart = false;
633     }
634
635     private void startRefreshingRecents() {
636         if(thread != null) thread.interrupt();
637         stopThread2 = true;
638
639         SharedPreferences pref = U.getSharedPreferences(context);
640         showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false);
641
642         currentTaskbarIds.clear();
643
644         handler = new Handler();
645         thread = new Thread(() -> {
646             updateSystemTray();
647             updateRecentApps(true);
648
649             if(!isRefreshingRecents) {
650                 isRefreshingRecents = true;
651
652                 while(shouldRefreshRecents) {
653                     SystemClock.sleep(refreshInterval);
654                     updateSystemTray();
655                     updateRecentApps(false);
656
657                     if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen())
658                         handler.post(() -> {
659                             if(layout != null) {
660                                 int[] location = new int[2];
661                                 layout.getLocationOnScreen(location);
662
663                                 if(location[1] != 0) {
664                                     if(location[1] > currentTaskbarPosition) {
665                                         currentTaskbarPosition = location[1];
666                                     } else if(location[1] < currentTaskbarPosition) {
667                                         if(currentTaskbarPosition - location[1] == getNavBarSize())
668                                             currentTaskbarPosition = location[1];
669                                         else if(!startThread2) {
670                                             startThread2 = true;
671                                             tempHideTaskbar(true);
672                                         }
673                                     }
674                                 }
675                             }
676                         });
677                 }
678
679                 isRefreshingRecents = false;
680             }
681         });
682
683         thread.start();
684     }
685
686     @SuppressWarnings("Convert2streamapi")
687     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
688     private void updateRecentApps(final boolean firstRefresh) {
689         if(isScreenOff()) return;
690
691         SharedPreferences pref = U.getSharedPreferences(context);
692         final PackageManager pm = context.getPackageManager();
693         final List<AppEntry> entries = new ArrayList<>();
694         List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
695         int maxNumOfEntries = U.getMaxNumOfEntries(context);
696         int realNumOfPinnedApps = 0;
697         boolean fullLength = pref.getBoolean("full_length", false);
698
699         if(runningAppsOnly)
700             currentRunningAppIds.clear();
701
702         PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
703         List<AppEntry> pinnedApps = setTimeLastUsedFor(pba.getPinnedApps());
704         List<AppEntry> blockedApps = pba.getBlockedApps();
705         List<String> applicationIdsToRemove = new ArrayList<>();
706
707         // Filter out anything on the pinned/blocked apps lists
708         if(pinnedApps.size() > 0) {
709             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
710             LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
711
712             for(AppEntry entry : pinnedApps) {
713                 boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
714                         userManager.getUserForSerialNumber(entry.getUserId(context)));
715
716                 if(packageEnabled)
717                     entries.add(entry);
718                 else
719                     realNumOfPinnedApps--;
720
721                 applicationIdsToRemove.add(entry.getPackageName());
722             }
723
724             realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
725         }
726
727         if(blockedApps.size() > 0) {
728             for(AppEntry entry : blockedApps) {
729                 applicationIdsToRemove.add(entry.getPackageName());
730             }
731         }
732
733         // Get list of all recently used apps
734         List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
735         if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
736             if(realNumOfPinnedApps < maxNumOfEntries) {
737                 List<AppEntry> usageStatsList2 = new ArrayList<>();
738                 List<AppEntry> usageStatsList3 = new ArrayList<>();
739                 List<AppEntry> usageStatsList4 = new ArrayList<>();
740                 List<AppEntry> usageStatsList5 = new ArrayList<>();
741                 List<AppEntry> usageStatsList6;
742
743                 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
744                 homeIntent.addCategory(Intent.CATEGORY_HOME);
745                 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
746
747                 // Filter out apps without a launcher intent
748                 // Also filter out the current launcher, and Taskbar itself
749                 for(AppEntry packageInfo : usageStatsList) {
750                     if(hasLauncherIntent(packageInfo.getPackageName())
751                             && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
752                             && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName))
753                         usageStatsList2.add(packageInfo);
754                 }
755
756                 // Filter out apps that don't fall within our current search interval
757                 for(AppEntry stats : usageStatsList2) {
758                     if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
759                         usageStatsList3.add(stats);
760                 }
761
762                 // Sort apps by either most recently used, or most time used
763                 if(!runningAppsOnly && sortOrder.contains("most_used")) {
764                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
765                 } else {
766                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
767                 }
768
769                 // Filter out any duplicate entries
770                 List<String> applicationIds = new ArrayList<>();
771                 for(AppEntry stats : usageStatsList3) {
772                     if(!applicationIds.contains(stats.getPackageName())) {
773                         usageStatsList4.add(stats);
774                         applicationIds.add(stats.getPackageName());
775                     }
776                 }
777
778                 // Filter out the currently running foreground app, if requested by the user
779                 if(pref.getBoolean("hide_foreground", false)) {
780                     UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
781                     UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
782                     UsageEvents.Event eventCache = new UsageEvents.Event();
783                     String currentForegroundApp = null;
784
785                     while(events.hasNextEvent()) {
786                         events.getNextEvent(eventCache);
787
788                         if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
789                             if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
790                                     && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
791                                     && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
792                                     && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName())))
793                                 currentForegroundApp = eventCache.getPackageName();
794                         }
795                     }
796
797                     if(!applicationIdsToRemove.contains(currentForegroundApp))
798                         applicationIdsToRemove.add(currentForegroundApp);
799                 }
800
801                 for(AppEntry stats : usageStatsList4) {
802                     if(!applicationIdsToRemove.contains(stats.getPackageName())) {
803                         usageStatsList5.add(stats);
804                     }
805                 }
806
807                 // Truncate list to a maximum length
808                 if(usageStatsList5.size() > maxNumOfEntries)
809                     usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
810                 else
811                     usageStatsList6 = usageStatsList5;
812
813                 // Determine if we need to reverse the order
814                 boolean needToReverseOrder;
815                 switch(U.getTaskbarPosition(context)) {
816                     case "bottom_right":
817                     case "top_right":
818                         needToReverseOrder = sortOrder.contains("false");
819                         break;
820                     default:
821                         needToReverseOrder = sortOrder.contains("true");
822                         break;
823                 }
824
825                 if(needToReverseOrder) {
826                     Collections.reverse(usageStatsList6);
827                 }
828
829                 // Generate the AppEntries for the recent apps list
830                 int number = usageStatsList6.size() == maxNumOfEntries
831                         ? usageStatsList6.size() - realNumOfPinnedApps
832                         : usageStatsList6.size();
833
834                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
835                 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
836
837                 final List<UserHandle> userHandles = userManager.getUserProfiles();
838
839                 for(int i = 0; i < number; i++) {
840                     for(UserHandle handle : userHandles) {
841                         String packageName = usageStatsList6.get(i).getPackageName();
842                         long lastTimeUsed = usageStatsList6.get(i).getLastTimeUsed();
843                         List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
844                         if(!list.isEmpty()) {
845                             // Google App workaround
846                             if(!packageName.equals("com.google.android.googlequicksearchbox"))
847                                 launcherAppCache.add(list.get(0));
848                             else {
849                                 boolean added = false;
850                                 for(LauncherActivityInfo info : list) {
851                                     if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
852                                         launcherAppCache.add(info);
853                                         added = true;
854                                     }
855                                 }
856
857                                 if(!added) launcherAppCache.add(list.get(0));
858                             }
859
860                             AppEntry newEntry = new AppEntry(
861                                     packageName,
862                                     null,
863                                     null,
864                                     null,
865                                     false
866                             );
867
868                             newEntry.setUserId(userManager.getSerialNumberForUser(handle));
869                             newEntry.setLastTimeUsed(lastTimeUsed);
870                             entries.add(newEntry);
871
872                             break;
873                         }
874                     }
875                 }
876             }
877
878             while(entries.size() > maxNumOfEntries) {
879                 try {
880                     entries.remove(entries.size() - 1);
881                     launcherAppCache.remove(launcherAppCache.size() - 1);
882                 } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ }
883             }
884
885             // Determine if we need to reverse the order again
886             if(U.getTaskbarPosition(context).contains("vertical")) {
887                 Collections.reverse(entries);
888                 Collections.reverse(launcherAppCache);
889             }
890
891             // Now that we've generated the list of apps,
892             // we need to determine if we need to redraw the Taskbar or not
893             boolean shouldRedrawTaskbar = firstRefresh;
894
895             List<String> finalApplicationIds = new ArrayList<>();
896             for(AppEntry entry : entries) {
897                 finalApplicationIds.add(entry.getPackageName());
898             }
899
900             if(finalApplicationIds.size() != currentTaskbarIds.size()
901                     || (runningAppsOnly && currentRunningAppIds.size() != prevRunningAppIds.size())
902                     || numOfPinnedApps != realNumOfPinnedApps)
903                 shouldRedrawTaskbar = true;
904             else {
905                 for(int i = 0; i < finalApplicationIds.size(); i++) {
906                     if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
907                         shouldRedrawTaskbar = true;
908                         break;
909                     }
910                 }
911
912                 if(!shouldRedrawTaskbar && runningAppsOnly) {
913                     for(int i = 0; i < finalApplicationIds.size(); i++) {
914                         if(!currentRunningAppIds.get(i).equals(prevRunningAppIds.get(i))) {
915                             shouldRedrawTaskbar = true;
916                             break;
917                         }
918                     }
919                 }
920             }
921
922             if(shouldRedrawTaskbar) {
923                 currentTaskbarIds = finalApplicationIds;
924                 numOfPinnedApps = realNumOfPinnedApps;
925
926                 if(runningAppsOnly) {
927                     prevRunningAppIds.clear();
928                     prevRunningAppIds.addAll(currentRunningAppIds);
929                 }
930
931                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
932
933                 int launcherAppCachePos = -1;
934                 for(int i = 0; i < entries.size(); i++) {
935                     if(entries.get(i).getComponentName() == null) {
936                         launcherAppCachePos++;
937                         LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
938                         String packageName = entries.get(i).getPackageName();
939                         long lastTimeUsed = entries.get(i).getLastTimeUsed();
940
941                         entries.remove(i);
942
943                         AppEntry newEntry = new AppEntry(
944                                 packageName,
945                                 appInfo.getComponentName().flattenToString(),
946                                 appInfo.getLabel().toString(),
947                                 IconCache.getInstance(context).getIcon(context, pm, appInfo),
948                                 false);
949
950                         newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
951                         newEntry.setLastTimeUsed(lastTimeUsed);
952                         entries.add(i, newEntry);
953                     }
954                 }
955
956                 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
957
958                 handler.post(() -> {
959                     if(numOfEntries > 0 || fullLength) {
960                         ViewGroup.LayoutParams params = scrollView.getLayoutParams();
961                         DisplayInfo display = U.getDisplayInfo(context, true);
962                         int recentsSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries;
963                         float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
964
965                         if(U.getTaskbarPosition(context).contains("vertical")) {
966                             int maxScreenSize = Math.max(0, display.height
967                                     - U.getStatusBarHeight(context)
968                                     - U.getBaseTaskbarSize(context));
969
970                             params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
971                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
972
973                             if(fullLength) {
974                                 try {
975                                     Space whitespaceTop = layout.findViewById(R.id.whitespace_top);
976                                     Space whitespaceBottom = layout.findViewById(R.id.whitespace_bottom);
977                                     int height = maxScreenSize - recentsSize;
978
979                                     if(pref.getBoolean("centered_icons", false)) {
980                                         ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
981                                         topParams.height = height / 2;
982                                         whitespaceTop.setLayoutParams(topParams);
983
984                                         ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
985                                         bottomParams.height = height / 2;
986                                         whitespaceBottom.setLayoutParams(bottomParams);
987                                     } else if(U.getTaskbarPosition(context).contains("bottom")) {
988                                         ViewGroup.LayoutParams topParams = whitespaceTop.getLayoutParams();
989                                         topParams.height = height;
990                                         whitespaceTop.setLayoutParams(topParams);
991                                     } else {
992                                         ViewGroup.LayoutParams bottomParams = whitespaceBottom.getLayoutParams();
993                                         bottomParams.height = height;
994                                         whitespaceBottom.setLayoutParams(bottomParams);
995                                     }
996                                 } catch (NullPointerException e) { /* Gracefully fail */ }
997                             }
998                         } else {
999                             int maxScreenSize = Math.max(0, display.width - U.getBaseTaskbarSize(context));
1000
1001                             params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
1002                                     + context.getResources().getDimensionPixelSize(R.dimen.divider_size);
1003
1004                             if(fullLength) {
1005                                 try {
1006                                     Space whitespaceLeft = layout.findViewById(R.id.whitespace_left);
1007                                     Space whitespaceRight = layout.findViewById(R.id.whitespace_right);
1008                                     int width = maxScreenSize - recentsSize;
1009
1010                                     if(pref.getBoolean("centered_icons", false)) {
1011                                         ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
1012                                         leftParams.width = width / 2;
1013                                         whitespaceLeft.setLayoutParams(leftParams);
1014
1015                                         ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
1016                                         rightParams.width = width / 2;
1017                                         whitespaceRight.setLayoutParams(rightParams);
1018                                     } else if(U.getTaskbarPosition(context).contains("right")) {
1019                                         ViewGroup.LayoutParams leftParams = whitespaceLeft.getLayoutParams();
1020                                         leftParams.width = width;
1021                                         whitespaceLeft.setLayoutParams(leftParams);
1022                                     } else {
1023                                         ViewGroup.LayoutParams rightParams = whitespaceRight.getLayoutParams();
1024                                         rightParams.width = width;
1025                                         whitespaceRight.setLayoutParams(rightParams);
1026                                     }
1027                                 } catch (NullPointerException e) { /* Gracefully fail */ }
1028                             }
1029                         }
1030
1031                         scrollView.setLayoutParams(params);
1032
1033                         taskbar.removeAllViews();
1034                         for(int i = 0; i < entries.size(); i++) {
1035                             taskbar.addView(getView(entries, i));
1036                         }
1037
1038                         isShowingRecents = true;
1039                         if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
1040                             if(firstRefresh)
1041                                 scrollView.setVisibility(View.INVISIBLE);
1042                             else
1043                                 scrollView.setVisibility(View.VISIBLE);
1044                         }
1045
1046                         if(firstRefresh && scrollView.getVisibility() != View.VISIBLE)
1047                             new Handler().post(() -> {
1048                                 switch(U.getTaskbarPosition(context)) {
1049                                     case "bottom_left":
1050                                     case "bottom_right":
1051                                     case "top_left":
1052                                     case "top_right":
1053                                         if(sortOrder.contains("false"))
1054                                             scrollView.scrollTo(0, 0);
1055                                         else if(sortOrder.contains("true"))
1056                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1057                                         break;
1058                                     case "bottom_vertical_left":
1059                                     case "bottom_vertical_right":
1060                                     case "top_vertical_left":
1061                                     case "top_vertical_right":
1062                                         if(sortOrder.contains("false"))
1063                                             scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1064                                         else if(sortOrder.contains("true"))
1065                                             scrollView.scrollTo(0, 0);
1066                                         break;
1067                                 }
1068
1069                                 if(shouldRefreshRecents) {
1070                                     scrollView.setVisibility(View.VISIBLE);
1071                                 }
1072                             });
1073                     } else {
1074                         isShowingRecents = false;
1075                         scrollView.setVisibility(View.GONE);
1076                     }
1077                 });
1078             }
1079         } else if(firstRefresh || currentTaskbarIds.size() > 0) {
1080             currentTaskbarIds.clear();
1081             handler.post(() -> {
1082                 isShowingRecents = false;
1083                 scrollView.setVisibility(View.GONE);
1084             });
1085         }
1086     }
1087
1088     private void toggleTaskbar(boolean userInitiated) {
1089         if(userInitiated && Build.BRAND.equalsIgnoreCase("essential")) {
1090             SharedPreferences pref = U.getSharedPreferences(context);
1091             if(!pref.getBoolean("grip_rejection_toast_shown", false)) {
1092                 U.showToastLong(context, R.string.essential_phone_grip_rejection);
1093                 pref.edit().putBoolean("grip_rejection_toast_shown", true).apply();
1094             }
1095         }
1096
1097         if(startButton.getVisibility() == View.GONE)
1098             showTaskbar(true);
1099         else
1100             hideTaskbar(true);
1101     }
1102
1103     private void showTaskbar(boolean clearVariables) {
1104         if(clearVariables) {
1105             taskbarShownTemporarily = false;
1106             taskbarHiddenTemporarily = false;
1107         }
1108
1109         if(startButton.getVisibility() == View.GONE) {
1110             startButton.setVisibility(View.VISIBLE);
1111             space.setVisibility(View.VISIBLE);
1112
1113             if(dashboardEnabled)
1114                 dashboardButton.setVisibility(View.VISIBLE);
1115
1116             if(navbarButtonsEnabled)
1117                 navbarButtons.setVisibility(View.VISIBLE);
1118
1119             if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1120                 scrollView.setVisibility(View.INVISIBLE);
1121
1122             if(sysTrayEnabled)
1123                 sysTrayParentLayout.setVisibility(View.VISIBLE);
1124
1125             shouldRefreshRecents = true;
1126             startRefreshingRecents();
1127
1128             SharedPreferences pref = U.getSharedPreferences(context);
1129             pref.edit().putBoolean("collapsed", true).apply();
1130
1131             updateButton(false);
1132
1133             new Handler().post(() -> LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_START_MENU_SPACE")));
1134         }
1135     }
1136
1137     private void hideTaskbar(boolean clearVariables) {
1138         if(clearVariables) {
1139             taskbarShownTemporarily = false;
1140             taskbarHiddenTemporarily = false;
1141         }
1142
1143         if(startButton.getVisibility() == View.VISIBLE) {
1144             startButton.setVisibility(View.GONE);
1145             space.setVisibility(View.GONE);
1146
1147             if(dashboardEnabled)
1148                 dashboardButton.setVisibility(View.GONE);
1149
1150             if(navbarButtonsEnabled)
1151                 navbarButtons.setVisibility(View.GONE);
1152
1153             if(isShowingRecents)
1154                 scrollView.setVisibility(View.GONE);
1155
1156             if(sysTrayEnabled)
1157                 sysTrayParentLayout.setVisibility(View.GONE);
1158
1159             shouldRefreshRecents = false;
1160             if(thread != null) thread.interrupt();
1161
1162             SharedPreferences pref = U.getSharedPreferences(context);
1163             pref.edit().putBoolean("collapsed", false).apply();
1164
1165             updateButton(true);
1166
1167             if(clearVariables) {
1168                 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
1169                 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD"));
1170             }
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
1570         if(batLevel == Integer.MIN_VALUE)
1571             return null;
1572
1573         IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
1574         Intent batteryStatus = context.registerReceiver(null, ifilter);
1575
1576         int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
1577         boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
1578                 status == BatteryManager.BATTERY_STATUS_FULL;
1579
1580         String batDrawable;
1581         if(batLevel < 10 && !isCharging)
1582             batDrawable = "alert";
1583         else if(batLevel < 25)
1584             batDrawable = "20";
1585         else if(batLevel < 40)
1586             batDrawable = "30";
1587         else if(batLevel < 55)
1588             batDrawable = "50";
1589         else if(batLevel < 70)
1590             batDrawable = "60";
1591         else if(batLevel < 85)
1592             batDrawable = "80";
1593         else if(batLevel < 95)
1594             batDrawable = "90";
1595         else
1596             batDrawable = "full";
1597
1598         String charging;
1599         if(isCharging)
1600             charging = "charging_";
1601         else
1602             charging = "";
1603
1604         String batRes = "ic_battery_" + charging + batDrawable + "_black_24dp";
1605         int id = context.getResources().getIdentifier(batRes, "drawable", BuildConfig.APPLICATION_ID);
1606
1607         return applyTintTo(ContextCompat.getDrawable(context, id));
1608     }
1609
1610     @TargetApi(Build.VERSION_CODES.M)
1611     private Drawable getWifiDrawable() {
1612         ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1613
1614         NetworkInfo ethernet = manager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
1615         if(ethernet != null && ethernet.isConnected())
1616             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_settings_ethernet_black_24dp));
1617
1618         NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
1619         if(wifi == null || !wifi.isConnected())
1620             return null;
1621
1622         WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
1623         int numberOfLevels = 5;
1624
1625         WifiInfo wifiInfo = wifiManager.getConnectionInfo();
1626         int level = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), numberOfLevels);
1627
1628         String wifiRes = "ic_signal_wifi_" + level + "_bar_black_24dp";
1629         int id = context.getResources().getIdentifier(wifiRes, "drawable", BuildConfig.APPLICATION_ID);
1630
1631         return applyTintTo(ContextCompat.getDrawable(context, id));
1632     }
1633
1634     private Drawable getBluetoothDrawable() {
1635         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1636         if(adapter != null && adapter.isEnabled())
1637             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_bluetooth_black_24dp));
1638
1639         return null;
1640     }
1641
1642     @TargetApi(Build.VERSION_CODES.M)
1643     private Drawable getCellularDrawable() {
1644         if(Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0)
1645             return applyTintTo(ContextCompat.getDrawable(context, R.drawable.ic_airplanemode_active_black_24dp));
1646
1647         if(cellStrength == -1)
1648             return null;
1649
1650         String cellRes = "ic_signal_cellular_" + cellStrength + "_bar_black_24dp";
1651         int id = context.getResources().getIdentifier(cellRes, "drawable", BuildConfig.APPLICATION_ID);
1652
1653         return applyTintTo(ContextCompat.getDrawable(context, id));
1654     }
1655     
1656     private Drawable applyTintTo(Drawable drawable) {
1657         if(drawable == null) return null;
1658
1659         drawable.setTint(U.getAccentColor(context));
1660         return drawable;
1661     }
1662 }