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.activity;
18 import android.annotation.SuppressLint;
19 import android.annotation.TargetApi;
20 import android.app.AlertDialog;
21 import android.app.WallpaperManager;
22 import android.content.ActivityNotFoundException;
23 import android.content.BroadcastReceiver;
24 import android.content.ClipData;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.SharedPreferences;
29 import android.os.Build;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.support.design.widget.FloatingActionButton;
33 import android.support.v4.content.ContextCompat;
34 import android.support.v4.content.LocalBroadcastManager;
35 import android.support.v7.app.AppCompatActivity;
36 import android.util.SparseArray;
37 import android.view.DragEvent;
38 import android.view.Gravity;
39 import android.view.LayoutInflater;
40 import android.view.MotionEvent;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.view.ViewTreeObserver;
44 import android.view.WindowManager;
45 import android.widget.FrameLayout;
46 import android.widget.GridLayout;
47 import android.widget.ImageView;
48 import android.widget.TextView;
50 import com.farmerbb.taskbar.R;
51 import com.farmerbb.taskbar.service.DashboardService;
52 import com.farmerbb.taskbar.service.NotificationService;
53 import com.farmerbb.taskbar.service.StartMenuService;
54 import com.farmerbb.taskbar.service.TaskbarService;
55 import com.farmerbb.taskbar.ui.DashboardController;
56 import com.farmerbb.taskbar.ui.UIHost;
57 import com.farmerbb.taskbar.ui.ViewParams;
58 import com.farmerbb.taskbar.ui.StartMenuController;
59 import com.farmerbb.taskbar.ui.TaskbarController;
60 import com.farmerbb.taskbar.util.AppEntry;
61 import com.farmerbb.taskbar.util.CompatUtils;
62 import com.farmerbb.taskbar.util.DesktopIconInfo;
63 import com.farmerbb.taskbar.util.DisplayInfo;
64 import com.farmerbb.taskbar.util.FeatureFlags;
65 import com.farmerbb.taskbar.util.FreeformHackHelper;
66 import com.farmerbb.taskbar.util.IconCache;
67 import com.farmerbb.taskbar.util.LauncherHelper;
68 import com.farmerbb.taskbar.util.MenuHelper;
69 import com.farmerbb.taskbar.util.U;
71 import org.json.JSONArray;
72 import org.json.JSONException;
74 import java.text.Collator;
75 import java.util.ArrayList;
76 import java.util.Collections;
77 import java.util.List;
79 public class HomeActivityDelegate extends AppCompatActivity implements UIHost {
80 private TaskbarController taskbarController;
81 private StartMenuController startMenuController;
82 private DashboardController dashboardController;
84 private FrameLayout layout;
85 private GridLayout desktopIcons;
86 private FloatingActionButton fab;
88 private boolean forceTaskbarStart = false;
89 private AlertDialog dialog;
91 private boolean shouldDelayFreeformHack;
94 private boolean iconArrangeMode = false;
95 private int startDragIndex;
96 private int endDragIndex;
98 private BroadcastReceiver killReceiver = new BroadcastReceiver() {
100 public void onReceive(Context context, Intent intent) {
105 private BroadcastReceiver forceTaskbarStartReceiver = new BroadcastReceiver() {
107 public void onReceive(Context context, Intent intent) {
108 forceTaskbarStart = true;
112 private BroadcastReceiver restartReceiver = new BroadcastReceiver() {
114 public void onReceive(Context context, Intent intent) {
115 if(taskbarController != null) taskbarController.onRecreateHost(HomeActivityDelegate.this);
116 if(startMenuController != null) startMenuController.onRecreateHost(HomeActivityDelegate.this);
117 if(dashboardController != null) dashboardController.onRecreateHost(HomeActivityDelegate.this);
121 private BroadcastReceiver freeformToggleReceiver = new BroadcastReceiver() {
123 public void onReceive(Context context, Intent intent) {
128 private BroadcastReceiver refreshDesktopIconsReceiver = new BroadcastReceiver() {
130 public void onReceive(Context context, Intent intent) {
131 refreshDesktopIcons();
135 private BroadcastReceiver iconArrangeModeReceiver = new BroadcastReceiver() {
137 public void onReceive(Context context, Intent intent) {
138 enterIconArrangeMode();
142 private BroadcastReceiver sortDesktopIconsReceiver = new BroadcastReceiver() {
144 public void onReceive(Context context, Intent intent) {
149 private BroadcastReceiver updateMarginsReceiver = new BroadcastReceiver() {
151 public void onReceive(Context context, Intent intent) {
156 @SuppressLint("RestrictedApi")
158 protected void onCreate(Bundle savedInstanceState) {
159 super.onCreate(savedInstanceState);
161 shouldDelayFreeformHack = true;
164 WindowManager.LayoutParams params = getWindow().getAttributes();
165 if(CompatUtils.applyDisplayCutoutModeTo(params))
166 getWindow().setAttributes(params);
168 SharedPreferences pref = U.getSharedPreferences(this);
170 layout = new FrameLayout(this) {
172 protected void onAttachedToWindow() {
173 super.onAttachedToWindow();
175 WallpaperManager wallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
176 wallpaperManager.setWallpaperOffsets(getWindowToken(), 0.5f, 0.5f);
178 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
179 DisplayInfo display = U.getDisplayInfo(HomeActivityDelegate.this);
180 wallpaperManager.suggestDesiredDimensions(display.width, display.height);
183 boolean shouldStartFreeformHack = shouldDelayFreeformHack && hits > 0;
184 shouldDelayFreeformHack = false;
186 if(shouldStartFreeformHack)
191 if(FeatureFlags.desktopIcons(HomeActivityDelegate.this)) {
192 layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
194 public void onGlobalLayout() {
195 layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
197 if(savedInstanceState != null)
198 iconArrangeMode = savedInstanceState.getBoolean("icon_arrange_mode");
205 if(!FeatureFlags.desktopIcons(this)) {
206 layout.setOnClickListener(view1 -> LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU")));
208 layout.setOnLongClickListener(view2 -> {
209 if(!pref.getBoolean("freeform_hack", false))
215 layout.setOnGenericMotionListener((view3, motionEvent) -> {
216 if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
217 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY
218 && !pref.getBoolean("freeform_hack", false))
225 layout.setFitsSystemWindows(true);
227 if((this instanceof HomeActivity || U.isLauncherPermanentlyEnabled(this))
228 && !U.isChromeOs(this)) {
229 setContentView(layout);
230 pref.edit().putBoolean("launcher", true).apply();
236 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
237 lbm.registerReceiver(killReceiver, new IntentFilter("com.farmerbb.taskbar.KILL_HOME_ACTIVITY"));
238 lbm.registerReceiver(forceTaskbarStartReceiver, new IntentFilter("com.farmerbb.taskbar.FORCE_TASKBAR_RESTART"));
240 IntentFilter intentFilter = new IntentFilter();
241 intentFilter.addAction("com.farmerbb.taskbar.UPDATE_FREEFORM_CHECKBOX");
242 intentFilter.addAction("com.farmerbb.taskbar.TOUCH_ABSORBER_STATE_CHANGED");
244 lbm.registerReceiver(freeformToggleReceiver, intentFilter);
246 if(FeatureFlags.homeActivityUIHost())
247 lbm.registerReceiver(restartReceiver, new IntentFilter("com.farmerbb.taskbar.RESTART"));
249 if(FeatureFlags.desktopIcons(this)) {
250 lbm.registerReceiver(refreshDesktopIconsReceiver, new IntentFilter("com.farmerbb.taskbar.REFRESH_DESKTOP_ICONS"));
251 lbm.registerReceiver(iconArrangeModeReceiver, new IntentFilter("com.farmerbb.taskbar.ENTER_ICON_ARRANGE_MODE"));
252 lbm.registerReceiver(sortDesktopIconsReceiver, new IntentFilter("com.farmerbb.taskbar.SORT_DESKTOP_ICONS"));
253 lbm.registerReceiver(updateMarginsReceiver, new IntentFilter("com.farmerbb.taskbar.UPDATE_HOME_SCREEN_MARGINS"));
259 private void setWallpaper() {
260 if(U.shouldCollapse(this, true))
261 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
263 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
266 startActivity(Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), getString(R.string.set_wallpaper)));
267 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
270 @TargetApi(Build.VERSION_CODES.N)
272 protected void onResume() {
275 if(U.canBootToFreeform(this)) {
276 if(U.launcherIsDefault(this))
279 U.showToastLong(this, R.string.set_as_default_home);
281 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
282 homeIntent.addCategory(Intent.CATEGORY_HOME);
283 homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
286 startActivity(homeIntent);
288 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
291 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR"));
296 protected void onStart() {
299 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
301 if(U.canDrawOverlays(this, true)) {
302 if(!U.canBootToFreeform(this)) {
303 final LauncherHelper helper = LauncherHelper.getInstance();
304 helper.setOnHomeScreen(true);
306 if(forceTaskbarStart) {
307 forceTaskbarStart = false;
308 new Handler().postDelayed(() -> {
309 helper.setOnHomeScreen(true);
314 } else if(U.launcherIsDefault(this))
317 dialog = U.showPermissionDialog(U.wrapContext(this),
318 () -> dialog = U.showErrorDialog(U.wrapContext(this), "SYSTEM_ALERT_WINDOW"),
322 private void startTaskbar() {
323 SharedPreferences pref = U.getSharedPreferences(this);
324 if(pref.getBoolean("first_run", true)) {
325 SharedPreferences.Editor editor = pref.edit();
326 editor.putBoolean("first_run", false);
327 editor.putBoolean("collapsed", true);
330 dialog = U.showRecentAppsDialog(U.wrapContext(this),
331 () -> dialog = U.showErrorDialog(U.wrapContext(this), "GET_USAGE_STATS"),
335 if(FeatureFlags.homeActivityUIHost()) {
336 // Stop any currently running services and switch to using HomeActivityDelegate as UI host
337 stopService(new Intent(this, TaskbarService.class));
338 stopService(new Intent(this, StartMenuService.class));
339 stopService(new Intent(this, DashboardService.class));
341 taskbarController = new TaskbarController(this);
342 startMenuController = new StartMenuController(this);
343 dashboardController = new DashboardController(this);
345 taskbarController.onCreateHost(this);
346 startMenuController.onCreateHost(this);
347 dashboardController.onCreateHost(this);
349 // We always start the Taskbar and Start Menu services, even if the app isn't normally running
350 startService(new Intent(this, TaskbarService.class));
351 startService(new Intent(this, StartMenuService.class));
352 startService(new Intent(this, DashboardService.class));
355 if(pref.getBoolean("taskbar_active", false) && !U.isServiceRunning(this, NotificationService.class))
356 pref.edit().putBoolean("taskbar_active", false).apply();
358 // Show the Taskbar temporarily, as nothing else will be visible on screen
359 new Handler().postDelayed(() -> LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.TEMP_SHOW_TASKBAR")), 100);
362 private void startFreeformHack() {
363 if(shouldDelayFreeformHack)
366 U.startFreeformHack(this);
370 protected void onStop() {
373 SharedPreferences pref = U.getSharedPreferences(this);
374 if(!U.canBootToFreeform(this)) {
375 LauncherHelper.getInstance().setOnHomeScreen(false);
377 if(U.shouldCollapse(this, true))
378 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.TEMP_HIDE_TASKBAR"));
380 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
382 if(FeatureFlags.homeActivityUIHost()) {
383 if(taskbarController != null) taskbarController.onDestroyHost(this);
384 if(startMenuController != null) startMenuController.onDestroyHost(this);
385 if(dashboardController != null) dashboardController.onDestroyHost(this);
387 IconCache.getInstance(this).clearCache();
389 // Stop using HomeActivityDelegate as UI host and restart services if needed
390 if(pref.getBoolean("taskbar_active", false) && !pref.getBoolean("is_hidden", false)) {
391 startService(new Intent(this, TaskbarService.class));
392 startService(new Intent(this, StartMenuService.class));
393 startService(new Intent(this, DashboardService.class));
396 // Stop the Taskbar and Start Menu services if they should normally not be active
397 if(!pref.getBoolean("taskbar_active", false) || pref.getBoolean("is_hidden", false)) {
398 stopService(new Intent(this, TaskbarService.class));
399 stopService(new Intent(this, StartMenuService.class));
400 stopService(new Intent(this, DashboardService.class));
402 IconCache.getInstance(this).clearCache();
414 protected void onDestroy() {
417 LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
418 lbm.unregisterReceiver(killReceiver);
419 lbm.unregisterReceiver(forceTaskbarStartReceiver);
420 lbm.unregisterReceiver(freeformToggleReceiver);
422 if(FeatureFlags.homeActivityUIHost())
423 lbm.unregisterReceiver(restartReceiver);
425 if(FeatureFlags.desktopIcons(this)) {
426 lbm.unregisterReceiver(refreshDesktopIconsReceiver);
427 lbm.unregisterReceiver(iconArrangeModeReceiver);
428 lbm.unregisterReceiver(sortDesktopIconsReceiver);
429 lbm.unregisterReceiver(updateMarginsReceiver);
434 protected void onSaveInstanceState(Bundle outState) {
435 outState.putBoolean("icon_arrange_mode", iconArrangeMode);
436 super.onSaveInstanceState(outState);
440 public void onBackPressed() {
441 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
444 private void killHomeActivity() {
445 LauncherHelper.getInstance().setOnHomeScreen(false);
447 if(FeatureFlags.homeActivityUIHost()) {
448 if(taskbarController != null) taskbarController.onDestroyHost(this);
449 if(startMenuController != null) startMenuController.onDestroyHost(this);
450 if(dashboardController != null) dashboardController.onDestroyHost(this);
452 IconCache.getInstance(this).clearCache();
454 U.stopFreeformHack(this);
456 // Stop using HomeActivityDelegate as UI host and restart services if needed
457 SharedPreferences pref = U.getSharedPreferences(this);
458 if(pref.getBoolean("taskbar_active", false) && !pref.getBoolean("is_hidden", false)) {
459 startService(new Intent(this, TaskbarService.class));
460 startService(new Intent(this, StartMenuService.class));
461 startService(new Intent(this, DashboardService.class));
464 // Stop the Taskbar and Start Menu services if they should normally not be active
465 SharedPreferences pref = U.getSharedPreferences(this);
466 if(!pref.getBoolean("taskbar_active", false) || pref.getBoolean("is_hidden", false)) {
467 stopService(new Intent(this, TaskbarService.class));
468 stopService(new Intent(this, StartMenuService.class));
469 stopService(new Intent(this, DashboardService.class));
471 IconCache.getInstance(this).clearCache();
473 U.stopFreeformHack(this);
480 private void updateWindowFlags() {
481 int flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
482 if(FreeformHackHelper.getInstance().isTouchAbsorberActive() && U.isOverridingFreeformHack(this))
483 getWindow().setFlags(flags, flags);
485 getWindow().clearFlags(flags);
489 public void addView(View view, ViewParams params) {
490 final FrameLayout.LayoutParams flParams = new FrameLayout.LayoutParams(
495 if(params.gravity > -1)
496 flParams.gravity = params.gravity;
498 view.setLayoutParams(flParams);
499 layout.addView(view);
503 public void removeView(View view) {
504 layout.removeView(view);
508 public void terminate() {
512 private void initDesktopIcons() {
513 desktopIcons = new GridLayout(this);
514 fab = new FloatingActionButton(this);
517 refreshDesktopIcons();
519 fab.setImageResource(R.drawable.ic_done_black_24dp);
520 fab.setOnClickListener(v -> {
521 iconArrangeMode = false;
523 refreshDesktopIcons();
526 if(!iconArrangeMode) fab.hide();
528 layout.addView(desktopIcons, 0);
529 layout.addView(fab, 1);
532 private void refreshDesktopIcons() {
533 boolean taskbarIsVertical = U.getTaskbarPosition(this).contains("vertical");
534 int iconSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
535 int desktopIconSize = getResources().getDimensionPixelSize(R.dimen.start_menu_grid_width);
537 int columns = (layout.getWidth() - (taskbarIsVertical ? iconSize : 0)) / desktopIconSize;
538 int rows = (layout.getHeight() - (!taskbarIsVertical ? iconSize : 0)) / desktopIconSize;
540 desktopIcons.removeAllViews();
541 desktopIcons.setOrientation(GridLayout.VERTICAL);
542 desktopIcons.setColumnCount(columns);
543 desktopIcons.setRowCount(rows);
545 SparseArray<DesktopIconInfo> icons = new SparseArray<>();
548 SharedPreferences pref = U.getSharedPreferences(this);
549 JSONArray jsonIcons = new JSONArray(pref.getString("desktop_icons", "[]"));
551 for(int i = 0; i < jsonIcons.length(); i++) {
552 DesktopIconInfo info = DesktopIconInfo.fromJson(jsonIcons.getJSONObject(i));
554 icons.put(getIndex(info), info);
556 } catch (JSONException e) { /* Gracefully fail */ }
558 for(int i = 0; i < columns * rows; i++) {
559 FrameLayout iconContainer = new FrameLayout(this);
560 iconContainer.setLayoutParams(new GridLayout.LayoutParams(new ViewGroup.LayoutParams(desktopIconSize, desktopIconSize)));
561 iconContainer.setOnDragListener(new DesktopIconDragListener());
565 iconContainer.setOnClickListener(view -> {
566 boolean isStartMenuOpen = MenuHelper.getInstance().isStartMenuOpen();
567 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
569 DesktopIconInfo info = icons.get(index);
570 if(!isStartMenuOpen && info != null && info.entry != null) {
573 info.entry.getPackageName(),
574 info.entry.getComponentName(),
575 info.entry.getUserId(this),
583 iconContainer.setOnLongClickListener(view -> {
584 int[] location = new int[2];
585 view.getLocationOnScreen(location);
587 DesktopIconInfo info = icons.get(index);
588 if(info == null) info = getDesktopIconInfo(index);
590 openContextMenu(info, location);
594 iconContainer.setOnGenericMotionListener((view, motionEvent) -> {
595 int action = motionEvent.getAction();
597 if(action == MotionEvent.ACTION_BUTTON_PRESS
598 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
599 int[] location = new int[2];
600 view.getLocationOnScreen(location);
602 DesktopIconInfo info = icons.get(index);
603 if(info == null) info = getDesktopIconInfo(index);
605 openContextMenu(info, location);
611 DesktopIconInfo info = icons.get(index);
612 if(info != null && info.entry != null)
613 iconContainer.addView(inflateDesktopIcon(iconContainer, info.entry));
615 desktopIcons.addView(iconContainer);
619 private void sortDesktopIcons() {
621 SharedPreferences pref = U.getSharedPreferences(this);
622 JSONArray jsonIcons = new JSONArray(pref.getString("desktop_icons", "[]"));
624 if(jsonIcons.length() == 0) {
625 U.showToast(this, R.string.no_icons_to_sort);
629 List<DesktopIconInfo> icons = new ArrayList<>();
631 for(int i = 0; i < jsonIcons.length(); i++) {
632 DesktopIconInfo info = DesktopIconInfo.fromJson(jsonIcons.getJSONObject(i));
637 Collections.sort(icons, (o1, o2) -> Collator.getInstance().compare(o1.entry.getLabel(), o2.entry.getLabel()));
639 jsonIcons = new JSONArray();
641 for(int i = 0; i < icons.size(); i++) {
642 DesktopIconInfo oldInfo = icons.get(i);
643 DesktopIconInfo newInfo = getDesktopIconInfo(i);
645 oldInfo.column = newInfo.column;
646 oldInfo.row = newInfo.row;
648 jsonIcons.put(oldInfo.toJson(this));
651 pref.edit().putString("desktop_icons", jsonIcons.toString()).apply();
652 refreshDesktopIcons();
653 } catch (JSONException e) { /* Gracefully fail */ }
656 private void reassignDroppedIcon() {
657 if(startDragIndex == endDragIndex) return;
660 SharedPreferences pref = U.getSharedPreferences(this);
661 JSONArray jsonIcons = new JSONArray(pref.getString("desktop_icons", "[]"));
662 int iconToRemove = -1;
664 DesktopIconInfo oldInfo = getDesktopIconInfo(startDragIndex);
665 DesktopIconInfo newInfo = getDesktopIconInfo(endDragIndex);
667 for(int i = 0; i < jsonIcons.length(); i++) {
668 DesktopIconInfo info = DesktopIconInfo.fromJson(jsonIcons.getJSONObject(i));
669 if(info != null && info.column == oldInfo.column && info.row == oldInfo.row) {
670 newInfo.entry = info.entry;
676 if(iconToRemove > -1) {
677 jsonIcons.remove(iconToRemove);
678 jsonIcons.put(newInfo.toJson(this));
680 pref.edit().putString("desktop_icons", jsonIcons.toString()).apply();
682 } catch (JSONException e) { /* Gracefully fail */ }
685 private void enterIconArrangeMode() {
687 SharedPreferences pref = U.getSharedPreferences(this);
688 JSONArray jsonIcons = new JSONArray(pref.getString("desktop_icons", "[]"));
690 if(jsonIcons.length() == 0) {
691 U.showToast(this, R.string.no_icons_to_arrange);
695 iconArrangeMode = true;
697 } catch (JSONException e) { /* Gracefully fail */ }
700 private void updateMargins() {
701 if(desktopIcons == null || fab == null) return;
703 String position = U.getTaskbarPosition(this);
704 int iconSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
711 if(position.contains("vertical_left"))
713 else if(position.contains("vertical_right"))
715 else if(position.contains("bottom"))
720 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
721 FrameLayout.LayoutParams.MATCH_PARENT,
722 FrameLayout.LayoutParams.MATCH_PARENT
725 params.setMargins(left, top, right, bottom);
726 desktopIcons.setLayoutParams(params);
728 int fabMargin = getResources().getDimensionPixelSize(R.dimen.desktop_icon_fab_margin);
734 FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(
735 FrameLayout.LayoutParams.WRAP_CONTENT,
736 FrameLayout.LayoutParams.WRAP_CONTENT
739 params2.gravity = Gravity.BOTTOM | Gravity.END;
740 params2.setMargins(left, top, right, bottom);
741 fab.setLayoutParams(params2);
744 private int getIndex(DesktopIconInfo info) {
745 return (info.column * desktopIcons.getRowCount()) + info.row;
748 private DesktopIconInfo getDesktopIconInfo(int index) {
749 int row = index % desktopIcons.getRowCount();
755 pos -= desktopIcons.getRowCount();
759 return new DesktopIconInfo(column, row, null);
762 private View inflateDesktopIcon(ViewGroup parent, AppEntry entry) {
763 View icon = LayoutInflater.from(this).inflate(R.layout.row_alt, parent, false);
765 TextView textView = icon.findViewById(R.id.name);
766 textView.setText(entry.getLabel());
767 textView.setTextColor(ContextCompat.getColor(this, R.color.desktop_icon_text));
768 textView.setShadowLayer(50, 0, 0, R.color.desktop_icon_shadow);
770 ImageView imageView = icon.findViewById(R.id.icon);
771 imageView.setImageDrawable(entry.getIcon(this));
773 icon.setOnTouchListener(new DesktopIconTouchListener());
777 private void openContextMenu(final DesktopIconInfo info, final int[] location) {
778 if(iconArrangeMode) return;
780 Bundle args = new Bundle();
782 if(info.entry != null) {
783 args.putString("package_name", info.entry.getPackageName());
784 args.putString("app_name", info.entry.getLabel());
785 args.putString("component_name", info.entry.getComponentName());
786 args.putLong("user_id", info.entry.getUserId(this));
789 args.putSerializable("desktop_icon", info);
790 args.putInt("x", location[0]);
791 args.putInt("y", location[1]);
793 U.startContextMenuActivity(this, args);
796 private final class DesktopIconTouchListener implements View.OnTouchListener {
798 public boolean onTouch(View view, MotionEvent motionEvent) {
799 if(iconArrangeMode && motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
800 startDragIndex = desktopIcons.indexOfChild((ViewGroup) view.getParent());
802 ClipData data = ClipData.newPlainText("", "");
803 View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
804 view.startDrag(data, shadowBuilder, view, 0);
805 view.setVisibility(View.INVISIBLE);
812 private final class DesktopIconDragListener implements View.OnDragListener {
814 public boolean onDrag(View v, DragEvent event) {
815 switch(event.getAction()) {
816 case DragEvent.ACTION_DRAG_STARTED:
820 case DragEvent.ACTION_DRAG_ENTERED:
821 FrameLayout container = (FrameLayout) v;
822 if(container.getChildCount() == 0
823 || startDragIndex == desktopIcons.indexOfChild(container)) {
824 v.setBackgroundColor(U.getAccentColor(HomeActivityDelegate.this));
828 case DragEvent.ACTION_DRAG_ENDED:
829 View view = (View) event.getLocalState();
830 view.setVisibility(View.VISIBLE);
832 case DragEvent.ACTION_DRAG_EXITED:
833 v.setBackground(null);
836 case DragEvent.ACTION_DROP:
837 FrameLayout container2 = (FrameLayout) v;
838 if(container2.getChildCount() == 0) {
839 // Dropped, reassign View to ViewGroup
840 View view2 = (View) event.getLocalState();
841 ViewGroup owner = (ViewGroup) view2.getParent();
842 owner.removeView(view2);
843 container2.addView(view2);
845 endDragIndex = desktopIcons.indexOfChild(container2);
846 reassignDroppedIcon();