1 /* Copyright 2016 Braden Farmer
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.farmerbb.taskbar.ui;
18 import android.annotation.SuppressLint;
19 import android.annotation.TargetApi;
20 import android.app.SearchManager;
21 import android.content.ActivityNotFoundException;
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.SharedPreferences;
27 import android.content.pm.LauncherActivityInfo;
28 import android.content.pm.LauncherApps;
29 import android.content.pm.PackageManager;
30 import android.content.res.Configuration;
31 import android.graphics.drawable.Drawable;
32 import android.net.Uri;
33 import android.os.Build;
34 import android.os.Bundle;
35 import android.os.Handler;
36 import android.os.UserHandle;
37 import android.os.UserManager;
39 import androidx.annotation.VisibleForTesting;
40 import androidx.appcompat.widget.SearchView;
41 import android.util.Patterns;
42 import android.view.Gravity;
43 import android.view.LayoutInflater;
44 import android.view.MotionEvent;
45 import android.view.View;
46 import android.view.ViewGroup;
47 import android.view.WindowManager;
48 import android.view.inputmethod.EditorInfo;
49 import android.view.inputmethod.InputMethodManager;
50 import android.webkit.URLUtil;
51 import android.widget.EditText;
52 import android.widget.FrameLayout;
53 import android.widget.GridView;
54 import android.widget.LinearLayout;
55 import android.widget.ListAdapter;
56 import android.widget.TextView;
58 import com.farmerbb.taskbar.R;
59 import com.farmerbb.taskbar.activity.InvisibleActivity;
60 import com.farmerbb.taskbar.activity.InvisibleActivityAlt;
61 import com.farmerbb.taskbar.adapter.StartMenuAdapter;
62 import com.farmerbb.taskbar.util.TaskbarPosition;
63 import com.farmerbb.taskbar.util.AppEntry;
64 import com.farmerbb.taskbar.util.Blacklist;
65 import com.farmerbb.taskbar.helper.FreeformHackHelper;
66 import com.farmerbb.taskbar.util.IconCache;
67 import com.farmerbb.taskbar.helper.LauncherHelper;
68 import com.farmerbb.taskbar.helper.MenuHelper;
69 import com.farmerbb.taskbar.util.TopApps;
70 import com.farmerbb.taskbar.util.U;
71 import com.farmerbb.taskbar.widget.StartMenuLayout;
73 import java.text.Collator;
74 import java.util.ArrayList;
75 import java.util.Collections;
76 import java.util.Comparator;
77 import java.util.List;
79 import static com.farmerbb.taskbar.util.Constants.*;
81 public class StartMenuController extends UIController {
83 private StartMenuLayout layout;
84 private GridView startMenu;
85 private SearchView searchView;
86 private TextView textView;
87 private PackageManager pm;
88 private StartMenuAdapter adapter;
90 private Handler handler;
91 private Thread thread;
93 private boolean hasSubmittedQuery = false;
94 private boolean hasHardwareKeyboard = false;
95 private boolean searchViewClicked = false;
97 private List<String> currentStartMenuIds = new ArrayList<>();
99 private final View.OnClickListener ocl = view -> toggleStartMenu();
101 private final BroadcastReceiver toggleReceiver = new BroadcastReceiver() {
103 public void onReceive(Context context, Intent intent) {
108 private final BroadcastReceiver showSpaceReceiver = new BroadcastReceiver() {
110 public void onReceive(Context context, Intent intent) {
111 layout.findViewById(R.id.start_menu_space).setVisibility(View.VISIBLE);
115 private final BroadcastReceiver hideSpaceReceiver = new BroadcastReceiver() {
117 public void onReceive(Context context, Intent intent) {
118 layout.findViewById(R.id.start_menu_space).setVisibility(View.GONE);
122 private final BroadcastReceiver hideReceiver = new BroadcastReceiver() {
124 public void onReceive(Context context, Intent intent) {
129 private final BroadcastReceiver hideReceiverNoReset = new BroadcastReceiver() {
131 public void onReceive(Context context, Intent intent) {
132 hideStartMenu(false);
136 private final BroadcastReceiver resetReceiver = new BroadcastReceiver() {
138 public void onReceive(Context context, Intent intent) {
139 startMenu.setSelection(0);
143 private final Comparator<LauncherActivityInfo> comparator = (ai1, ai2) -> {
148 label1 = ai1.getLabel().toString();
149 label2 = ai2.getLabel().toString();
150 } catch (OutOfMemoryError e) {
153 label1 = ai1.getApplicationInfo().packageName;
154 label2 = ai2.getApplicationInfo().packageName;
157 return Collator.getInstance().compare(label1, label2);
160 public StartMenuController(Context context) {
164 @TargetApi(Build.VERSION_CODES.M)
166 public void onCreateHost(UIHost host) {
167 hasHardwareKeyboard = context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
169 init(context, host, () -> drawStartMenu(host));
172 private void drawStartMenu(UIHost host) {
173 IconCache.getInstance(context).clearCache();
175 final SharedPreferences pref = U.getSharedPreferences(context);
176 boolean shouldShowSearchBox = shouldShowSearchBox(pref, hasHardwareKeyboard);
178 // Initialize layout params
179 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
180 TaskbarPosition.setCachedRotation(windowManager.getDefaultDisplay().getRotation());
182 final ViewParams params = new ViewParams(
183 WindowManager.LayoutParams.WRAP_CONTENT,
184 WindowManager.LayoutParams.WRAP_CONTENT,
186 shouldShowSearchBox ? 0 : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
187 getBottomMargin(context, host)
190 // Determine where to show the start menu on screen
191 String taskbarPosition = TaskbarPosition.getTaskbarPosition(context);
192 int layoutId = getStartMenuLayoutId(taskbarPosition);
193 params.gravity = getStartMenuGravity(taskbarPosition);
196 layout = (StartMenuLayout) LayoutInflater.from(U.wrapContext(context)).inflate(layoutId, null);
199 startMenu = layout.findViewById(R.id.start_menu);
201 if((shouldShowSearchBox && !hasHardwareKeyboard) || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1)
202 layout.viewHandlesBackButton();
204 boolean scrollbar = pref.getBoolean(PREF_SCROLLBAR, false);
205 startMenu.setFastScrollEnabled(scrollbar);
206 startMenu.setFastScrollAlwaysVisible(scrollbar);
207 startMenu.setScrollBarStyle(scrollbar ? View.SCROLLBARS_OUTSIDE_INSET : View.SCROLLBARS_INSIDE_OVERLAY);
209 if(pref.getBoolean(PREF_TRANSPARENT_START_MENU, false))
210 startMenu.setBackgroundColor(0);
212 if(pref.getBoolean(PREF_VISUAL_FEEDBACK, true))
213 startMenu.setRecyclerListener(view -> view.setBackgroundColor(0));
215 int columns = context.getResources().getInteger(R.integer.tb_start_menu_columns);
216 boolean isGrid = pref.getString(PREF_START_MENU_LAYOUT, "grid").equals("grid");
219 ViewGroup.LayoutParams startMenuParams = startMenu.getLayoutParams();
220 startMenuParams.width = (int) (startMenuParams.width * (columns / 3f));
221 startMenu.setLayoutParams(startMenuParams);
224 searchView = layout.findViewById(R.id.search);
225 searchViewClicked = false;
227 int backgroundTint = U.getBackgroundTint(context);
229 FrameLayout startMenuFrame = layout.findViewById(R.id.start_menu_frame);
230 FrameLayout searchViewLayout = layout.findViewById(R.id.search_view_layout);
231 startMenuFrame.setBackgroundColor(backgroundTint);
232 searchViewLayout.setBackgroundColor(backgroundTint);
234 if(shouldShowSearchBox) {
235 if(!hasHardwareKeyboard) searchView.setIconifiedByDefault(true);
237 searchView.setOnTouchListener((v, event) -> {
238 searchViewClicked = true;
242 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
244 public boolean onQueryTextSubmit(String query) {
245 if(!hasSubmittedQuery) {
246 ListAdapter adapter = startMenu.getAdapter();
247 if(adapter != null) {
248 hasSubmittedQuery = true;
250 if(adapter.getCount() > 0) {
251 View view = adapter.getView(0, null, startMenu);
252 LinearLayout layout = view.findViewById(R.id.entry);
253 layout.performClick();
255 if(U.shouldCollapse(context, true)) {
256 U.sendBroadcast(context, ACTION_HIDE_TASKBAR);
261 Intent intent = generateQueryWebSearchIntent(query);
262 if(intent.resolveActivity(context.getPackageManager()) != null) {
263 context.startActivity(intent);
265 intent = generateQueryGoogleIntent(query);
267 context.startActivity(intent);
268 } catch (ActivityNotFoundException ignored) {}
277 public boolean onQueryTextChange(String newText) {
278 searchView.setIconified(false);
280 View closeButton = searchView.findViewById(R.id.search_close_btn);
281 if(closeButton != null) closeButton.setVisibility(View.GONE);
283 refreshApps(newText, false);
285 if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
286 U.newHandler().postDelayed(() -> {
287 EditText editText = searchView.findViewById(R.id.search_src_text);
288 if(editText != null) {
289 editText.requestFocus();
290 editText.setSelection(editText.getText().length());
299 searchView.setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
301 LinearLayout powerButton = layout.findViewById(R.id.power_button);
302 powerButton.setOnClickListener(view -> {
303 int[] location = new int[2];
304 view.getLocationOnScreen(location);
305 openContextMenu(location);
308 powerButton.setOnGenericMotionListener((view, motionEvent) -> {
309 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
310 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
311 int[] location = new int[2];
312 view.getLocationOnScreen(location);
313 openContextMenu(location);
318 searchViewLayout.setOnClickListener(view -> searchView.setIconified(false));
320 startMenu.setOnItemClickListener((viewParent, view, position, id) -> {
323 AppEntry entry = (AppEntry) viewParent.getAdapter().getItem(position);
324 U.launchApp(context, entry, null, false, false, view);
327 View childLayout = layout.findViewById(R.id.search_view_child_layout);
328 if(pref.getBoolean(PREF_TRANSPARENT_START_MENU, false))
329 childLayout.setBackgroundColor(0);
332 ViewGroup.LayoutParams childLayoutParams = childLayout.getLayoutParams();
333 childLayoutParams.width = (int) (childLayoutParams.width * (columns / 3f));
334 childLayout.setLayoutParams(childLayoutParams);
337 searchViewLayout.setVisibility(View.GONE);
339 applyMarginFix(host, layout, params);
341 textView = layout.findViewById(R.id.no_apps_found);
343 U.registerReceiver(context, toggleReceiver, ACTION_TOGGLE_START_MENU);
344 U.registerReceiver(context, hideReceiver, ACTION_HIDE_START_MENU);
345 U.registerReceiver(context, hideReceiverNoReset, ACTION_HIDE_START_MENU_NO_RESET);
346 U.registerReceiver(context, showSpaceReceiver, ACTION_SHOW_START_MENU_SPACE);
347 U.registerReceiver(context, hideSpaceReceiver, ACTION_HIDE_START_MENU_SPACE);
348 U.registerReceiver(context, resetReceiver, ACTION_RESET_START_MENU);
350 handler = U.newHandler();
353 host.addView(layout, params);
357 boolean shouldShowSearchBox(SharedPreferences pref, boolean hasHardwareKeyboard) {
358 boolean shouldShowSearchBox;
359 switch(pref.getString(PREF_SHOW_SEARCH_BAR, "always")) {
361 shouldShowSearchBox = true;
364 shouldShowSearchBox = hasHardwareKeyboard;
367 shouldShowSearchBox = false;
370 return shouldShowSearchBox;
374 int getStartMenuLayoutId(String taskbarPosition) {
375 switch(taskbarPosition) {
376 case POSITION_BOTTOM_LEFT:
378 return R.layout.tb_start_menu_left;
379 case POSITION_BOTTOM_RIGHT:
380 return R.layout.tb_start_menu_right;
381 case POSITION_TOP_LEFT:
382 return R.layout.tb_start_menu_top_left;
383 case POSITION_TOP_VERTICAL_LEFT:
384 case POSITION_BOTTOM_VERTICAL_LEFT:
385 return R.layout.tb_start_menu_vertical_left;
386 case POSITION_TOP_RIGHT:
387 return R.layout.tb_start_menu_top_right;
388 case POSITION_TOP_VERTICAL_RIGHT:
389 case POSITION_BOTTOM_VERTICAL_RIGHT:
390 return R.layout.tb_start_menu_vertical_right;
395 @SuppressLint("RtlHardcoded")
396 int getStartMenuGravity(String taskbarPosition) {
397 switch(taskbarPosition) {
398 case POSITION_BOTTOM_LEFT:
399 case POSITION_BOTTOM_VERTICAL_LEFT:
401 return Gravity.BOTTOM | Gravity.LEFT;
402 case POSITION_BOTTOM_RIGHT:
403 case POSITION_BOTTOM_VERTICAL_RIGHT:
404 return Gravity.BOTTOM | Gravity.RIGHT;
405 case POSITION_TOP_LEFT:
406 case POSITION_TOP_VERTICAL_LEFT:
407 return Gravity.TOP | Gravity.LEFT;
408 case POSITION_TOP_RIGHT:
409 case POSITION_TOP_VERTICAL_RIGHT:
410 return Gravity.TOP | Gravity.RIGHT;
415 Intent generateQueryWebSearchIntent(String query) {
417 if(Patterns.WEB_URL.matcher(query).matches()) {
418 intent = new Intent(Intent.ACTION_VIEW);
419 intent.setData(Uri.parse(URLUtil.guessUrl(query)));
421 intent = new Intent(Intent.ACTION_WEB_SEARCH);
422 intent.putExtra(SearchManager.QUERY, query);
425 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
430 Intent generateQueryGoogleIntent(String query) {
432 Uri uri = new Uri.Builder()
434 .authority("www.google.com")
436 .appendQueryParameter("q", query)
439 intent = new Intent(Intent.ACTION_VIEW);
441 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
445 private void refreshApps(boolean firstDraw) {
446 refreshApps(null, firstDraw);
449 private void refreshApps(final String query, final boolean firstDraw) {
450 if(thread != null) thread.interrupt();
452 handler = U.newHandler();
453 thread = new Thread(() -> {
454 if(pm == null) pm = context.getPackageManager();
456 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
457 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
459 final List<UserHandle> userHandles = userManager.getUserProfiles();
460 final List<LauncherActivityInfo> unfilteredList = new ArrayList<>();
462 for(UserHandle handle : userHandles) {
463 unfilteredList.addAll(launcherApps.getActivityList(null, handle));
466 final List<LauncherActivityInfo> topAppsList = new ArrayList<>();
467 final List<LauncherActivityInfo> allAppsList = new ArrayList<>();
468 final List<LauncherActivityInfo> list = new ArrayList<>();
470 TopApps topApps = TopApps.getInstance(context);
471 for(LauncherActivityInfo appInfo : unfilteredList) {
472 String userSuffix = ":" + userManager.getSerialNumberForUser(appInfo.getUser());
473 if(topApps.isTopApp(appInfo.getComponentName().flattenToString() + userSuffix)
474 || topApps.isTopApp(appInfo.getComponentName().flattenToString())
475 || topApps.isTopApp(appInfo.getName()))
476 topAppsList.add(appInfo);
479 Blacklist blacklist = Blacklist.getInstance(context);
480 for(LauncherActivityInfo appInfo : unfilteredList) {
481 String userSuffix = ":" + userManager.getSerialNumberForUser(appInfo.getUser());
482 if(!(blacklist.isBlocked(appInfo.getComponentName().flattenToString() + userSuffix)
483 || blacklist.isBlocked(appInfo.getComponentName().flattenToString())
484 || blacklist.isBlocked(appInfo.getName()))
485 && !(topApps.isTopApp(appInfo.getComponentName().flattenToString() + userSuffix)
486 || topApps.isTopApp(appInfo.getComponentName().flattenToString())
487 || topApps.isTopApp(appInfo.getName())))
488 allAppsList.add(appInfo);
491 Collections.sort(topAppsList, comparator);
492 Collections.sort(allAppsList, comparator);
494 list.addAll(topAppsList);
495 list.addAll(allAppsList);
500 List<LauncherActivityInfo> queryList;
504 queryList = new ArrayList<>();
505 for(LauncherActivityInfo appInfo : list) {
506 if(appInfo.getLabel().toString().toLowerCase().contains(query.toLowerCase()))
507 queryList.add(appInfo);
511 // Now that we've generated the list of apps,
512 // we need to determine if we need to redraw the start menu or not
513 boolean shouldRedrawStartMenu = false;
514 List<String> finalApplicationIds = new ArrayList<>();
516 if(query == null && !firstDraw) {
517 for(LauncherActivityInfo appInfo : queryList) {
518 finalApplicationIds.add(appInfo.getApplicationInfo().packageName);
521 if(finalApplicationIds.size() != currentStartMenuIds.size())
522 shouldRedrawStartMenu = true;
524 for(int i = 0; i < finalApplicationIds.size(); i++) {
525 if(!finalApplicationIds.get(i).equals(currentStartMenuIds.get(i))) {
526 shouldRedrawStartMenu = true;
531 } else shouldRedrawStartMenu = true;
533 if(shouldRedrawStartMenu) {
534 if(query == null) currentStartMenuIds = finalApplicationIds;
536 final List<AppEntry> entries =
537 generateAppEntries(context, userManager, pm, queryList);
540 String queryText = searchView.getQuery().toString();
541 if(query == null && queryText.length() == 0
542 || query != null && query.equals(queryText)) {
545 SharedPreferences pref = U.getSharedPreferences(context);
546 if(pref.getString(PREF_START_MENU_LAYOUT, "grid").equals("grid")) {
547 startMenu.setNumColumns(context.getResources().getInteger(R.integer.tb_start_menu_columns));
548 adapter = new StartMenuAdapter(context, R.layout.tb_row_alt, entries);
550 adapter = new StartMenuAdapter(context, R.layout.tb_row, entries);
552 startMenu.setAdapter(adapter);
555 int position = startMenu.getFirstVisiblePosition();
557 if(!firstDraw && adapter != null)
558 adapter.updateList(entries);
560 startMenu.setSelection(position);
562 if(adapter != null && adapter.getCount() > 0)
563 textView.setText(null);
564 else if(query != null)
565 textView.setText(context.getString(Patterns.WEB_URL.matcher(query).matches() ? R.string.tb_press_enter_alt : R.string.tb_press_enter));
567 textView.setText(context.getString(R.string.tb_nothing_to_see_here));
577 List<AppEntry> generateAppEntries(Context context,
578 UserManager userManager,
580 List<LauncherActivityInfo> queryList) {
581 final List<AppEntry> entries = new ArrayList<>();
582 Drawable defaultIcon = pm.getDefaultActivityIcon();
583 for(LauncherActivityInfo appInfo : queryList) {
584 // Attempt to work around frequently reported OutOfMemoryErrors
589 label = appInfo.getLabel().toString();
590 icon = IconCache.getInstance(context).getIcon(context, pm, appInfo);
591 } catch (OutOfMemoryError e) {
594 label = appInfo.getApplicationInfo().packageName;
598 String packageName = appInfo.getApplicationInfo().packageName;
599 ComponentName componentName = new ComponentName(packageName, appInfo.getName());
601 new AppEntry(packageName, componentName.flattenToString(), label, icon, false);
603 newEntry.setUserId(userManager.getSerialNumberForUser(appInfo.getUser()));
604 entries.add(newEntry);
609 private void toggleStartMenu() {
610 if(layout.getVisibility() == View.GONE)
616 @TargetApi(Build.VERSION_CODES.N)
617 private void showStartMenu() {
618 if(layout.getVisibility() == View.GONE) {
619 layout.setOnClickListener(ocl);
620 layout.setVisibility(View.VISIBLE);
622 if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 && !hasHardwareKeyboard)
625 MenuHelper.getInstance().setStartMenuOpen(true);
627 U.sendBroadcast(context, ACTION_START_MENU_APPEARING);
629 boolean onHomeScreen = LauncherHelper.getInstance().isOnHomeScreen(context);
630 boolean inFreeformMode = FreeformHackHelper.getInstance().isInFreeformWorkspace();
632 if(!U.isChromeOs(context) && (!onHomeScreen || inFreeformMode)) {
633 Class<?> clazz = inFreeformMode && !U.hasBrokenSetLaunchBoundsApi()
634 ? InvisibleActivityAlt.class
635 : InvisibleActivity.class;
637 Intent intent = new Intent(context, clazz);
638 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
639 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
642 if(clazz.equals(InvisibleActivity.class))
643 U.startActivityLowerRight(context, intent);
644 else if(clazz.equals(InvisibleActivityAlt.class))
645 U.startActivityMaximized(context, intent);
647 context.startActivity(intent);
650 EditText editText = searchView.findViewById(R.id.search_src_text);
651 if(searchView.getVisibility() == View.VISIBLE) {
652 if(hasHardwareKeyboard) {
653 searchView.setIconifiedByDefault(true);
656 editText.setShowSoftInputOnFocus(false);
658 searchView.requestFocus();
663 U.newHandler().postDelayed(() -> {
664 if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1 || hasHardwareKeyboard)
667 if(hasHardwareKeyboard) {
668 searchView.setIconifiedByDefault(false);
670 editText.setShowSoftInputOnFocus(true);
672 searchView.requestFocus();
675 searchView.setOnQueryTextFocusChangeListener((view, b) -> {
676 if(!hasHardwareKeyboard) {
677 ViewGroup.LayoutParams params1 = startMenu.getLayoutParams();
678 params1.height = context.getResources().getDimensionPixelSize(
679 b && isImeFixDisabled()
680 ? R.dimen.tb_start_menu_height_half
681 : R.dimen.tb_start_menu_height);
682 startMenu.setLayoutParams(params1);
685 if(!b && !(U.isBlissOs(context) && Build.VERSION.SDK_INT == Build.VERSION_CODES.P)) {
686 if(hasHardwareKeyboard && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
689 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
690 imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
695 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
696 imm.hideSoftInputFromWindow(layout.getWindowToken(), 0);
701 private void hideStartMenu(boolean shouldReset) {
702 if(layout.getVisibility() == View.VISIBLE) {
703 layout.setOnClickListener(null);
706 MenuHelper.getInstance().setStartMenuOpen(false);
708 U.sendBroadcast(context, ACTION_START_MENU_DISAPPEARING);
710 layout.postDelayed(() -> {
711 layout.setVisibility(View.GONE);
713 if(searchViewClicked || hasHardwareKeyboard) {
714 if(!hasHardwareKeyboard)
715 searchView.setQuery(null, false);
717 searchView.setIconified(true);
720 searchView.setOnQueryTextFocusChangeListener(null);
721 hasSubmittedQuery = false;
724 startMenu.smoothScrollBy(0, 0);
725 startMenu.setSelection(0);
728 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
729 imm.hideSoftInputFromWindow(layout.getWindowToken(), 0);
735 public void onDestroyHost(UIHost host) {
738 host.removeView(layout);
739 } catch (IllegalArgumentException ignored) {}
741 U.unregisterReceiver(context, toggleReceiver);
742 U.unregisterReceiver(context, hideReceiver);
743 U.unregisterReceiver(context, hideReceiverNoReset);
744 U.unregisterReceiver(context, showSpaceReceiver);
745 U.unregisterReceiver(context, hideSpaceReceiver);
746 U.unregisterReceiver(context, resetReceiver);
748 U.sendBroadcast(context, ACTION_START_MENU_DISAPPEARING);
751 @TargetApi(Build.VERSION_CODES.M)
753 public void onRecreateHost(UIHost host) {
756 host.removeView(layout);
757 } catch (IllegalArgumentException ignored) {}
759 if(U.canDrawOverlays(context))
762 SharedPreferences pref = U.getSharedPreferences(context);
763 pref.edit().putBoolean(PREF_TASKBAR_ACTIVE, false).apply();
770 private void openContextMenu(final int[] location) {
771 hideStartMenu(false);
773 Bundle args = new Bundle();
774 args.putBoolean("launched_from_start_menu", true);
775 args.putBoolean("is_overflow_menu", true);
776 args.putInt("x", location[0]);
777 args.putInt("y", location[1]);
779 U.newHandler().postDelayed(() -> U.startContextMenuActivity(context, args), shouldDelay() ? 100 : 0);
782 private boolean shouldDelay() {
783 return U.hasFreeformSupport(context)
784 && U.isFreeformModeEnabled(context)
785 && !FreeformHackHelper.getInstance().isFreeformHackActive();