OSDN Git Service

Couple more fixes
[android-x86/packages-apps-Taskbar.git] / app / src / main / java / com / farmerbb / taskbar / ui / TaskbarController.java
1 /* Copyright 2016 Braden Farmer
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 package com.farmerbb.taskbar.ui;
17
18 import android.accessibilityservice.AccessibilityService;
19 import android.annotation.SuppressLint;
20 import android.annotation.TargetApi;
21 import android.app.ActivityManager;
22 import android.app.AlarmManager;
23 import android.app.usage.UsageEvents;
24 import android.app.usage.UsageStats;
25 import android.app.usage.UsageStatsManager;
26 import android.bluetooth.BluetoothAdapter;
27 import android.content.ActivityNotFoundException;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.SharedPreferences;
33 import android.content.pm.LauncherActivityInfo;
34 import android.content.pm.LauncherApps;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ResolveInfo;
37 import android.content.res.Resources;
38 import android.graphics.Color;
39 import android.graphics.Point;
40 import android.graphics.Typeface;
41 import android.graphics.drawable.Drawable;
42 import android.net.ConnectivityManager;
43 import android.net.NetworkInfo;
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.Process;
52 import android.os.SystemClock;
53 import android.os.UserHandle;
54 import android.os.UserManager;
55 import android.provider.Settings;
56 import android.speech.RecognizerIntent;
57
58 import androidx.annotation.VisibleForTesting;
59 import androidx.core.content.ContextCompat;
60 import androidx.core.content.res.ResourcesCompat;
61 import androidx.core.graphics.ColorUtils;
62 import android.telephony.PhoneStateListener;
63 import android.telephony.SignalStrength;
64 import android.telephony.TelephonyManager;
65 import android.text.format.DateFormat;
66 import android.view.Display;
67 import android.view.Gravity;
68 import android.view.LayoutInflater;
69 import android.view.MotionEvent;
70 import android.view.PointerIcon;
71 import android.view.View;
72 import android.view.ViewGroup;
73 import android.view.WindowManager;
74 import android.view.inputmethod.InputMethodManager;
75 import android.widget.Button;
76 import android.widget.FrameLayout;
77 import android.widget.ImageView;
78
79 import java.lang.reflect.Field;
80 import java.util.ArrayList;
81 import java.util.Collections;
82 import java.util.Date;
83 import java.util.HashMap;
84 import java.util.List;
85 import java.util.Map;
86
87 import android.widget.LinearLayout;
88 import android.widget.Space;
89 import android.widget.TextView;
90
91 import com.farmerbb.taskbar.BuildConfig;
92 import com.farmerbb.taskbar.activity.HomeActivityDelegate;
93 import com.farmerbb.taskbar.activity.MainActivity;
94 import com.farmerbb.taskbar.R;
95 import com.farmerbb.taskbar.activity.HomeActivity;
96 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
97 import com.farmerbb.taskbar.activity.SecondaryHomeActivity;
98 import com.farmerbb.taskbar.util.TaskbarPosition;
99 import com.farmerbb.taskbar.util.AppEntry;
100 import com.farmerbb.taskbar.util.DisplayInfo;
101 import com.farmerbb.taskbar.helper.FreeformHackHelper;
102 import com.farmerbb.taskbar.util.IconCache;
103 import com.farmerbb.taskbar.helper.LauncherHelper;
104 import com.farmerbb.taskbar.util.PinnedBlockedApps;
105 import com.farmerbb.taskbar.helper.MenuHelper;
106 import com.farmerbb.taskbar.util.U;
107
108 import static com.farmerbb.taskbar.util.Constants.*;
109
110 public class TaskbarController extends UIController {
111
112     private LinearLayout layout;
113     private ImageView startButton;
114     private LinearLayout taskbar;
115     private FrameLayout scrollView;
116     private Button button;
117     private Space space;
118     private FrameLayout dashboardButton;
119     private LinearLayout navbarButtons;
120     private LinearLayout sysTrayLayout;
121     private FrameLayout sysTrayParentLayout;
122     private TextView time;
123     private ImageView notificationCountCircle;
124     private TextView notificationCountText;
125
126     private Handler handler;
127     private Handler handler2;
128     private Thread thread;
129     private Thread thread2;
130
131     private boolean isShowingRecents = true;
132     private boolean shouldRefreshRecents = true;
133     private boolean taskbarShownTemporarily = false;
134     private boolean taskbarHiddenTemporarily = false;
135     private boolean isRefreshingRecents = false;
136     private boolean isFirstStart = true;
137
138     private boolean startThread2 = false;
139     private boolean stopThread2 = false;
140
141     private int refreshInterval = -1;
142     private long searchInterval = -1;
143     private String sortOrder = "false";
144     private boolean runningAppsOnly = false;
145
146     private int currentTaskbarPosition = 0;
147     private boolean showHideAutomagically = false;
148     private boolean positionIsVertical = false;
149     private boolean dashboardEnabled = false;
150     private boolean navbarButtonsEnabled = false;
151     private boolean sysTrayEnabled = false;
152
153     private List<String> currentTaskbarIds = new ArrayList<>();
154     private int numOfPinnedApps = -1;
155
156     private int cellStrength = -1;
157     private int notificationCount = 0;
158     private int numOfSysTrayIcons = 0;
159
160     private boolean matchParent;
161     private Runnable updateParamsRunnable;
162
163     private final Map<Integer, Boolean> sysTrayIconStates = new HashMap<>();
164
165     private final View.OnClickListener ocl = view ->
166             U.sendBroadcast(context, ACTION_TOGGLE_START_MENU);
167
168     private final BroadcastReceiver showReceiver = new BroadcastReceiver() {
169         @Override
170         public void onReceive(Context context, Intent intent) {
171             showTaskbar(true);
172         }
173     };
174
175     private final BroadcastReceiver hideReceiver = new BroadcastReceiver() {
176         @Override
177         public void onReceive(Context context, Intent intent) {
178             hideTaskbar(true);
179         }
180     };
181
182     private final BroadcastReceiver tempShowReceiver = new BroadcastReceiver() {
183         @Override
184         public void onReceive(Context context, Intent intent) {
185             tempShowTaskbar();
186         }
187     };
188
189     private final BroadcastReceiver tempHideReceiver = new BroadcastReceiver() {
190         @Override
191         public void onReceive(Context context, Intent intent) {
192             tempHideTaskbar(false);
193         }
194     };
195
196     private final BroadcastReceiver startMenuAppearReceiver = new BroadcastReceiver() {
197         @Override
198         public void onReceive(Context context, Intent intent) {
199             if(startButton.getVisibility() == View.GONE
200                     && (!LauncherHelper.getInstance().isOnHomeScreen(context) || FreeformHackHelper.getInstance().isInFreeformWorkspace()))
201                 layout.setVisibility(View.GONE);
202         }
203     };
204
205     private final BroadcastReceiver startMenuDisappearReceiver = new BroadcastReceiver() {
206         @Override
207         public void onReceive(Context context, Intent intent) {
208             if(startButton.getVisibility() == View.GONE)
209                 layout.setVisibility(View.VISIBLE);
210         }
211     };
212
213     private final BroadcastReceiver notificationCountReceiver = new BroadcastReceiver() {
214         @Override
215         public void onReceive(Context context, Intent intent) {
216             notificationCount = intent.getIntExtra(EXTRA_COUNT, 0);
217         }
218     };
219
220     @TargetApi(Build.VERSION_CODES.M)
221     private final PhoneStateListener listener = new PhoneStateListener() {
222         @Override
223         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
224             try {
225                 cellStrength = signalStrength.getLevel();
226             } catch (SecurityException e) {
227                 cellStrength = -1;
228             }
229         }
230     };
231
232     public TaskbarController(Context context) {
233         super(context);
234     }
235
236     @Override
237     public void onCreateHost(UIHost host) {
238         init(context, host, () -> drawTaskbar(host));
239     }
240
241     private void drawTaskbar(UIHost host) {
242         IconCache.getInstance(context).clearCache();
243
244         // Initialize layout params
245         WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
246         TaskbarPosition.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
247
248         final ViewParams params = new ViewParams(
249                 WindowManager.LayoutParams.WRAP_CONTENT,
250                 WindowManager.LayoutParams.WRAP_CONTENT,
251                 -1,
252                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
253                 getBottomMargin(context, host)
254         );
255
256         // Determine where to show the taskbar on screen
257         String taskbarPosition = TaskbarPosition.getTaskbarPosition(context);
258         params.gravity = getTaskbarGravity(taskbarPosition);
259         int layoutId = getTaskbarLayoutId(taskbarPosition);
260         positionIsVertical = TaskbarPosition.isVertical(taskbarPosition);
261
262         // Initialize views
263         SharedPreferences pref = U.getSharedPreferences(context);
264         boolean altButtonConfig = pref.getBoolean(PREF_ALT_BUTTON_CONFIG, false);
265
266         layout = (LinearLayout) LayoutInflater.from(U.wrapContext(context)).inflate(layoutId, null);
267         taskbar = layout.findViewById(R.id.taskbar);
268         scrollView = layout.findViewById(R.id.taskbar_scrollview);
269
270         int backgroundTint = U.getBackgroundTint(context);
271         int accentColor = U.getAccentColor(context);
272
273         if(altButtonConfig) {
274             space = layout.findViewById(R.id.space_alt);
275             layout.findViewById(R.id.space).setVisibility(View.GONE);
276         } else {
277             space = layout.findViewById(R.id.space);
278             layout.findViewById(R.id.space_alt).setVisibility(View.GONE);
279         }
280
281         space.setOnClickListener(v -> toggleTaskbar(true));
282
283         startButton = layout.findViewById(R.id.start_button);
284         drawStartButton(context, startButton, pref, accentColor);
285
286         refreshInterval = (int) (Float.parseFloat(pref.getString(PREF_REFRESH_FREQUENCY, "1")) * 1000);
287         if(refreshInterval == 0)
288             refreshInterval = 100;
289
290         sortOrder = pref.getString(PREF_SORT_ORDER, "false");
291         runningAppsOnly =
292                 PREF_RECENTS_AMOUNT_RUNNING_APPS_ONLY
293                         .equals(pref.getString(PREF_RECENTS_AMOUNT, PREF_RECENTS_AMOUNT_PAST_DAY));
294         searchInterval = getSearchInterval(pref);
295
296         U.sendBroadcast(context, ACTION_HIDE_START_MENU);
297         U.sendBroadcast(context, ACTION_UPDATE_HOME_SCREEN_MARGINS);
298
299         if(altButtonConfig) {
300             button = layout.findViewById(R.id.hide_taskbar_button_alt);
301             layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE);
302         } else {
303             button = layout.findViewById(R.id.hide_taskbar_button);
304             layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE);
305         }
306
307         try {
308             button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf"));
309         } catch (RuntimeException ignored) {}
310
311         updateButton(false);
312         button.setOnClickListener(v -> toggleTaskbar(true));
313
314         LinearLayout buttonLayout = layout.findViewById(altButtonConfig
315                 ? R.id.hide_taskbar_button_layout_alt
316                 : R.id.hide_taskbar_button_layout);
317         if(buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar(true));
318
319         LinearLayout buttonLayoutToHide = layout.findViewById(altButtonConfig
320                 ? R.id.hide_taskbar_button_layout
321                 : R.id.hide_taskbar_button_layout_alt);
322         if(buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE);
323
324         dashboardButton = layout.findViewById(R.id.dashboard_button);
325         navbarButtons = layout.findViewById(R.id.navbar_buttons);
326         dashboardEnabled = drawDashboardButton(context, layout, dashboardButton, accentColor);
327         navbarButtonsEnabled = drawNavbarButtons(context, layout, pref, accentColor);
328         if(!navbarButtonsEnabled)
329             navbarButtons.setVisibility(View.GONE);
330
331         sysTrayEnabled = U.isSystemTrayEnabled(context);
332
333         if(sysTrayEnabled) {
334             drawSysTray(context, layoutId, layout);
335         }
336
337         layout.setBackgroundColor(backgroundTint);
338         layout.findViewById(R.id.divider).setBackgroundColor(accentColor);
339         button.setTextColor(accentColor);
340
341         applyMarginFix(host, layout, params);
342
343         if(isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace())
344             showTaskbar(false);
345         else if(!pref.getBoolean(PREF_COLLAPSED, false) && pref.getBoolean(PREF_TASKBAR_ACTIVE, false))
346             toggleTaskbar(false);
347
348         if(pref.getBoolean(PREF_AUTO_HIDE_NAVBAR, false))
349             U.showHideNavigationBar(context, false);
350
351         if(FreeformHackHelper.getInstance().isTouchAbsorberActive()) {
352             U.sendBroadcast(context, ACTION_FINISH_FREEFORM_ACTIVITY);
353
354             U.newHandler().postDelayed(() -> U.startTouchAbsorberActivity(context), 500);
355         }
356
357         U.registerReceiver(context, showReceiver, ACTION_SHOW_TASKBAR);
358         U.registerReceiver(context, hideReceiver, ACTION_HIDE_TASKBAR);
359         U.registerReceiver(context, tempShowReceiver, ACTION_TEMP_SHOW_TASKBAR);
360         U.registerReceiver(context, tempHideReceiver, ACTION_TEMP_HIDE_TASKBAR);
361         U.registerReceiver(context, startMenuAppearReceiver, ACTION_START_MENU_APPEARING);
362         U.registerReceiver(context, startMenuDisappearReceiver, ACTION_START_MENU_DISAPPEARING);
363
364         if(sysTrayEnabled) {
365             TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
366             manager.listen(listener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
367
368             U.registerReceiver(context, notificationCountReceiver, ACTION_NOTIFICATION_COUNT_CHANGED);
369             U.sendBroadcast(context, ACTION_REQUEST_NOTIFICATION_COUNT);
370         }
371
372         matchParent = false;
373         updateParamsRunnable = () -> {
374             ViewParams newParams;
375             if(TaskbarPosition.isVertical(context)) {
376                 newParams = matchParent
377                         ? params.updateHeight(WindowManager.LayoutParams.MATCH_PARENT)
378                         : params.updateHeight(WindowManager.LayoutParams.WRAP_CONTENT);
379             } else {
380                 newParams = matchParent
381                         ? params.updateWidth(WindowManager.LayoutParams.MATCH_PARENT)
382                         : params.updateWidth(WindowManager.LayoutParams.WRAP_CONTENT);
383             }
384
385             host.updateViewLayout(layout, newParams);
386         };
387
388         startRefreshingRecents();
389
390         host.addView(layout, params);
391
392         isFirstStart = false;
393     }
394
395     @SuppressLint("RtlHardcoded")
396     @VisibleForTesting
397     int getTaskbarGravity(String taskbarPosition) {
398         int gravity = Gravity.BOTTOM | Gravity.LEFT;
399         switch(taskbarPosition) {
400             case POSITION_BOTTOM_LEFT:
401             case POSITION_BOTTOM_VERTICAL_LEFT:
402                 gravity = Gravity.BOTTOM | Gravity.LEFT;
403                 break;
404             case POSITION_BOTTOM_RIGHT:
405             case POSITION_BOTTOM_VERTICAL_RIGHT:
406                 gravity = Gravity.BOTTOM | Gravity.RIGHT;
407                 break;
408             case POSITION_TOP_LEFT:
409             case POSITION_TOP_VERTICAL_LEFT:
410                 gravity = Gravity.TOP | Gravity.LEFT;
411                 break;
412             case POSITION_TOP_RIGHT:
413             case POSITION_TOP_VERTICAL_RIGHT:
414                 gravity = Gravity.TOP | Gravity.RIGHT;
415                 break;
416         }
417         return gravity;
418     }
419
420     @VisibleForTesting
421     int getTaskbarLayoutId(String taskbarPosition) {
422         int layoutId = R.layout.tb_taskbar_left;
423         switch(taskbarPosition) {
424             case POSITION_BOTTOM_LEFT:
425             case POSITION_TOP_LEFT:
426                 layoutId = R.layout.tb_taskbar_left;
427                 break;
428             case POSITION_BOTTOM_VERTICAL_LEFT:
429             case POSITION_BOTTOM_VERTICAL_RIGHT:
430                 layoutId = R.layout.tb_taskbar_vertical;
431                 break;
432             case POSITION_BOTTOM_RIGHT:
433             case POSITION_TOP_RIGHT:
434                 layoutId = R.layout.tb_taskbar_right;
435                 break;
436             case POSITION_TOP_VERTICAL_LEFT:
437             case POSITION_TOP_VERTICAL_RIGHT:
438                 layoutId = R.layout.tb_taskbar_top_vertical;
439                 break;
440         }
441         return layoutId;
442     }
443
444     @VisibleForTesting
445     void drawStartButton(Context context, ImageView startButton, SharedPreferences pref, int accentColor) {
446         Drawable allAppsIcon = ContextCompat.getDrawable(context, R.drawable.tb_all_apps_button_icon);
447         int padding = 0;
448
449         switch(pref.getString(PREF_START_BUTTON_IMAGE, U.getDefaultStartButtonImage(context))) {
450             case PREF_START_BUTTON_IMAGE_DEFAULT:
451                 startButton.setImageDrawable(allAppsIcon);
452                 padding = context.getResources().getDimensionPixelSize(R.dimen.tb_app_drawer_icon_padding);
453                 break;
454             case PREF_START_BUTTON_IMAGE_APP_LOGO:
455                 Drawable drawable;
456
457                 if(U.isAndroidGeneric(context)) {
458                     try {
459                         String bdPackageName = "com.boringdroid.systemui";
460                         Resources res = context.getPackageManager().getResourcesForApplication(bdPackageName);
461                         int id = res.getIdentifier("bt_all_apps", "drawable", bdPackageName);
462                         drawable = ResourcesCompat.getDrawable(res, id, null);
463                     } catch (Exception e) {
464                         drawable = ContextCompat.getDrawable(context, R.drawable.tb_bliss);
465                         drawable.setTint(accentColor);
466                     }
467                 } else {
468                     LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
469                     LauncherActivityInfo info = launcherApps.getActivityList(context.getPackageName(), Process.myUserHandle()).get(0);
470                     drawable = IconCache.getInstance(context).getIcon(context, context.getPackageManager(), info);
471                 }
472
473                 startButton.setImageDrawable(drawable);
474                 padding = context.getResources().getDimensionPixelSize(R.dimen.tb_app_drawer_icon_padding_alt);
475                 break;
476             case PREF_START_BUTTON_IMAGE_CUSTOM:
477                 U.applyCustomImage(context, "custom_image", startButton, allAppsIcon);
478                 padding = context.getResources().getDimensionPixelSize(R.dimen.tb_app_drawer_icon_padding);
479                 break;
480         }
481
482         startButton.setPadding(padding, padding, padding, padding);
483         startButton.setOnClickListener(ocl);
484         startButton.setOnLongClickListener(view -> {
485             openContextMenu();
486             return true;
487         });
488
489         startButton.setOnGenericMotionListener((view, motionEvent) -> {
490             if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
491                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
492                 openContextMenu();
493
494             return false;
495         });
496     }
497
498     @VisibleForTesting
499     boolean drawDashboardButton(Context context,
500                                 LinearLayout layout,
501                                 FrameLayout dashboardButton,
502                                 int accentColor) {
503         boolean dashboardEnabled = U.getBooleanPrefWithDefault(context, PREF_DASHBOARD);
504         if(dashboardEnabled) {
505             layout.findViewById(R.id.square1).setBackgroundColor(accentColor);
506             layout.findViewById(R.id.square2).setBackgroundColor(accentColor);
507             layout.findViewById(R.id.square3).setBackgroundColor(accentColor);
508             layout.findViewById(R.id.square4).setBackgroundColor(accentColor);
509             layout.findViewById(R.id.square5).setBackgroundColor(accentColor);
510             layout.findViewById(R.id.square6).setBackgroundColor(accentColor);
511
512             dashboardButton.setOnClickListener(v -> U.sendBroadcast(context, ACTION_TOGGLE_DASHBOARD));
513             dashboardButton.setVisibility(View.VISIBLE);
514         } else
515             dashboardButton.setVisibility(View.GONE);
516
517         return dashboardEnabled;
518     }
519
520     @VisibleForTesting
521     boolean drawNavbarButtons(Context context,
522                               LinearLayout layout,
523                               SharedPreferences pref,
524                               int accentColor) {
525         boolean navbarButtonsEnabled = false;
526         if(pref.getBoolean(PREF_BUTTON_BACK, false)) {
527             navbarButtonsEnabled = true;
528
529             ImageView backButton = layout.findViewById(R.id.button_back);
530             backButton.setColorFilter(accentColor);
531             backButton.setVisibility(View.VISIBLE);
532             backButton.setOnClickListener(v -> {
533                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_BACK);
534                 if(U.shouldCollapse(context, false))
535                     hideTaskbar(true);
536             });
537
538             backButton.setOnLongClickListener(v -> {
539                 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
540                 imm.showInputMethodPicker();
541
542                 if(U.shouldCollapse(context, false))
543                     hideTaskbar(true);
544
545                 return true;
546             });
547
548             backButton.setOnGenericMotionListener((view13, motionEvent) -> {
549                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
550                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
551                     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
552                     imm.showInputMethodPicker();
553
554                     if(U.shouldCollapse(context, false))
555                         hideTaskbar(true);
556                 }
557                 return true;
558             });
559         }
560
561         if(pref.getBoolean(PREF_BUTTON_HOME, false)) {
562             navbarButtonsEnabled = true;
563
564             ImageView homeButton = layout.findViewById(R.id.button_home);
565             homeButton.setColorFilter(accentColor);
566             homeButton.setVisibility(View.VISIBLE);
567             homeButton.setOnClickListener(v -> {
568                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_HOME);
569                 if(U.shouldCollapse(context, false))
570                     hideTaskbar(true);
571             });
572
573             homeButton.setOnLongClickListener(v -> {
574                 Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
575                 voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
576
577                 try {
578                     context.startActivity(voiceSearchIntent);
579                 } catch (ActivityNotFoundException ignored) {}
580
581                 if(U.shouldCollapse(context, false))
582                     hideTaskbar(true);
583
584                 return true;
585             });
586
587             homeButton.setOnGenericMotionListener((view13, motionEvent) -> {
588                 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
589                         && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
590                     Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
591                     voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
592
593                     try {
594                         context.startActivity(voiceSearchIntent);
595                     } catch (ActivityNotFoundException ignored) {}
596
597                     if(U.shouldCollapse(context, false))
598                         hideTaskbar(true);
599                 }
600                 return true;
601             });
602         }
603
604         if(pref.getBoolean(PREF_BUTTON_RECENTS, false)) {
605             navbarButtonsEnabled = true;
606
607             ImageView recentsButton = layout.findViewById(R.id.button_recents);
608             recentsButton.setColorFilter(accentColor);
609             recentsButton.setVisibility(View.VISIBLE);
610             recentsButton.setOnClickListener(v -> {
611                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_RECENTS);
612                 if(U.shouldCollapse(context, false))
613                     hideTaskbar(true);
614             });
615
616             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
617                 recentsButton.setOnLongClickListener(v -> {
618                     U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
619                     if(U.shouldCollapse(context, false))
620                         hideTaskbar(true);
621
622                     return true;
623                 });
624
625                 recentsButton.setOnGenericMotionListener((view13, motionEvent) -> {
626                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
627                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
628                         U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
629                         if(U.shouldCollapse(context, false))
630                             hideTaskbar(true);
631                     }
632                     return true;
633                 });
634             }
635         }
636         return navbarButtonsEnabled;
637     }
638
639     @VisibleForTesting
640     long getSearchInterval(SharedPreferences pref) {
641         long searchInterval = -1;
642         switch(pref.getString(PREF_RECENTS_AMOUNT, PREF_RECENTS_AMOUNT_PAST_DAY)) {
643             case PREF_RECENTS_AMOUNT_PAST_DAY:
644                 searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY;
645                 break;
646             case PREF_RECENTS_AMOUNT_APP_START:
647                 long appStartTime = pref.getLong(PREF_TIME_OF_SERVICE_START, System.currentTimeMillis());
648                 long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
649                 searchInterval = Math.max(deviceStartTime, appStartTime);
650                 break;
651             case PREF_RECENTS_AMOUNT_SHOW_ALL:
652                 searchInterval = 0;
653                 break;
654         }
655         return searchInterval;
656     }
657
658     @VisibleForTesting
659     void drawSysTray(Context context, int layoutId, LinearLayout layout) {
660         sysTrayLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.tb_system_tray, null);
661
662         FrameLayout.LayoutParams sysTrayParams = new FrameLayout.LayoutParams(
663                 FrameLayout.LayoutParams.WRAP_CONTENT,
664                 context.getResources().getDimensionPixelSize(R.dimen.tb_icon_size)
665         );
666
667         if(layoutId == R.layout.tb_taskbar_right) {
668             time = sysTrayLayout.findViewById(R.id.time_left);
669             sysTrayParams.gravity = Gravity.START;
670             sysTrayLayout.findViewById(R.id.space_right).setVisibility(View.VISIBLE);
671         } else {
672             time = sysTrayLayout.findViewById(R.id.time_right);
673             sysTrayParams.gravity = Gravity.END;
674             sysTrayLayout.findViewById(R.id.space_left).setVisibility(View.VISIBLE);
675         }
676
677         time.setVisibility(View.VISIBLE);
678         sysTrayLayout.setLayoutParams(sysTrayParams);
679
680         if(!U.isLibrary(context)) {
681             sysTrayLayout.setOnClickListener(v -> {
682                 U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, () -> {
683                     if(LauncherHelper.getInstance().isOnSecondaryHomeScreen(context)) {
684                         U.showToast(context, R.string.tb_opening_notification_tray);
685                         U.sendBroadcast(context, ACTION_UNDIM_SCREEN);
686                     }
687                 });
688
689                 if(U.shouldCollapse(context, false))
690                     hideTaskbar(true);
691             });
692
693             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
694                 sysTrayLayout.setOnLongClickListener(v -> {
695                     U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS, () -> {
696                         if(LauncherHelper.getInstance().isOnSecondaryHomeScreen(context)) {
697                             U.showToast(context, R.string.tb_opening_quick_settings);
698                             U.sendBroadcast(context, ACTION_UNDIM_SCREEN);
699                         }
700                     });
701
702                     if(U.shouldCollapse(context, false))
703                         hideTaskbar(true);
704
705                     return true;
706                 });
707
708                 sysTrayLayout.setOnGenericMotionListener((view, motionEvent) -> {
709                     if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
710                             && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
711                         U.sendAccessibilityAction(context, AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS, () -> {
712                             if(LauncherHelper.getInstance().isOnSecondaryHomeScreen(context)) {
713                                 U.showToast(context, R.string.tb_opening_quick_settings);
714                                 U.sendBroadcast(context, ACTION_UNDIM_SCREEN);
715                             }
716                         });
717
718                         if(U.shouldCollapse(context, false))
719                             hideTaskbar(true);
720                     }
721                     return true;
722                 });
723             }
724         }
725
726         notificationCountCircle = sysTrayLayout.findViewById(R.id.notification_count_circle);
727         notificationCountText = sysTrayLayout.findViewById(R.id.notification_count_text);
728
729         sysTrayParentLayout = layout.findViewById(R.id.add_systray_here);
730         sysTrayParentLayout.setVisibility(View.VISIBLE);
731         sysTrayParentLayout.addView(sysTrayLayout);
732
733         sysTrayIconStates.clear();
734         sysTrayIconStates.put(R.id.cellular, false);
735         sysTrayIconStates.put(R.id.bluetooth, false);
736         sysTrayIconStates.put(R.id.wifi, false);
737         sysTrayIconStates.put(R.id.battery, false);
738         sysTrayIconStates.put(R.id.notification_count, false);
739     }
740
741     private void startRefreshingRecents() {
742         if(thread != null) thread.interrupt();
743         stopThread2 = true;
744
745         SharedPreferences pref = U.getSharedPreferences(context);
746         showHideAutomagically = pref.getBoolean(PREF_HIDE_WHEN_KEYBOARD_SHOWN, false);
747
748         currentTaskbarIds.clear();
749
750         handler = U.newHandler();
751         thread = new Thread(() -> {
752             updateRecentApps(true);
753
754             if(!isRefreshingRecents) {
755                 isRefreshingRecents = true;
756
757                 while(shouldRefreshRecents) {
758                     updateRecentApps(false);
759
760                     if(showHideAutomagically && !positionIsVertical && !MenuHelper.getInstance().isStartMenuOpen()) {
761                         handler.post(() -> {
762                             if(layout != null) {
763                                 int[] location = new int[2];
764                                 layout.getLocationOnScreen(location);
765
766                                 if(location[1] != 0) {
767                                     if(location[1] > currentTaskbarPosition) {
768                                         currentTaskbarPosition = location[1];
769                                     } else if(location[1] < currentTaskbarPosition) {
770                                         if(currentTaskbarPosition - location[1] == getNavBarSize())
771                                             currentTaskbarPosition = location[1];
772                                         else if(!startThread2) {
773                                             startThread2 = true;
774                                             tempHideTaskbar(true);
775                                         }
776                                     }
777                                 }
778                             }
779                         });
780                     }
781
782                     SystemClock.sleep(refreshInterval);
783                 }
784
785                 isRefreshingRecents = false;
786             }
787         });
788
789         thread.start();
790     }
791
792     @SuppressWarnings("Convert2streamapi")
793     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
794     private void updateRecentApps(final boolean firstRefresh) {
795         if(isScreenOff()) return;
796
797         updateSystemTray();
798
799         SharedPreferences pref = U.getSharedPreferences(context);
800         final PackageManager pm = context.getPackageManager();
801         final List<AppEntry> entries = new ArrayList<>();
802         List<LauncherActivityInfo> launcherAppCache = new ArrayList<>();
803         int maxNumOfEntries = firstRefresh ? 0 : U.getMaxNumOfEntries(context);
804         boolean fullLength = pref.getBoolean(PREF_FULL_LENGTH, true);
805
806         PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
807         List<AppEntry> pinnedApps = pba.getPinnedApps();
808         List<AppEntry> blockedApps = pba.getBlockedApps();
809         List<String> applicationIdsToRemove = new ArrayList<>();
810
811         // Filter out anything on the pinned/blocked apps lists
812         int realNumOfPinnedApps = filterRealPinnedApps(context, pinnedApps, entries, applicationIdsToRemove);
813
814         if(blockedApps.size() > 0) {
815             //noinspection SynchronizationOnLocalVariableOrMethodParameter
816             synchronized(blockedApps) {
817                 for(AppEntry entry : blockedApps) {
818                     applicationIdsToRemove.add(entry.getPackageName());
819                 }
820             }
821         }
822
823         // Get list of all recently used apps
824         List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>();
825         if(usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) {
826             if(realNumOfPinnedApps < maxNumOfEntries) {
827                 List<AppEntry> usageStatsList2 = new ArrayList<>();
828                 List<AppEntry> usageStatsList3 = new ArrayList<>();
829                 List<AppEntry> usageStatsList4 = new ArrayList<>();
830                 List<AppEntry> usageStatsList5 = new ArrayList<>();
831                 List<AppEntry> usageStatsList6;
832
833                 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
834                 homeIntent.addCategory(Intent.CATEGORY_HOME);
835                 ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
836
837                 // Filter out apps without a launcher intent
838                 // Also filter out the current launcher, and Taskbar itself
839                 for(AppEntry packageInfo : usageStatsList) {
840                     if(hasLauncherIntent(packageInfo.getPackageName())
841                             && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
842                             && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName)
843                             && (!(U.launcherIsDefault(context) && pref.getBoolean(PREF_DESKTOP_MODE, false))
844                             || !packageInfo.getPackageName().equals(pref.getString(PREF_HSL_ID, "null"))))
845                         usageStatsList2.add(packageInfo);
846                 }
847
848                 // Filter out apps that don't fall within our current search interval
849                 for(AppEntry stats : usageStatsList2) {
850                     if(stats.getLastTimeUsed() > searchInterval || runningAppsOnly)
851                         usageStatsList3.add(stats);
852                 }
853
854                 // Sort apps by either most recently used, or most time used
855                 if(!runningAppsOnly && sortOrder.contains("most_used")) {
856                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground()));
857                 } else {
858                     Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed()));
859                 }
860
861                 // Filter out any duplicate entries
862                 List<String> applicationIds = new ArrayList<>();
863                 for(AppEntry stats : usageStatsList3) {
864                     if(!applicationIds.contains(stats.getPackageName())) {
865                         usageStatsList4.add(stats);
866                         applicationIds.add(stats.getPackageName());
867                     }
868                 }
869
870                 // Filter out the currently running foreground app, if requested by the user
871                 filterForegroundApp(context, pref, searchInterval, applicationIdsToRemove);
872
873                 for(AppEntry stats : usageStatsList4) {
874                     if(!applicationIdsToRemove.contains(stats.getPackageName())) {
875                         usageStatsList5.add(stats);
876                     }
877                 }
878
879                 // Truncate list to a maximum length
880                 if(usageStatsList5.size() > maxNumOfEntries)
881                     usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries);
882                 else
883                     usageStatsList6 = usageStatsList5;
884
885                 // Determine if we need to reverse the order
886                 if(needToReverseOrder(context, sortOrder)) {
887                     Collections.reverse(usageStatsList6);
888                 }
889
890                 // Generate the AppEntries for the recent apps list
891                 int number = usageStatsList6.size() == maxNumOfEntries
892                         ? usageStatsList6.size() - realNumOfPinnedApps
893                         : usageStatsList6.size();
894
895                 generateAppEntries(context, number, usageStatsList6, entries, launcherAppCache);
896             }
897
898             while(entries.size() > maxNumOfEntries) {
899                 try {
900                     entries.remove(entries.size() - 1);
901                     launcherAppCache.remove(launcherAppCache.size() - 1);
902                 } catch (ArrayIndexOutOfBoundsException ignored) {}
903             }
904
905             // Determine if we need to reverse the order again
906             if(TaskbarPosition.isVertical(context)) {
907                 Collections.reverse(entries);
908                 Collections.reverse(launcherAppCache);
909             }
910
911             // Now that we've generated the list of apps,
912             // we need to determine if we need to redraw the Taskbar or not
913             boolean shouldRedrawTaskbar = firstRefresh;
914
915             List<String> finalApplicationIds = new ArrayList<>();
916             for(AppEntry entry : entries) {
917                 finalApplicationIds.add(entry.getPackageName());
918             }
919
920             int realNumOfSysTrayIcons = 0;
921             for(Integer key : sysTrayIconStates.keySet()) {
922                 if(sysTrayIconStates.get(key))
923                     realNumOfSysTrayIcons++;
924             }
925
926             if(finalApplicationIds.size() != currentTaskbarIds.size()
927                     || numOfPinnedApps != realNumOfPinnedApps
928                     || numOfSysTrayIcons != realNumOfSysTrayIcons)
929                 shouldRedrawTaskbar = true;
930             else {
931                 for(int i = 0; i < finalApplicationIds.size(); i++) {
932                     if(!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) {
933                         shouldRedrawTaskbar = true;
934                         break;
935                     }
936                 }
937             }
938
939             if(shouldRedrawTaskbar) {
940                 currentTaskbarIds = finalApplicationIds;
941                 numOfPinnedApps = realNumOfPinnedApps;
942                 numOfSysTrayIcons = realNumOfSysTrayIcons;
943
944                 populateAppEntries(context, pm, entries, launcherAppCache);
945
946                 final int numOfEntries = Math.min(entries.size(), maxNumOfEntries);
947
948                 handler.post(() -> {
949                     if(numOfEntries > 0 || fullLength) {
950                         ViewGroup.LayoutParams params = scrollView.getLayoutParams();
951                         calculateScrollViewParams(context, pref, params, fullLength, numOfEntries);
952                         scrollView.setLayoutParams(params);
953
954                         for(Integer key : sysTrayIconStates.keySet()) {
955                             sysTrayLayout.findViewById(key).setVisibility(
956                                     sysTrayIconStates.get(key) ? View.VISIBLE : View.GONE
957                             );
958                         }
959
960                         taskbar.removeAllViews();
961                         for(int i = 0; i < entries.size(); i++) {
962                             taskbar.addView(getView(entries, i));
963                         }
964
965                         if(runningAppsOnly)
966                             updateRunningAppIndicators(pinnedApps, usageStatsList, entries);
967
968                         isShowingRecents = true;
969                         if(shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) {
970                             if(firstRefresh)
971                                 scrollView.setVisibility(View.INVISIBLE);
972                             else
973                                 scrollView.setVisibility(View.VISIBLE);
974                         }
975
976                         if(firstRefresh && scrollView.getVisibility() != View.VISIBLE) {
977                             U.newHandler().post(
978                                     () -> scrollTaskbar(
979                                             scrollView,
980                                             taskbar,
981                                             TaskbarPosition.getTaskbarPosition(context),
982                                             sortOrder,
983                                             shouldRefreshRecents
984                                     )
985                             );
986                         }
987                     } else {
988                         isShowingRecents = false;
989                         scrollView.setVisibility(View.GONE);
990                     }
991                 });
992             } else if(runningAppsOnly)
993                 handler.post(() -> updateRunningAppIndicators(pinnedApps, usageStatsList, entries));
994         } else if(firstRefresh || currentTaskbarIds.size() > 0) {
995             currentTaskbarIds.clear();
996             handler.post(() -> {
997                 isShowingRecents = false;
998                 scrollView.setVisibility(View.GONE);
999             });
1000         }
1001     }
1002
1003     @VisibleForTesting
1004     void calculateScrollViewParams(Context context,
1005                                    SharedPreferences pref,
1006                                    ViewGroup.LayoutParams params,
1007                                    boolean fullLength,
1008                                    int numOfEntries) {
1009         DisplayInfo display = U.getDisplayInfo(context, true);
1010         int recentsSize = context.getResources().getDimensionPixelSize(R.dimen.tb_icon_size) * numOfEntries;
1011         float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize;
1012         int maxScreenSize;
1013
1014         float baseStart = U.getBaseTaskbarSizeStart(context);
1015         float baseEnd = U.getBaseTaskbarSizeEnd(context, sysTrayIconStates);
1016         int baseTotal = Math.round(baseStart + baseEnd);
1017
1018         int diff = Math.round(Math.max(baseStart, baseEnd) - Math.min(baseStart, baseEnd));
1019         boolean startIsBigger = Math.max(baseStart, baseEnd) == baseStart;
1020
1021         if(TaskbarPosition.isVertical(context)) {
1022             maxScreenSize = Math.max(0, display.height
1023                     - U.getStatusBarHeight(context)
1024                     - baseTotal);
1025
1026             params.height = (int) Math.min(maxRecentsSize, maxScreenSize)
1027                     + context.getResources().getDimensionPixelSize(R.dimen.tb_divider_size);
1028
1029             if(fullLength) {
1030                 try {
1031                     Space whitespaceStart = layout.findViewById(R.id.whitespace_start);
1032                     Space whitespaceEnd = layout.findViewById(R.id.whitespace_end);
1033                     int height = maxScreenSize - recentsSize;
1034
1035                     if(pref.getBoolean(PREF_CENTERED_ICONS, false)) {
1036                         int startHeight = (height / 2) + (diff / (startIsBigger ? -2 : 2));
1037                         int endHeight = (height / 2) + (diff / (startIsBigger ? 2 : -2));
1038                         
1039                         if(startHeight < 0) {
1040                             startHeight = 0;
1041                             endHeight = height;
1042                         }
1043
1044                         if(endHeight < 0) {
1045                             startHeight = height;
1046                             endHeight = 0;
1047                         }
1048                         
1049                         ViewGroup.LayoutParams startParams = whitespaceStart.getLayoutParams();
1050                         startParams.height = startHeight;
1051                         whitespaceStart.setLayoutParams(startParams);
1052
1053                         ViewGroup.LayoutParams endParams = whitespaceEnd.getLayoutParams();
1054                         endParams.height = endHeight;
1055                         whitespaceEnd.setLayoutParams(endParams);
1056                     } else {
1057                         ViewGroup.LayoutParams endParams = whitespaceEnd.getLayoutParams();
1058                         endParams.height = height;
1059                         whitespaceEnd.setLayoutParams(endParams);
1060                     }
1061                 } catch (NullPointerException ignored) {}
1062             }
1063         } else {
1064             maxScreenSize = Math.max(0, display.width - baseTotal);
1065
1066             params.width = (int) Math.min(maxRecentsSize, maxScreenSize)
1067                     + context.getResources().getDimensionPixelSize(R.dimen.tb_divider_size);
1068
1069             if(fullLength) {
1070                 try {
1071                     Space whitespaceStart = layout.findViewById(R.id.whitespace_start);
1072                     Space whitespaceEnd = layout.findViewById(R.id.whitespace_end);
1073                     int width = maxScreenSize - recentsSize;
1074
1075                     if(pref.getBoolean(PREF_CENTERED_ICONS, false)) {
1076                         int startWidth = (width / 2) + (diff / (startIsBigger ? -2 : 2));
1077                         int endWidth = (width / 2) + (diff / (startIsBigger ? 2 : -2));
1078
1079                         if(startWidth < 0) {
1080                             startWidth = 0;
1081                             endWidth = width;
1082                         }
1083                         
1084                         if(endWidth < 0) {
1085                             startWidth = width;
1086                             endWidth = 0;
1087                         }
1088                         
1089                         ViewGroup.LayoutParams startParams = whitespaceStart.getLayoutParams();
1090                         startParams.width = startWidth;
1091                         whitespaceStart.setLayoutParams(startParams);
1092
1093                         ViewGroup.LayoutParams endParams = whitespaceEnd.getLayoutParams();
1094                         endParams.width = endWidth;
1095                         whitespaceEnd.setLayoutParams(endParams);
1096                     } else {
1097                         ViewGroup.LayoutParams endParams = whitespaceEnd.getLayoutParams();
1098                         endParams.width = width;
1099                         whitespaceEnd.setLayoutParams(endParams);
1100                     }
1101                 } catch (NullPointerException ignored) {}
1102             }
1103         }
1104
1105         boolean realMatchParent = maxRecentsSize >= maxScreenSize
1106                 && pref.getBoolean(PREF_COLLAPSED, false)
1107                 && !(TaskbarPosition.isVertical(context) && U.isChromeOs(context));
1108
1109         if(realMatchParent != matchParent) {
1110             matchParent = realMatchParent;
1111             U.newHandler().post(updateParamsRunnable);
1112         }
1113     }
1114
1115     @VisibleForTesting
1116     void scrollTaskbar(FrameLayout scrollView,
1117                        LinearLayout taskbar,
1118                        String taskbarPosition,
1119                        String sortOrder,
1120                        boolean shouldRefreshRecents) {
1121         if(TaskbarPosition.isVertical(taskbarPosition)) {
1122             if(sortOrder.contains("false")) {
1123                 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1124             } else if(sortOrder.contains("true")) {
1125                 scrollView.scrollTo(0, 0);
1126             }
1127         } else {
1128             if(sortOrder.contains("false")) {
1129                 scrollView.scrollTo(0, 0);
1130             } else if(sortOrder.contains("true")) {
1131                 scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight());
1132             }
1133         }
1134
1135         if(shouldRefreshRecents) {
1136             scrollView.setVisibility(View.VISIBLE);
1137         }
1138     }
1139
1140     @TargetApi(Build.VERSION_CODES.M)
1141     @VisibleForTesting
1142     void filterForegroundApp(Context context,
1143                              SharedPreferences pref,
1144                              long searchInterval,
1145                              List<String> applicationIdsToRemove) {
1146         if(pref.getBoolean(PREF_HIDE_FOREGROUND, false)) {
1147             UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
1148             UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis());
1149             UsageEvents.Event eventCache = new UsageEvents.Event();
1150             String currentForegroundApp = null;
1151
1152             while (events.hasNextEvent()) {
1153                 events.getNextEvent(eventCache);
1154
1155                 if(eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
1156                     if(!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID)
1157                             && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName())
1158                             && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName())
1159                             && !eventCache.getClassName().equals(HomeActivityDelegate.class.getCanonicalName())
1160                             && !eventCache.getClassName().equals(SecondaryHomeActivity.class.getCanonicalName())
1161                             && !eventCache.getClassName().equals(InvisibleActivityFreeform.class.getCanonicalName()))) {
1162                         currentForegroundApp = eventCache.getPackageName();
1163                     }
1164                 }
1165             }
1166
1167             if(!applicationIdsToRemove.contains(currentForegroundApp)) {
1168                 applicationIdsToRemove.add(currentForegroundApp);
1169             }
1170         }
1171     }
1172
1173     @VisibleForTesting
1174     boolean needToReverseOrder(Context context, String sortOrder) {
1175         switch(TaskbarPosition.getTaskbarPosition(context)) {
1176             case POSITION_BOTTOM_RIGHT:
1177             case POSITION_TOP_RIGHT:
1178                 return sortOrder.contains("false");
1179             default:
1180                 return sortOrder.contains("true");
1181         }
1182     }
1183
1184     @VisibleForTesting
1185     int filterRealPinnedApps(Context context,
1186                              List<AppEntry> pinnedApps,
1187                              List<AppEntry> entries,
1188                              List<String> applicationIdsToRemove) {
1189         int realNumOfPinnedApps = 0;
1190         if(pinnedApps.size() > 0) {
1191             //noinspection SynchronizationOnLocalVariableOrMethodParameter
1192             synchronized(pinnedApps) {
1193                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1194                 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
1195
1196                 for(AppEntry entry : pinnedApps) {
1197                     boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(),
1198                             userManager.getUserForSerialNumber(entry.getUserId(context)));
1199
1200                     if(packageEnabled)
1201                         entries.add(entry);
1202                     else
1203                         realNumOfPinnedApps--;
1204
1205                     applicationIdsToRemove.add(entry.getPackageName());
1206                 }
1207
1208                 realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size();
1209             }
1210         }
1211
1212         return realNumOfPinnedApps;
1213     }
1214
1215     @VisibleForTesting
1216     void generateAppEntries(Context context,
1217                             int number,
1218                             List<AppEntry> usageStatsList6,
1219                             List<AppEntry> entries,
1220                             List<LauncherActivityInfo> launcherAppCache) {
1221         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1222         LauncherApps launcherApps =
1223                 (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
1224
1225         final List<UserHandle> userHandles = userManager.getUserProfiles();
1226
1227         final String googleSearchBoxPackage = "com.google.android.googlequicksearchbox";
1228         final String googleSearchBoxActivity =
1229                 "com.google.android.googlequicksearchbox.SearchActivity";
1230         for(int i = 0; i < number; i++) {
1231             for(UserHandle handle : userHandles) {
1232                 String packageName = usageStatsList6.get(i).getPackageName();
1233                 long lastTimeUsed = usageStatsList6.get(i).getLastTimeUsed();
1234                 List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle);
1235                 if(!list.isEmpty()) {
1236                     // Google App workaround
1237                     if(!packageName.equals(googleSearchBoxPackage)) {
1238                         launcherAppCache.add(list.get(0));
1239                     } else {
1240                         boolean added = false;
1241                         for(LauncherActivityInfo info : list) {
1242                             if(info.getName().equals(googleSearchBoxActivity)) {
1243                                 launcherAppCache.add(info);
1244                                 added = true;
1245                             }
1246                         }
1247
1248                         if(!added) {
1249                             launcherAppCache.add(list.get(0));
1250                         }
1251                     }
1252
1253                     AppEntry newEntry = new AppEntry(packageName, null, null, null, false);
1254
1255                     newEntry.setUserId(userManager.getSerialNumberForUser(handle));
1256                     newEntry.setLastTimeUsed(lastTimeUsed);
1257                     entries.add(newEntry);
1258
1259                     break;
1260                 }
1261             }
1262         }
1263     }
1264
1265     @SuppressWarnings("SuspiciousListRemoveInLoop")
1266     @VisibleForTesting
1267     void populateAppEntries(Context context,
1268                             PackageManager pm,
1269                             List<AppEntry> entries,
1270                             List<LauncherActivityInfo> launcherAppCache) {
1271         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1272
1273         int launcherAppCachePos = -1;
1274         for(int i = 0; i < entries.size(); i++) {
1275             if(entries.get(i).getComponentName() == null) {
1276                 launcherAppCachePos++;
1277                 LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos);
1278                 String packageName = entries.get(i).getPackageName();
1279                 long lastTimeUsed = entries.get(i).getLastTimeUsed();
1280
1281                 entries.remove(i);
1282
1283                 AppEntry newEntry = new AppEntry(
1284                         packageName,
1285                         appInfo.getComponentName().flattenToString(),
1286                         appInfo.getLabel().toString(),
1287                         IconCache.getInstance(context).getIcon(context, pm, appInfo),
1288                         false);
1289
1290                 newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
1291                 newEntry.setLastTimeUsed(lastTimeUsed);
1292                 entries.add(i, newEntry);
1293             }
1294         }
1295     }
1296
1297     private void updateRunningAppIndicators(List<AppEntry> pinnedApps, List<AppEntry> usageStatsList, List<AppEntry> entries) {
1298         if(taskbar.getChildCount() != entries.size())
1299             return;
1300
1301         List<String> pinnedPackageList = new ArrayList<>();
1302         List<String> runningPackageList = new ArrayList<>();
1303
1304         for(AppEntry entry : pinnedApps)
1305             pinnedPackageList.add(entry.getPackageName());
1306
1307         for(AppEntry entry : usageStatsList)
1308             runningPackageList.add(entry.getPackageName());
1309
1310         for(int i = 0; i < taskbar.getChildCount(); i++) {
1311             View convertView = taskbar.getChildAt(i);
1312             String packageName = entries.get(i).getPackageName();
1313
1314             ImageView runningAppIndicator = convertView.findViewById(R.id.running_app_indicator);
1315             if(pinnedPackageList.contains(packageName) && !runningPackageList.contains(packageName))
1316                 runningAppIndicator.setVisibility(View.GONE);
1317             else {
1318                 runningAppIndicator.setVisibility(View.VISIBLE);
1319                 runningAppIndicator.setColorFilter(U.getAccentColor(context));
1320             }
1321         }
1322     }
1323
1324     private void toggleTaskbar(boolean userInitiated) {
1325         if(userInitiated && Build.BRAND.equalsIgnoreCase("essential")) {
1326             SharedPreferences pref = U.getSharedPreferences(context);
1327             LauncherHelper helper = LauncherHelper.getInstance();
1328
1329             if(!pref.getBoolean(PREF_GRIP_REJECTION_TOAST_SHOWN, false)
1330                     && !helper.isOnSecondaryHomeScreen(context)) {
1331                 U.showToastLong(context, R.string.tb_essential_phone_grip_rejection);
1332                 pref.edit().putBoolean(PREF_GRIP_REJECTION_TOAST_SHOWN, true).apply();
1333             }
1334         }
1335
1336         if(startButton.getVisibility() == View.GONE)
1337             showTaskbar(true);
1338         else
1339             hideTaskbar(true);
1340     }
1341
1342     private void showTaskbar(boolean clearVariables) {
1343         if(clearVariables) {
1344             taskbarShownTemporarily = false;
1345             taskbarHiddenTemporarily = false;
1346         }
1347
1348         if(startButton.getVisibility() == View.GONE) {
1349             startButton.setVisibility(View.VISIBLE);
1350             space.setVisibility(View.VISIBLE);
1351
1352             if(dashboardEnabled)
1353                 dashboardButton.setVisibility(View.VISIBLE);
1354
1355             if(navbarButtonsEnabled)
1356                 navbarButtons.setVisibility(View.VISIBLE);
1357
1358             if(isShowingRecents && scrollView.getVisibility() == View.GONE)
1359                 scrollView.setVisibility(View.INVISIBLE);
1360
1361             if(sysTrayEnabled)
1362                 sysTrayParentLayout.setVisibility(View.VISIBLE);
1363
1364             shouldRefreshRecents = true;
1365             startRefreshingRecents();
1366
1367             SharedPreferences pref = U.getSharedPreferences(context);
1368             pref.edit().putBoolean(PREF_COLLAPSED, true).apply();
1369
1370             updateButton(false);
1371
1372             U.newHandler().post(() -> U.sendBroadcast(context, ACTION_SHOW_START_MENU_SPACE));
1373         }
1374     }
1375
1376     private void hideTaskbar(boolean clearVariables) {
1377         if(clearVariables) {
1378             taskbarShownTemporarily = false;
1379             taskbarHiddenTemporarily = false;
1380         }
1381
1382         if(startButton.getVisibility() == View.VISIBLE) {
1383             startButton.setVisibility(View.GONE);
1384             space.setVisibility(View.GONE);
1385
1386             if(dashboardEnabled)
1387                 dashboardButton.setVisibility(View.GONE);
1388
1389             if(navbarButtonsEnabled)
1390                 navbarButtons.setVisibility(View.GONE);
1391
1392             if(isShowingRecents)
1393                 scrollView.setVisibility(View.GONE);
1394
1395             if(sysTrayEnabled)
1396                 sysTrayParentLayout.setVisibility(View.GONE);
1397
1398             shouldRefreshRecents = false;
1399             if(thread != null) thread.interrupt();
1400
1401             SharedPreferences pref = U.getSharedPreferences(context);
1402             pref.edit().putBoolean(PREF_COLLAPSED, false).apply();
1403
1404             updateButton(true);
1405
1406             if(clearVariables) {
1407                 U.sendBroadcast(context, ACTION_HIDE_START_MENU);
1408                 U.sendBroadcast(context, ACTION_HIDE_DASHBOARD);
1409             }
1410
1411             if(matchParent) {
1412                 matchParent = false;
1413                 U.newHandler().post(updateParamsRunnable);
1414             }
1415
1416             U.newHandler().post(() -> U.sendBroadcast(context, ACTION_HIDE_START_MENU_SPACE));
1417         }
1418     }
1419
1420     private void tempShowTaskbar() {
1421         if(!taskbarHiddenTemporarily) {
1422             SharedPreferences pref = U.getSharedPreferences(context);
1423             if(!pref.getBoolean(PREF_COLLAPSED, false)) taskbarShownTemporarily = true;
1424         }
1425
1426         showTaskbar(false);
1427
1428         if(taskbarHiddenTemporarily)
1429             taskbarHiddenTemporarily = false;
1430     }
1431
1432     private void tempHideTaskbar(boolean monitorPositionChanges) {
1433         if(!taskbarShownTemporarily) {
1434             SharedPreferences pref = U.getSharedPreferences(context);
1435             if(pref.getBoolean(PREF_COLLAPSED, false)) taskbarHiddenTemporarily = true;
1436         }
1437
1438         hideTaskbar(false);
1439
1440         if(taskbarShownTemporarily)
1441             taskbarShownTemporarily = false;
1442
1443         if(monitorPositionChanges && showHideAutomagically && !positionIsVertical) {
1444             if(thread2 != null) thread2.interrupt();
1445
1446             handler2 = U.newHandler();
1447             thread2 = new Thread(() -> {
1448                 stopThread2 = false;
1449
1450                 while(!stopThread2) {
1451                     SystemClock.sleep(refreshInterval);
1452
1453                     handler2.post(() -> stopThread2 = checkPositionChange());
1454                 }
1455
1456                 startThread2 = false;
1457             });
1458
1459             thread2.start();
1460         }
1461     }
1462
1463     private boolean checkPositionChange() {
1464         if(!isScreenOff() && layout != null) {
1465             int[] location = new int[2];
1466             layout.getLocationOnScreen(location);
1467
1468             if(location[1] == 0) {
1469                 return true;
1470             } else {
1471                 if(location[1] > currentTaskbarPosition) {
1472                     currentTaskbarPosition = location[1];
1473                     if(taskbarHiddenTemporarily) {
1474                         tempShowTaskbar();
1475                         return true;
1476                     }
1477                 } else if(location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) {
1478                     tempShowTaskbar();
1479                     return true;
1480                 } else if(location[1] < currentTaskbarPosition
1481                         && currentTaskbarPosition - location[1] == getNavBarSize()) {
1482                     currentTaskbarPosition = location[1];
1483                 }
1484             }
1485         }
1486
1487         return false;
1488     }
1489
1490     private int getNavBarSize() {
1491         Point size = new Point();
1492         Point realSize = new Point();
1493
1494         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1495         Display display = wm.getDefaultDisplay();
1496         display.getSize(size);
1497         display.getRealSize(realSize);
1498
1499         return realSize.y - size.y;
1500     }
1501
1502     @Override
1503     public void onDestroyHost(UIHost host) {
1504         shouldRefreshRecents = false;
1505
1506         if(layout != null)
1507             try {
1508                 host.removeView(layout);
1509             } catch (IllegalArgumentException ignored) {}
1510
1511         SharedPreferences pref = U.getSharedPreferences(context);
1512         if(pref.getBoolean(PREF_SKIP_AUTO_HIDE_NAVBAR, false)) {
1513             pref.edit().remove(PREF_SKIP_AUTO_HIDE_NAVBAR).apply();
1514         } else if(pref.getBoolean(PREF_AUTO_HIDE_NAVBAR, false))
1515             U.showHideNavigationBar(context, true);
1516
1517         U.unregisterReceiver(context, showReceiver);
1518         U.unregisterReceiver(context, hideReceiver);
1519         U.unregisterReceiver(context, tempShowReceiver);
1520         U.unregisterReceiver(context, tempHideReceiver);
1521         U.unregisterReceiver(context, startMenuAppearReceiver);
1522         U.unregisterReceiver(context, startMenuDisappearReceiver);
1523
1524         if(sysTrayEnabled) {
1525             TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1526             manager.listen(listener, PhoneStateListener.LISTEN_NONE);
1527
1528             U.unregisterReceiver(context, notificationCountReceiver);
1529         }
1530
1531         isFirstStart = true;
1532     }
1533
1534     private void openContextMenu() {
1535         SharedPreferences pref = U.getSharedPreferences(context);
1536
1537         Bundle args = new Bundle();
1538         args.putBoolean("dont_show_quit",
1539                 LauncherHelper.getInstance().isOnHomeScreen(context)
1540                         && !pref.getBoolean(PREF_TASKBAR_ACTIVE, false));
1541         args.putBoolean("is_start_button", true);
1542
1543         U.startContextMenuActivity(context, args);
1544     }
1545
1546     private void updateButton(boolean isCollapsed) {
1547         SharedPreferences pref = U.getSharedPreferences(context);
1548         boolean hide = pref.getBoolean(PREF_INVISIBLE_BUTTON, false);
1549
1550         if(button != null) button.setText(context.getString(isCollapsed ? R.string.tb_right_arrow : R.string.tb_left_arrow));
1551         if(layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1);
1552     }
1553
1554     @TargetApi(Build.VERSION_CODES.M)
1555     @Override
1556     public void onRecreateHost(UIHost host) {
1557         if(layout != null) {
1558             try {
1559                 host.removeView(layout);
1560             } catch (IllegalArgumentException ignored) {}
1561
1562             currentTaskbarPosition = 0;
1563
1564             if(U.canDrawOverlays(context))
1565                 drawTaskbar(host);
1566             else {
1567                 SharedPreferences pref = U.getSharedPreferences(context);
1568                 pref.edit().putBoolean(PREF_TASKBAR_ACTIVE, false).apply();
1569
1570                 host.terminate();
1571             }
1572         }
1573     }
1574
1575     private View getView(List<AppEntry> list, int position) {
1576         View convertView = View.inflate(context, R.layout.tb_icon, null);
1577
1578         final AppEntry entry = list.get(position);
1579         final SharedPreferences pref = U.getSharedPreferences(context);
1580
1581         ImageView imageView = convertView.findViewById(R.id.icon);
1582         ImageView imageView2 = convertView.findViewById(R.id.shortcut_icon);
1583         imageView.setImageDrawable(entry.getIcon(context));
1584         imageView2.setBackgroundColor(U.getAccentColor(context));
1585
1586         String taskbarPosition = TaskbarPosition.getTaskbarPosition(context);
1587         if(pref.getBoolean(PREF_SHORTCUT_ICON, true)) {
1588             boolean shouldShowShortcutIcon;
1589             if(taskbarPosition.contains("vertical"))
1590                 shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps;
1591             else
1592                 shouldShowShortcutIcon = position < numOfPinnedApps;
1593
1594             if(shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE);
1595         }
1596
1597         if(POSITION_BOTTOM_RIGHT.equals(taskbarPosition) || POSITION_TOP_RIGHT.equals(taskbarPosition)) {
1598             imageView.setRotationY(180);
1599             imageView2.setRotationY(180);
1600         }
1601
1602         FrameLayout layout = convertView.findViewById(R.id.entry);
1603         layout.setOnClickListener(view -> U.launchApp(
1604                 context,
1605                 entry,
1606                 null,
1607                 true,
1608                 false,
1609                 view
1610         ));
1611
1612         layout.setOnLongClickListener(view -> {
1613             int[] location = new int[2];
1614             view.getLocationOnScreen(location);
1615             openContextMenu(entry, location);
1616             return true;
1617         });
1618
1619         layout.setOnGenericMotionListener((view, motionEvent) -> {
1620             int action = motionEvent.getAction();
1621
1622             if(action == MotionEvent.ACTION_BUTTON_PRESS
1623                     && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
1624                 int[] location = new int[2];
1625                 view.getLocationOnScreen(location);
1626                 openContextMenu(entry, location);
1627             }
1628
1629             if(action == MotionEvent.ACTION_SCROLL && pref.getBoolean(PREF_VISUAL_FEEDBACK, true))
1630                 view.setBackgroundColor(0);
1631
1632             return false;
1633         });
1634
1635         if(pref.getBoolean(PREF_VISUAL_FEEDBACK, true)) {
1636             layout.setOnHoverListener((v, event) -> {
1637                 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
1638                     int accentColor = U.getAccentColor(context);
1639                     accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2);
1640                     v.setBackgroundColor(accentColor);
1641                 }
1642
1643                 if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT)
1644                     v.setBackgroundColor(0);
1645
1646                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1647                     v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
1648
1649                 return false;
1650             });
1651
1652             layout.setOnTouchListener((v, event) -> {
1653                 v.setAlpha(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1);
1654                 return false;
1655             });
1656         }
1657
1658         return convertView;
1659     }
1660
1661     private void openContextMenu(AppEntry entry, int[] location) {
1662         Bundle args = new Bundle();
1663         args.putSerializable("app_entry", entry);
1664         args.putInt("x", location[0]);
1665         args.putInt("y", location[1]);
1666
1667         U.startContextMenuActivity(context, args);
1668     }
1669
1670     private List<AppEntry> getAppEntries() {
1671         SharedPreferences pref = U.getSharedPreferences(context);
1672         if(runningAppsOnly)
1673             return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString(PREF_MAX_NUM_OF_RECENTS, "10")));
1674         else
1675             return getAppEntriesUsingUsageStats();
1676     }
1677
1678     @SuppressWarnings({"deprecation", "JavaReflectionMemberAccess"})
1679     @TargetApi(Build.VERSION_CODES.M)
1680     private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) {
1681         ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1682         List<ActivityManager.RecentTaskInfo> usageStatsList = mActivityManager.getRecentTasks(maxNum, 0);
1683         List<AppEntry> entries = new ArrayList<>();
1684
1685         for(int i = 0; i < usageStatsList.size(); i++) {
1686             ActivityManager.RecentTaskInfo recentTaskInfo = usageStatsList.get(i);
1687             if(recentTaskInfo.id != -1) {
1688                 String packageName = recentTaskInfo.baseActivity.getPackageName();
1689                 AppEntry newEntry = new AppEntry(
1690                         packageName,
1691                         null,
1692                         null,
1693                         null,
1694                         false
1695                 );
1696
1697                 U.allowReflection();
1698                 try {
1699                     Field field = ActivityManager.RecentTaskInfo.class.getField("firstActiveTime");
1700                     newEntry.setLastTimeUsed(field.getLong(recentTaskInfo));
1701                 } catch (Exception e) {
1702                     newEntry.setLastTimeUsed(i);
1703                 }
1704
1705                 entries.add(newEntry);
1706             }
1707         }
1708
1709         return entries;
1710     }
1711
1712     @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
1713     private List<AppEntry> getAppEntriesUsingUsageStats() {
1714         UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
1715         List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, searchInterval, System.currentTimeMillis());
1716         List<AppEntry> entries = new ArrayList<>();
1717
1718         for(UsageStats usageStats : usageStatsList) {
1719             AppEntry newEntry = new AppEntry(
1720                     usageStats.getPackageName(),
1721                     null,
1722                     null,
1723                     null,
1724                     false
1725             );
1726
1727             newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground());
1728             newEntry.setLastTimeUsed(usageStats.getLastTimeUsed());
1729             entries.add(newEntry);
1730         }
1731
1732         return entries;
1733     }
1734
1735     private boolean hasLauncherIntent(String packageName) {
1736         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1737         intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1738         intentToResolve.setPackage(packageName);
1739
1740         List<ResolveInfo> ris = context.getPackageManager().queryIntentActivities(intentToResolve, 0);
1741         return ris != null && ris.size() > 0;
1742     }
1743
1744     private boolean isScreenOff() {
1745         if(U.isChromeOs(context))
1746             return false;
1747
1748         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1749         return !pm.isInteractive();
1750     }
1751
1752     @SuppressLint("SetTextI18n")
1753     private void updateSystemTray() {
1754         if(!sysTrayEnabled) return;
1755
1756         handler.post(() -> {
1757             Map<Integer, Drawable> drawables = new HashMap<>();
1758             drawables.put(R.id.battery, getBatteryDrawable());
1759             drawables.put(R.id.wifi, getWifiDrawable());
1760             drawables.put(R.id.bluetooth, getBluetoothDrawable());
1761             drawables.put(R.id.cellular, getCellularDrawable());
1762
1763             for(Integer key : drawables.keySet()) {
1764                 ImageView view = sysTrayLayout.findViewById(key);
1765                 Drawable drawable = drawables.get(key);
1766
1767                 if(drawable != null) view.setImageDrawable(drawable);
1768                 sysTrayIconStates.put(key, drawable != null);
1769             }
1770
1771             if(notificationCount > 0) {
1772                 int color = ColorUtils.setAlphaComponent(U.getBackgroundTint(context), 255);
1773                 notificationCountText.setTextColor(color);
1774
1775                 Drawable drawable = ContextCompat.getDrawable(context, R.drawable.tb_circle);
1776                 drawable.setTint(U.getAccentColor(context));
1777
1778                 notificationCountCircle.setImageDrawable(drawable);
1779                 notificationCountText.setText(Integer.toString(notificationCount));
1780                 sysTrayIconStates.put(R.id.notification_count, true);
1781             } else
1782                 sysTrayIconStates.put(R.id.notification_count, false);
1783
1784             time.setText(context.getString(R.string.tb_systray_clock,
1785                     DateFormat.getTimeFormat(context).format(new Date()),
1786                     DateFormat.getDateFormat(context).format(new Date())));
1787             time.setTextColor(U.getAccentColor(context));
1788         });
1789     }
1790
1791     @TargetApi(Build.VERSION_CODES.M)
1792     private Drawable getBatteryDrawable() {
1793         BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
1794         int batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
1795
1796         if(batLevel == Integer.MIN_VALUE)
1797             return null;
1798
1799         IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
1800         Intent batteryStatus = context.registerReceiver(null, ifilter);
1801
1802         int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
1803         boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
1804                 status == BatteryManager.BATTERY_STATUS_FULL;
1805
1806         String batDrawable;
1807         if(batLevel < 10 && !isCharging)
1808             batDrawable = "alert";
1809         else if(batLevel < 25)
1810             batDrawable = "20";
1811         else if(batLevel < 40)
1812             batDrawable = "30";
1813         else if(batLevel < 55)
1814             batDrawable = "50";
1815         else if(batLevel < 70)
1816             batDrawable = "60";
1817         else if(batLevel < 85)
1818             batDrawable = "80";
1819         else if(batLevel < 95)
1820             batDrawable = "90";
1821         else
1822             batDrawable = "full";
1823
1824         String charging;
1825         if(isCharging)
1826             charging = "charging_";
1827         else
1828             charging = "";
1829
1830         String batRes = "tb_battery_" + charging + batDrawable;
1831         int id = getResourceIdFor(batRes);
1832
1833         return getDrawableForSysTray(id);
1834     }
1835
1836     @TargetApi(Build.VERSION_CODES.M)
1837     private Drawable getWifiDrawable() {
1838         ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1839
1840         NetworkInfo ethernet = manager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
1841         if(ethernet != null && ethernet.isConnected())
1842             return getDrawableForSysTray(R.drawable.tb_settings_ethernet);
1843
1844         NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
1845         if(wifi == null || !wifi.isConnected())
1846             return null;
1847
1848         WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
1849         int numberOfLevels = 5;
1850
1851         WifiInfo wifiInfo = wifiManager.getConnectionInfo();
1852         int level = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), numberOfLevels);
1853
1854         String wifiRes = "tb_signal_wifi_" + level + "_bar";
1855         int id = getResourceIdFor(wifiRes);
1856
1857         return getDrawableForSysTray(id);
1858     }
1859
1860     private Drawable getBluetoothDrawable() {
1861         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1862         if(adapter != null && adapter.isEnabled())
1863             return getDrawableForSysTray(R.drawable.tb_bluetooth);
1864
1865         return null;
1866     }
1867
1868     @TargetApi(Build.VERSION_CODES.M)
1869     private Drawable getCellularDrawable() {
1870         if(Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0)
1871             return getDrawableForSysTray(R.drawable.tb_airplanemode_active);
1872
1873         if(cellStrength == -1)
1874             return null;
1875
1876         String cellRes = "tb_signal_cellular_" + cellStrength + "_bar";
1877         int id = getResourceIdFor(cellRes);
1878
1879         return getDrawableForSysTray(id);
1880     }
1881
1882     private Drawable getDrawableForSysTray(int id) {
1883         Drawable drawable = null;
1884         try {
1885             drawable = ContextCompat.getDrawable(context, id);
1886         } catch (Resources.NotFoundException ignored) {}
1887
1888         if(drawable == null) return null;
1889
1890         drawable.setTint(U.getAccentColor(context));
1891         return drawable;
1892     }
1893
1894     private int getResourceIdFor(String name) {
1895         String packageName = context.getResources().getResourcePackageName(R.drawable.tb_dummy);
1896         return context.getResources().getIdentifier(name, "drawable", packageName);
1897     }
1898 }