Java tutorial
/* Copyright 2016 Braden Farmer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.farmerbb.taskbar.service; import android.accessibilityservice.AccessibilityService; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.Service; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Typeface; import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.speech.RecognizerIntent; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.ColorUtils; import android.util.DisplayMetrics; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.PointerIcon; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import java.util.ArrayList; import java.util.Collections; import java.util.List; import android.support.v4.content.LocalBroadcastManager; import android.widget.LinearLayout; import android.widget.Space; import com.farmerbb.taskbar.BuildConfig; import com.farmerbb.taskbar.MainActivity; import com.farmerbb.taskbar.R; import com.farmerbb.taskbar.activity.ContextMenuActivity; import com.farmerbb.taskbar.activity.dark.ContextMenuActivityDark; import com.farmerbb.taskbar.activity.HomeActivity; import com.farmerbb.taskbar.activity.InvisibleActivityFreeform; import com.farmerbb.taskbar.util.AppEntry; import com.farmerbb.taskbar.util.ApplicationType; import com.farmerbb.taskbar.util.FreeformHackHelper; import com.farmerbb.taskbar.util.IconCache; import com.farmerbb.taskbar.util.LauncherHelper; import com.farmerbb.taskbar.util.PinnedBlockedApps; import com.farmerbb.taskbar.util.StartMenuHelper; import com.farmerbb.taskbar.util.U; public class TaskbarService extends Service { private WindowManager windowManager; private LinearLayout layout; private ImageView startButton; private LinearLayout taskbar; private FrameLayout scrollView; private Button button; private Space space; private FrameLayout dashboardButton; private LinearLayout navbarButtons; private Handler handler; private Handler handler2; private Thread thread; private Thread thread2; private boolean isShowingRecents = true; private boolean shouldRefreshRecents = true; private boolean taskbarShownTemporarily = false; private boolean taskbarHiddenTemporarily = false; private boolean isRefreshingRecents = false; private boolean isFirstStart = true; private boolean startThread2 = false; private boolean stopThread2 = false; private int refreshInterval = -1; private long searchInterval = -1; private String sortOrder = "false"; private boolean runningAppsOnly = false; private int layoutId = R.layout.taskbar_left; private int currentTaskbarPosition = 0; private boolean showHideAutomagically = false; private boolean positionIsVertical = false; private boolean dashboardEnabled = false; private boolean navbarButtonsEnabled = false; private List<String> currentTaskbarIds = new ArrayList<>(); private int numOfPinnedApps = -1; private View.OnClickListener ocl = view -> { Intent intent = new Intent("com.farmerbb.taskbar.TOGGLE_START_MENU"); LocalBroadcastManager.getInstance(TaskbarService.this).sendBroadcast(intent); }; private BroadcastReceiver showReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { showTaskbar(true); } }; private BroadcastReceiver hideReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { hideTaskbar(true); } }; private BroadcastReceiver tempShowReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { tempShowTaskbar(); } }; private BroadcastReceiver tempHideReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { tempHideTaskbar(false); } }; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } @TargetApi(Build.VERSION_CODES.M) @Override public void onCreate() { super.onCreate(); SharedPreferences pref = U.getSharedPreferences(this); if (pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this)) drawTaskbar(); else { pref.edit().putBoolean("taskbar_active", false).apply(); stopSelf(); } } else stopSelf(); } @SuppressLint("RtlHardcoded") private void drawTaskbar() { IconCache.getInstance(this).clearCache(); // Initialize layout params windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); U.setCachedRotation(windowManager.getDefaultDisplay().getRotation()); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT); // Determine where to show the taskbar on screen switch (U.getTaskbarPosition(this)) { case "bottom_left": layoutId = R.layout.taskbar_left; params.gravity = Gravity.BOTTOM | Gravity.LEFT; positionIsVertical = false; break; case "bottom_vertical_left": layoutId = R.layout.taskbar_vertical; params.gravity = Gravity.BOTTOM | Gravity.LEFT; positionIsVertical = true; break; case "bottom_right": layoutId = R.layout.taskbar_right; params.gravity = Gravity.BOTTOM | Gravity.RIGHT; positionIsVertical = false; break; case "bottom_vertical_right": layoutId = R.layout.taskbar_vertical; params.gravity = Gravity.BOTTOM | Gravity.RIGHT; positionIsVertical = true; break; case "top_left": layoutId = R.layout.taskbar_left; params.gravity = Gravity.TOP | Gravity.LEFT; positionIsVertical = false; break; case "top_vertical_left": layoutId = R.layout.taskbar_top_vertical; params.gravity = Gravity.TOP | Gravity.LEFT; positionIsVertical = true; break; case "top_right": layoutId = R.layout.taskbar_right; params.gravity = Gravity.TOP | Gravity.RIGHT; positionIsVertical = false; break; case "top_vertical_right": layoutId = R.layout.taskbar_top_vertical; params.gravity = Gravity.TOP | Gravity.RIGHT; positionIsVertical = true; break; } // Initialize views int theme = 0; SharedPreferences pref = U.getSharedPreferences(this); switch (pref.getString("theme", "light")) { case "light": theme = R.style.AppTheme; break; case "dark": theme = R.style.AppTheme_Dark; break; } boolean altButtonConfig = pref.getBoolean("alt_button_config", false); ContextThemeWrapper wrapper = new ContextThemeWrapper(this, theme); layout = (LinearLayout) LayoutInflater.from(wrapper).inflate(layoutId, null); taskbar = (LinearLayout) layout.findViewById(R.id.taskbar); scrollView = (FrameLayout) layout.findViewById(R.id.taskbar_scrollview); if (altButtonConfig) { space = (Space) layout.findViewById(R.id.space_alt); layout.findViewById(R.id.space).setVisibility(View.GONE); } else { space = (Space) layout.findViewById(R.id.space); layout.findViewById(R.id.space_alt).setVisibility(View.GONE); } space.setOnClickListener(v -> toggleTaskbar()); startButton = (ImageView) layout.findViewById(R.id.start_button); int padding; if (pref.getBoolean("app_drawer_icon", false)) { startButton.setImageDrawable(ContextCompat.getDrawable(this, R.mipmap.ic_launcher)); padding = getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt); } else { startButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.all_apps_button_icon)); padding = getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding); } startButton.setPadding(padding, padding, padding, padding); startButton.setOnClickListener(ocl); startButton.setOnLongClickListener(view -> { openContextMenu(); return true; }); startButton.setOnGenericMotionListener((view, motionEvent) -> { if (motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) openContextMenu(); return false; }); refreshInterval = (int) (Float.parseFloat(pref.getString("refresh_frequency", "2")) * 1000); if (refreshInterval == 0) refreshInterval = 100; sortOrder = pref.getString("sort_order", "false"); runningAppsOnly = pref.getString("recents_amount", "past_day").equals("running_apps_only"); switch (pref.getString("recents_amount", "past_day")) { case "past_day": searchInterval = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY; break; case "app_start": long oneDayAgo = System.currentTimeMillis() - AlarmManager.INTERVAL_DAY; long appStartTime = pref.getLong("time_of_service_start", System.currentTimeMillis()); long deviceStartTime = System.currentTimeMillis() - SystemClock.elapsedRealtime(); long startTime = deviceStartTime > appStartTime ? deviceStartTime : appStartTime; searchInterval = startTime > oneDayAgo ? startTime : oneDayAgo; break; } Intent intent = new Intent("com.farmerbb.taskbar.HIDE_START_MENU"); LocalBroadcastManager.getInstance(TaskbarService.this).sendBroadcast(intent); if (altButtonConfig) { button = (Button) layout.findViewById(R.id.hide_taskbar_button_alt); layout.findViewById(R.id.hide_taskbar_button).setVisibility(View.GONE); } else { button = (Button) layout.findViewById(R.id.hide_taskbar_button); layout.findViewById(R.id.hide_taskbar_button_alt).setVisibility(View.GONE); } try { button.setTypeface(Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")); } catch (RuntimeException e) { /* Gracefully fail */ } updateButton(false); button.setOnClickListener(v -> toggleTaskbar()); LinearLayout buttonLayout = (LinearLayout) layout.findViewById( altButtonConfig ? R.id.hide_taskbar_button_layout_alt : R.id.hide_taskbar_button_layout); if (buttonLayout != null) buttonLayout.setOnClickListener(v -> toggleTaskbar()); LinearLayout buttonLayoutToHide = (LinearLayout) layout.findViewById( altButtonConfig ? R.id.hide_taskbar_button_layout : R.id.hide_taskbar_button_layout_alt); if (buttonLayoutToHide != null) buttonLayoutToHide.setVisibility(View.GONE); int backgroundTint = U.getBackgroundTint(this); int accentColor = U.getAccentColor(this); dashboardButton = (FrameLayout) layout.findViewById(R.id.dashboard_button); navbarButtons = (LinearLayout) layout.findViewById(R.id.navbar_buttons); dashboardEnabled = pref.getBoolean("dashboard", false); if (dashboardEnabled) { layout.findViewById(R.id.square1).setBackgroundColor(accentColor); layout.findViewById(R.id.square2).setBackgroundColor(accentColor); layout.findViewById(R.id.square3).setBackgroundColor(accentColor); layout.findViewById(R.id.square4).setBackgroundColor(accentColor); layout.findViewById(R.id.square5).setBackgroundColor(accentColor); layout.findViewById(R.id.square6).setBackgroundColor(accentColor); dashboardButton.setOnClickListener(v -> LocalBroadcastManager.getInstance(TaskbarService.this) .sendBroadcast(new Intent("com.farmerbb.taskbar.TOGGLE_DASHBOARD"))); } else dashboardButton.setVisibility(View.GONE); if (pref.getBoolean("button_back", false)) { navbarButtonsEnabled = true; ImageView backButton = (ImageView) layout.findViewById(R.id.button_back); backButton.setVisibility(View.VISIBLE); backButton.setOnClickListener(v -> { U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_BACK); if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); }); } if (pref.getBoolean("button_home", false)) { navbarButtonsEnabled = true; ImageView homeButton = (ImageView) layout.findViewById(R.id.button_home); homeButton.setVisibility(View.VISIBLE); homeButton.setOnClickListener(v -> { U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_HOME); if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); }); homeButton.setOnLongClickListener(v -> { Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(voiceSearchIntent); } catch (ActivityNotFoundException e) { /* Gracefully fail */ } if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); return true; }); homeButton.setOnGenericMotionListener((view13, motionEvent) -> { if (motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) { Intent voiceSearchIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); voiceSearchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(voiceSearchIntent); } catch (ActivityNotFoundException e) { /* Gracefully fail */ } if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); } return true; }); } if (pref.getBoolean("button_recents", false)) { navbarButtonsEnabled = true; ImageView recentsButton = (ImageView) layout.findViewById(R.id.button_recents); recentsButton.setVisibility(View.VISIBLE); recentsButton.setOnClickListener(v -> { U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_RECENTS); if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); }); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { recentsButton.setOnLongClickListener(v -> { U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN); if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); return true; }); recentsButton.setOnGenericMotionListener((view13, motionEvent) -> { if (motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) { U.sendAccessibilityAction(this, AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN); if (pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace()) hideTaskbar(true); } return true; }); } } if (!navbarButtonsEnabled) navbarButtons.setVisibility(View.GONE); layout.setBackgroundColor(backgroundTint); layout.findViewById(R.id.divider).setBackgroundColor(accentColor); button.setTextColor(accentColor); if (isFirstStart && FreeformHackHelper.getInstance().isInFreeformWorkspace()) showTaskbar(false); else if (!pref.getBoolean("collapsed", false) && pref.getBoolean("taskbar_active", false)) toggleTaskbar(); LocalBroadcastManager.getInstance(this).unregisterReceiver(showReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(hideReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(tempShowReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(tempHideReceiver); LocalBroadcastManager.getInstance(this).registerReceiver(showReceiver, new IntentFilter("com.farmerbb.taskbar.SHOW_TASKBAR")); LocalBroadcastManager.getInstance(this).registerReceiver(hideReceiver, new IntentFilter("com.farmerbb.taskbar.HIDE_TASKBAR")); LocalBroadcastManager.getInstance(this).registerReceiver(tempShowReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR")); LocalBroadcastManager.getInstance(this).registerReceiver(tempHideReceiver, new IntentFilter("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR")); startRefreshingRecents(); windowManager.addView(layout, params); isFirstStart = false; } private void startRefreshingRecents() { if (thread != null) thread.interrupt(); stopThread2 = true; SharedPreferences pref = U.getSharedPreferences(this); showHideAutomagically = pref.getBoolean("hide_when_keyboard_shown", false); currentTaskbarIds.clear(); handler = new Handler(); thread = new Thread(() -> { updateRecentApps(true); if (!isRefreshingRecents) { isRefreshingRecents = true; while (shouldRefreshRecents) { SystemClock.sleep(refreshInterval); updateRecentApps(false); if (showHideAutomagically && !positionIsVertical && !StartMenuHelper.getInstance().isStartMenuOpen()) handler.post(() -> { if (layout != null) { int[] location = new int[2]; layout.getLocationOnScreen(location); if (location[1] != 0) { if (location[1] > currentTaskbarPosition) { currentTaskbarPosition = location[1]; } else if (location[1] < currentTaskbarPosition) { if (currentTaskbarPosition - location[1] == getNavBarSize()) currentTaskbarPosition = location[1]; else if (!startThread2) { startThread2 = true; tempHideTaskbar(true); } } } } }); } isRefreshingRecents = false; } }); thread.start(); } @SuppressWarnings("Convert2streamapi") @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1) private void updateRecentApps(final boolean firstRefresh) { SharedPreferences pref = U.getSharedPreferences(this); final PackageManager pm = getPackageManager(); final List<AppEntry> entries = new ArrayList<>(); List<LauncherActivityInfo> launcherAppCache = new ArrayList<>(); int maxNumOfEntries = U.getMaxNumOfEntries(this); int realNumOfPinnedApps = 0; boolean fullLength = pref.getBoolean("full_length", false); PinnedBlockedApps pba = PinnedBlockedApps.getInstance(this); List<AppEntry> pinnedApps = pba.getPinnedApps(); List<AppEntry> blockedApps = pba.getBlockedApps(); List<String> applicationIdsToRemove = new ArrayList<>(); // Filter out anything on the pinned/blocked apps lists if (pinnedApps.size() > 0) { UserManager userManager = (UserManager) getSystemService(USER_SERVICE); LauncherApps launcherApps = (LauncherApps) getSystemService(LAUNCHER_APPS_SERVICE); for (AppEntry entry : pinnedApps) { boolean packageEnabled = launcherApps.isPackageEnabled(entry.getPackageName(), userManager.getUserForSerialNumber(entry.getUserId(this))); if (packageEnabled) entries.add(entry); else realNumOfPinnedApps--; applicationIdsToRemove.add(entry.getPackageName()); } realNumOfPinnedApps = realNumOfPinnedApps + pinnedApps.size(); } if (blockedApps.size() > 0) { for (AppEntry entry : blockedApps) { applicationIdsToRemove.add(entry.getPackageName()); } } // Get list of all recently used apps List<AppEntry> usageStatsList = realNumOfPinnedApps < maxNumOfEntries ? getAppEntries() : new ArrayList<>(); if (usageStatsList.size() > 0 || realNumOfPinnedApps > 0 || fullLength) { if (realNumOfPinnedApps < maxNumOfEntries) { List<AppEntry> usageStatsList2 = new ArrayList<>(); List<AppEntry> usageStatsList3 = new ArrayList<>(); List<AppEntry> usageStatsList4 = new ArrayList<>(); List<AppEntry> usageStatsList5 = new ArrayList<>(); List<AppEntry> usageStatsList6; Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory(Intent.CATEGORY_HOME); ResolveInfo defaultLauncher = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY); // Filter out apps without a launcher intent // Also filter out the current launcher, and Taskbar itself for (AppEntry packageInfo : usageStatsList) { if (hasLauncherIntent(packageInfo.getPackageName()) && !packageInfo.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID) && !packageInfo.getPackageName().equals(defaultLauncher.activityInfo.packageName)) usageStatsList2.add(packageInfo); } // Filter out apps that don't fall within our current search interval for (AppEntry stats : usageStatsList2) { if (stats.getLastTimeUsed() > searchInterval || runningAppsOnly) usageStatsList3.add(stats); } // Sort apps by either most recently used, or most time used if (!runningAppsOnly) { if (sortOrder.contains("most_used")) { Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getTotalTimeInForeground(), us1.getTotalTimeInForeground())); } else { Collections.sort(usageStatsList3, (us1, us2) -> Long.compare(us2.getLastTimeUsed(), us1.getLastTimeUsed())); } } // Filter out any duplicate entries List<String> applicationIds = new ArrayList<>(); for (AppEntry stats : usageStatsList3) { if (!applicationIds.contains(stats.getPackageName())) { usageStatsList4.add(stats); applicationIds.add(stats.getPackageName()); } } // Filter out the currently running foreground app, if requested by the user if (pref.getBoolean("hide_foreground", false)) { UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService( USAGE_STATS_SERVICE); UsageEvents events = mUsageStatsManager.queryEvents(searchInterval, System.currentTimeMillis()); UsageEvents.Event eventCache = new UsageEvents.Event(); String currentForegroundApp = null; while (events.hasNextEvent()) { events.getNextEvent(eventCache); if (eventCache.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) { if (!(eventCache.getPackageName().contains(BuildConfig.BASE_APPLICATION_ID) && !eventCache.getClassName().equals(MainActivity.class.getCanonicalName()) && !eventCache.getClassName().equals(HomeActivity.class.getCanonicalName()) && !eventCache.getClassName() .equals(InvisibleActivityFreeform.class.getCanonicalName()))) currentForegroundApp = eventCache.getPackageName(); } } if (!applicationIdsToRemove.contains(currentForegroundApp)) applicationIdsToRemove.add(currentForegroundApp); } for (AppEntry stats : usageStatsList4) { if (!applicationIdsToRemove.contains(stats.getPackageName())) { usageStatsList5.add(stats); } } // Truncate list to a maximum length if (usageStatsList5.size() > maxNumOfEntries) usageStatsList6 = usageStatsList5.subList(0, maxNumOfEntries); else usageStatsList6 = usageStatsList5; // Determine if we need to reverse the order boolean needToReverseOrder; switch (U.getTaskbarPosition(this)) { case "bottom_right": case "top_right": needToReverseOrder = sortOrder.contains("false"); break; default: needToReverseOrder = sortOrder.contains("true"); break; } if (needToReverseOrder) { Collections.reverse(usageStatsList6); } // Generate the AppEntries for TaskbarAdapter int number = usageStatsList6.size() == maxNumOfEntries ? usageStatsList6.size() - realNumOfPinnedApps : usageStatsList6.size(); UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); LauncherApps launcherApps = (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE); final List<UserHandle> userHandles = userManager.getUserProfiles(); for (int i = 0; i < number; i++) { for (UserHandle handle : userHandles) { String packageName = usageStatsList6.get(i).getPackageName(); List<LauncherActivityInfo> list = launcherApps.getActivityList(packageName, handle); if (!list.isEmpty()) { // Google App workaround if (!packageName.equals("com.google.android.googlequicksearchbox")) launcherAppCache.add(list.get(0)); else { boolean added = false; for (LauncherActivityInfo info : list) { if (info.getName() .equals("com.google.android.googlequicksearchbox.SearchActivity")) { launcherAppCache.add(info); added = true; } } if (!added) launcherAppCache.add(list.get(0)); } AppEntry newEntry = new AppEntry(packageName, null, null, null, false); newEntry.setUserId(userManager.getSerialNumberForUser(handle)); entries.add(newEntry); break; } } } } while (entries.size() > maxNumOfEntries) { try { entries.remove(entries.size() - 1); launcherAppCache.remove(launcherAppCache.size() - 1); } catch (ArrayIndexOutOfBoundsException e) { /* Gracefully fail */ } } // Determine if we need to reverse the order again if (U.getTaskbarPosition(this).contains("vertical")) { Collections.reverse(entries); Collections.reverse(launcherAppCache); } // Now that we've generated the list of apps, // we need to determine if we need to redraw the Taskbar or not boolean shouldRedrawTaskbar = firstRefresh; List<String> finalApplicationIds = new ArrayList<>(); for (AppEntry entry : entries) { finalApplicationIds.add(entry.getPackageName()); } if (finalApplicationIds.size() != currentTaskbarIds.size() || numOfPinnedApps != realNumOfPinnedApps) shouldRedrawTaskbar = true; else { for (int i = 0; i < finalApplicationIds.size(); i++) { if (!finalApplicationIds.get(i).equals(currentTaskbarIds.get(i))) { shouldRedrawTaskbar = true; break; } } } if (shouldRedrawTaskbar) { currentTaskbarIds = finalApplicationIds; numOfPinnedApps = realNumOfPinnedApps; UserManager userManager = (UserManager) getSystemService(USER_SERVICE); int launcherAppCachePos = -1; for (int i = 0; i < entries.size(); i++) { if (entries.get(i).getComponentName() == null) { launcherAppCachePos++; LauncherActivityInfo appInfo = launcherAppCache.get(launcherAppCachePos); String packageName = entries.get(i).getPackageName(); entries.remove(i); AppEntry newEntry = new AppEntry(packageName, appInfo.getComponentName().flattenToString(), appInfo.getLabel().toString(), IconCache.getInstance(TaskbarService.this) .getIcon(TaskbarService.this, pm, appInfo), false); newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser())); entries.add(i, newEntry); } } final int numOfEntries = Math.min(entries.size(), maxNumOfEntries); handler.post(() -> { if (numOfEntries > 0 || fullLength) { ViewGroup.LayoutParams params = scrollView.getLayoutParams(); DisplayMetrics metrics = getResources().getDisplayMetrics(); int recentsSize = getResources().getDimensionPixelSize(R.dimen.icon_size) * numOfEntries; float maxRecentsSize = fullLength ? Float.MAX_VALUE : recentsSize; if (U.getTaskbarPosition(TaskbarService.this).contains("vertical")) { int maxScreenSize = metrics.heightPixels - U.getStatusBarHeight(TaskbarService.this) - U.getBaseTaskbarSize(TaskbarService.this); params.height = (int) Math.min(maxRecentsSize, maxScreenSize) + getResources().getDimensionPixelSize(R.dimen.divider_size); if (fullLength && U.getTaskbarPosition(this).contains("bottom")) { try { Space whitespace = (Space) layout.findViewById(R.id.whitespace); ViewGroup.LayoutParams params2 = whitespace.getLayoutParams(); params2.height = maxScreenSize - recentsSize; whitespace.setLayoutParams(params2); } catch (NullPointerException e) { /* Gracefully fail */ } } } else { int maxScreenSize = metrics.widthPixels - U.getBaseTaskbarSize(TaskbarService.this); params.width = (int) Math.min(maxRecentsSize, maxScreenSize) + getResources().getDimensionPixelSize(R.dimen.divider_size); if (fullLength && U.getTaskbarPosition(this).contains("right")) { try { Space whitespace = (Space) layout.findViewById(R.id.whitespace); ViewGroup.LayoutParams params2 = whitespace.getLayoutParams(); params2.width = maxScreenSize - recentsSize; whitespace.setLayoutParams(params2); } catch (NullPointerException e) { /* Gracefully fail */ } } } scrollView.setLayoutParams(params); taskbar.removeAllViews(); for (int i = 0; i < entries.size(); i++) { taskbar.addView(getView(entries, i)); } isShowingRecents = true; if (shouldRefreshRecents && scrollView.getVisibility() != View.VISIBLE) { if (firstRefresh) scrollView.setVisibility(View.INVISIBLE); else scrollView.setVisibility(View.VISIBLE); } if (firstRefresh && scrollView.getVisibility() != View.VISIBLE) new Handler().post(() -> { switch (U.getTaskbarPosition(TaskbarService.this)) { case "bottom_left": case "bottom_right": case "top_left": case "top_right": if (sortOrder.contains("false")) scrollView.scrollTo(0, 0); else if (sortOrder.contains("true")) scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight()); break; case "bottom_vertical_left": case "bottom_vertical_right": case "top_vertical_left": case "top_vertical_right": if (sortOrder.contains("false")) scrollView.scrollTo(taskbar.getWidth(), taskbar.getHeight()); else if (sortOrder.contains("true")) scrollView.scrollTo(0, 0); break; } if (shouldRefreshRecents) { scrollView.setVisibility(View.VISIBLE); } }); } else { isShowingRecents = false; scrollView.setVisibility(View.GONE); } }); } } else if (firstRefresh || currentTaskbarIds.size() > 0) { currentTaskbarIds.clear(); handler.post(() -> { isShowingRecents = false; scrollView.setVisibility(View.GONE); }); } } private void toggleTaskbar() { if (startButton.getVisibility() == View.GONE) showTaskbar(true); else hideTaskbar(true); } private void showTaskbar(boolean clearVariables) { if (clearVariables) { taskbarShownTemporarily = false; taskbarHiddenTemporarily = false; } if (startButton.getVisibility() == View.GONE) { startButton.setVisibility(View.VISIBLE); space.setVisibility(View.VISIBLE); if (dashboardEnabled) dashboardButton.setVisibility(View.VISIBLE); if (navbarButtonsEnabled) navbarButtons.setVisibility(View.VISIBLE); if (isShowingRecents && scrollView.getVisibility() == View.GONE) scrollView.setVisibility(View.INVISIBLE); shouldRefreshRecents = true; startRefreshingRecents(); SharedPreferences pref = U.getSharedPreferences(this); pref.edit().putBoolean("collapsed", true).apply(); updateButton(false); } } private void hideTaskbar(boolean clearVariables) { if (clearVariables) { taskbarShownTemporarily = false; taskbarHiddenTemporarily = false; } if (startButton.getVisibility() == View.VISIBLE) { startButton.setVisibility(View.GONE); space.setVisibility(View.GONE); if (dashboardEnabled) dashboardButton.setVisibility(View.GONE); if (navbarButtonsEnabled) navbarButtons.setVisibility(View.GONE); if (isShowingRecents) { scrollView.setVisibility(View.GONE); } shouldRefreshRecents = false; if (thread != null) thread.interrupt(); SharedPreferences pref = U.getSharedPreferences(this); pref.edit().putBoolean("collapsed", false).apply(); updateButton(true); LocalBroadcastManager.getInstance(TaskbarService.this) .sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU")); LocalBroadcastManager.getInstance(TaskbarService.this) .sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_DASHBOARD")); } } private void tempShowTaskbar() { if (!taskbarHiddenTemporarily) { SharedPreferences pref = U.getSharedPreferences(TaskbarService.this); if (!pref.getBoolean("collapsed", false)) taskbarShownTemporarily = true; } showTaskbar(false); if (taskbarHiddenTemporarily) taskbarHiddenTemporarily = false; } private void tempHideTaskbar(boolean monitorPositionChanges) { if (!taskbarShownTemporarily) { SharedPreferences pref = U.getSharedPreferences(TaskbarService.this); if (pref.getBoolean("collapsed", false)) taskbarHiddenTemporarily = true; } hideTaskbar(false); if (taskbarShownTemporarily) taskbarShownTemporarily = false; if (monitorPositionChanges && showHideAutomagically && !positionIsVertical) { if (thread2 != null) thread2.interrupt(); handler2 = new Handler(); thread2 = new Thread(() -> { stopThread2 = false; while (!stopThread2) { SystemClock.sleep(refreshInterval); handler2.post(() -> stopThread2 = checkPositionChange()); } startThread2 = false; }); thread2.start(); } } private boolean checkPositionChange() { if (layout != null) { int[] location = new int[2]; layout.getLocationOnScreen(location); if (location[1] == 0) { return true; } else { if (location[1] > currentTaskbarPosition) { currentTaskbarPosition = location[1]; if (taskbarHiddenTemporarily) { tempShowTaskbar(); return true; } } else if (location[1] == currentTaskbarPosition && taskbarHiddenTemporarily) { tempShowTaskbar(); return true; } else if (location[1] < currentTaskbarPosition && currentTaskbarPosition - location[1] == getNavBarSize()) { currentTaskbarPosition = location[1]; } } } return false; } private int getNavBarSize() { Point size = new Point(); Point realSize = new Point(); WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); display.getSize(size); display.getRealSize(realSize); return realSize.y - size.y; } @Override public void onDestroy() { shouldRefreshRecents = false; super.onDestroy(); if (layout != null) try { windowManager.removeView(layout); } catch (IllegalArgumentException e) { /* Gracefully fail */ } LocalBroadcastManager.getInstance(this).unregisterReceiver(showReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(hideReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(tempShowReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(tempHideReceiver); isFirstStart = true; } @SuppressWarnings("deprecation") private void openContextMenu() { SharedPreferences pref = U.getSharedPreferences(this); Intent intent = null; switch (pref.getString("theme", "light")) { case "light": intent = new Intent(this, ContextMenuActivity.class); break; case "dark": intent = new Intent(this, ContextMenuActivityDark.class); break; } if (intent != null) { intent.putExtra("dont_show_quit", LauncherHelper.getInstance().isOnHomeScreen() && !pref.getBoolean("taskbar_active", false)); intent.putExtra("is_start_button", true); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) { DisplayManager dm = (DisplayManager) getSystemService(DISPLAY_SERVICE); Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (intent != null && U.isOPreview()) intent.putExtra("context_menu_fix", true); startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU) .setLaunchBounds(new Rect(0, 0, display.getWidth(), display.getHeight())).toBundle()); } else startActivity(intent); } private void updateButton(boolean isCollapsed) { SharedPreferences pref = U.getSharedPreferences(this); boolean hide = pref.getBoolean("invisible_button", false); if (button != null) button.setText(getString(isCollapsed ? R.string.right_arrow : R.string.left_arrow)); if (layout != null) layout.setAlpha(isCollapsed && hide ? 0 : 1); } @TargetApi(Build.VERSION_CODES.M) @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (layout != null) { try { windowManager.removeView(layout); } catch (IllegalArgumentException e) { /* Gracefully fail */ } currentTaskbarPosition = 0; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this)) drawTaskbar(); else { SharedPreferences pref = U.getSharedPreferences(this); pref.edit().putBoolean("taskbar_active", false).apply(); stopSelf(); } } } private View getView(List<AppEntry> list, int position) { View convertView = View.inflate(this, R.layout.icon, null); final AppEntry entry = list.get(position); final SharedPreferences pref = U.getSharedPreferences(this); ImageView imageView = (ImageView) convertView.findViewById(R.id.icon); ImageView imageView2 = (ImageView) convertView.findViewById(R.id.shortcut_icon); imageView.setImageDrawable(entry.getIcon(this)); imageView2.setBackgroundColor( pref.getInt("accent_color", getResources().getInteger(R.integer.translucent_white))); String taskbarPosition = U.getTaskbarPosition(this); if (pref.getBoolean("shortcut_icon", true)) { boolean shouldShowShortcutIcon; if (taskbarPosition.contains("vertical")) shouldShowShortcutIcon = position >= list.size() - numOfPinnedApps; else shouldShowShortcutIcon = position < numOfPinnedApps; if (shouldShowShortcutIcon) imageView2.setVisibility(View.VISIBLE); } if (taskbarPosition.equals("bottom_right") || taskbarPosition.equals("top_right")) { imageView.setRotationY(180); imageView2.setRotationY(180); } FrameLayout layout = (FrameLayout) convertView.findViewById(R.id.entry); layout.setOnClickListener(view -> U.launchApp(TaskbarService.this, entry.getPackageName(), entry.getComponentName(), entry.getUserId(TaskbarService.this), null, true, false)); layout.setOnLongClickListener(view -> { int[] location = new int[2]; view.getLocationOnScreen(location); openContextMenu(entry, location); return true; }); layout.setOnGenericMotionListener((view, motionEvent) -> { int action = motionEvent.getAction(); if (action == MotionEvent.ACTION_BUTTON_PRESS && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) { int[] location = new int[2]; view.getLocationOnScreen(location); openContextMenu(entry, location); } if (action == MotionEvent.ACTION_SCROLL && pref.getBoolean("visual_feedback", true)) view.setBackgroundColor(0); return false; }); if (pref.getBoolean("visual_feedback", true)) { layout.setOnHoverListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { int accentColor = U.getAccentColor(TaskbarService.this); accentColor = ColorUtils.setAlphaComponent(accentColor, Color.alpha(accentColor) / 2); v.setBackgroundColor(accentColor); } if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) v.setBackgroundColor(0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) v.setPointerIcon(PointerIcon.getSystemIcon(TaskbarService.this, PointerIcon.TYPE_DEFAULT)); return false; }); layout.setOnTouchListener((v, event) -> { v.setAlpha( event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE ? 0.5f : 1); return false; }); } return convertView; } @SuppressWarnings("deprecation") private void openContextMenu(AppEntry entry, int[] location) { SharedPreferences pref = U.getSharedPreferences(this); Intent intent = null; switch (pref.getString("theme", "light")) { case "light": intent = new Intent(this, ContextMenuActivity.class); break; case "dark": intent = new Intent(this, ContextMenuActivityDark.class); break; } if (intent != null) { intent.putExtra("package_name", entry.getPackageName()); intent.putExtra("app_name", entry.getLabel()); intent.putExtra("component_name", entry.getComponentName()); intent.putExtra("user_id", entry.getUserId(this)); intent.putExtra("x", location[0]); intent.putExtra("y", location[1]); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) { DisplayManager dm = (DisplayManager) getSystemService(DISPLAY_SERVICE); Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); if (intent != null && U.isOPreview()) intent.putExtra("context_menu_fix", true); startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU) .setLaunchBounds(new Rect(0, 0, display.getWidth(), display.getHeight())).toBundle()); } else startActivity(intent); } private List<AppEntry> getAppEntries() { SharedPreferences pref = U.getSharedPreferences(this); if (runningAppsOnly) return getAppEntriesUsingActivityManager(Integer.parseInt(pref.getString("max_num_of_recents", "10"))); else return getAppEntriesUsingUsageStats(); } @SuppressWarnings("deprecation") private List<AppEntry> getAppEntriesUsingActivityManager(int maxNum) { ActivityManager mActivityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> usageStatsList = mActivityManager.getRunningTasks(maxNum); List<AppEntry> entries = new ArrayList<>(); for (ActivityManager.RunningTaskInfo usageStats : usageStatsList) { AppEntry newEntry = new AppEntry(usageStats.baseActivity.getPackageName(), null, null, null, false); entries.add(newEntry); } return entries; } @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1) private List<AppEntry> getAppEntriesUsingUsageStats() { UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(USAGE_STATS_SERVICE); List<UsageStats> usageStatsList = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, searchInterval, System.currentTimeMillis()); List<AppEntry> entries = new ArrayList<>(); for (UsageStats usageStats : usageStatsList) { AppEntry newEntry = new AppEntry(usageStats.getPackageName(), null, null, null, false); newEntry.setTotalTimeInForeground(usageStats.getTotalTimeInForeground()); newEntry.setLastTimeUsed(usageStats.getLastTimeUsed()); entries.add(newEntry); } return entries; } private boolean hasLauncherIntent(String packageName) { Intent intentToResolve = new Intent(Intent.ACTION_MAIN); intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); intentToResolve.setPackage(packageName); List<ResolveInfo> ris = getPackageManager().queryIntentActivities(intentToResolve, 0); return ris != null && ris.size() > 0; } }