OSDN Git Service

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