package de.theknut.xposedgelsettings.hooks.general;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.text.TextUtils;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.ScaleAnimation;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Iterator;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import de.theknut.xposedgelsettings.R;
import de.theknut.xposedgelsettings.hooks.Common;
import de.theknut.xposedgelsettings.hooks.HooksBaseClass;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Classes;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Fields;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Methods;
import de.theknut.xposedgelsettings.hooks.PreferencesHelper;
import de.theknut.xposedgelsettings.hooks.Utils;
import de.theknut.xposedgelsettings.ui.AllAppsList;
import de.theknut.xposedgelsettings.ui.FragmentSelectiveIcon;
import de.theknut.xposedgelsettings.ui.SaveActivity;
import static de.robv.android.xposed.XposedBridge.hookAllMethods;
import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.callStaticMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static de.robv.android.xposed.XposedHelpers.getAdditionalInstanceField;
import static de.robv.android.xposed.XposedHelpers.getBooleanField;
import static de.robv.android.xposed.XposedHelpers.getIntField;
import static de.robv.android.xposed.XposedHelpers.getLongField;
import static de.robv.android.xposed.XposedHelpers.getObjectField;
import static de.robv.android.xposed.XposedHelpers.setAdditionalInstanceField;
import static de.robv.android.xposed.XposedHelpers.setObjectField;
import static de.theknut.xposedgelsettings.hooks.Utils.isIntersecting;
/**
* Created by Alexander Schulz on 20.07.2014.
*/
public class ContextMenu extends HooksBaseClass{
static Context XGELSContext;
static final String HOLDER_TAG = "XGELS_CONTEXT_MENU_HOLDER";
static final String CONTEXT_MENU_TAG = "XGELS_CONTEXT_MENU";
static float contextMenuWidth, contextMenuHeight, contextMenuItemWidth, padding, downX = -1, downY = -1;
static int animatingDuration = 150;
static boolean isAnimating;
static boolean isOpen;
static int closeThreshold;
static final int DISABLED = 0;
static final int SHORTCUT_ONLY = 1;
static final int WIDGET_ONLY = 2;
static final int SHORTCUT_WIDGET = 3;
static ClassLoader classLoader;
static Object dragObject;
public static void initAllHooks(final LoadPackageParam lpparam) {
classLoader = lpparam.classLoader;
if (isMode(DISABLED)) return;
if (isMode(WIDGET_ONLY) || isMode(SHORTCUT_WIDGET)) {
XC_MethodHook addResizeFrameHook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
int WIDGET = 0;
if ((Common.PACKAGE_OBFUSCATED && Common.GNL_VERSION >= ObfuscationHelper.GNL_4_2_16)
|| !Common.PACKAGE_OBFUSCATED) {
WIDGET = 1;
} else if (Common.PACKAGE_OBFUSCATED && Common.GNL_VERSION < ObfuscationHelper.GNL_4_2_16) {
WIDGET = 0;
}
Object resize = getAdditionalInstanceField(param.args[WIDGET], "resize");
if (resize == null) {
param.setResult(null);
} else {
setAdditionalInstanceField(param.args[WIDGET], "resize", false);
if (!(Boolean) resize) {
param.setResult(null);
}
}
}
};
if (Common.IS_GNL && Common.IS_M_GNL) {
} else if (Common.GNL_VERSION >= ObfuscationHelper.GNL_4_2_16) {
findAndHookMethod(Classes.DragLayer, Methods.dlAddResizeFrame, Classes.ItemInfo, Classes.LauncherAppWidgetHostView, Classes.CellLayout, addResizeFrameHook);
}
else if (Common.PACKAGE_OBFUSCATED && Common.GNL_VERSION < ObfuscationHelper.GNL_4_2_16) {
findAndHookMethod(Classes.DragLayer, Methods.dlAddResizeFrame, Classes.LauncherAppWidgetHostView, Classes.CellLayout, addResizeFrameHook);
} else {
findAndHookMethod(Classes.DragLayer, Methods.dlAddResizeFrame, Classes.ItemInfo, Classes.LauncherAppWidgetHostView, Classes.CellLayout, addResizeFrameHook);
}
}
XC_MethodHook longClickHook = new XC_MethodHook() {
LayoutInflater inflater;
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (PreferencesHelper.lockHomescreen) return;
if (!param.thisObject.getClass().equals(Classes.Folder)) {
if (callMethod(Common.WORKSPACE_INSTANCE, Methods.wGetOpenFolder) != null) {
return;
}
}
final View longPressedItem = (View) param.args[0];
if (longPressedItem.getTag() == null) return;
if (longPressedItem.getClass().equals(Classes.CellLayout)) return;
if (Common.IS_KK_TREBUCHET) {
try {
// alls apps button
if (getIntField(longPressedItem.getTag(), Fields.iiItemType) == 5) {
return;
}
}catch (Exception e) {
e.printStackTrace();
}
}
if (isMode(SHORTCUT_ONLY) && !longPressedItem.getClass().equals(Classes.BubbleTextView)) return;
if (isMode(WIDGET_ONLY) && !isWidget(longPressedItem)) return;
if (inflater == null) {
XGELSContext = Common.LAUNCHER_CONTEXT.createPackageContext(Common.PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY);
inflater = (LayoutInflater) XGELSContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
contextMenuItemWidth = XGELSContext.getResources().getDimension(R.dimen.context_menu_icon_size);
contextMenuHeight = XGELSContext.getResources().getDimension(R.dimen.context_menu_icon_size);
padding = XGELSContext.getResources().getDimension(R.dimen.context_menu_padding);
closeThreshold = Math.round(XGELSContext.getResources().getDimension(R.dimen.context_menu_close_threshold));
contextMenuHeight += 2 * padding;
}
final ViewGroup dragLayer = getDragLayer();
ViewGroup contextMenuHolder = setupContextMenu(longPressedItem);
closeAndRemove();
dragLayer.addView(contextMenuHolder, 0);
animateOpen(contextMenuHolder);
}
private ViewGroup setupContextMenu(View longPressedItem) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewGroup contextMenuHolder = (ViewGroup) inflater.inflate(R.layout.contextmenu, null, true);
ViewGroup contextMenu = (ViewGroup) contextMenuHolder.findViewById(R.id.contextmenu);
setupMenuItems(contextMenuHolder, longPressedItem);
contextMenuWidth = getContextMenuWidth(contextMenu);
int availableWidth = getAvailableWidth();
int statusBarHeight = getStatusBarHeight();
int[] location = new int[2];
longPressedItem.getLocationInWindow(location);
float neededSpace = contextMenuWidth / 2;
float x, y;
x = location[0] - neededSpace + longPressedItem.getWidth() / 2;
if (isWidget(longPressedItem)) {
y = location[1] + longPressedItem.getHeight() / 2 - contextMenuHeight;
} else {
y = location[1] - contextMenuHeight;
if (Common.PACKAGE_OBFUSCATED) {
y = location[1] - contextMenuHeight / 2 - longPressedItem.getPivotY() - padding;
}
if (y < statusBarHeight) {
y = statusBarHeight + location[1];
}
}
if (x < (3 * padding)) {
x = 3 * padding;
} else if ((x + contextMenuWidth + 3 * padding) > availableWidth) {
x = availableWidth - contextMenuWidth - 3 * padding;
}
params.setMargins(Math.round(x), Math.round(y), 0, 0);
contextMenuHolder.setTag(HOLDER_TAG);
contextMenu.setTag(CONTEXT_MENU_TAG);
contextMenu.setLayoutParams(params);
return contextMenuHolder;
}
};
findAndHookMethod(Classes.Launcher, "onLongClick", View.class, longClickHook);
findAndHookMethod(Classes.Folder, "onLongClick", View.class, longClickHook);
findAndHookMethod(Classes.DragLayer, "onTouchEvent", MotionEvent.class, new XC_MethodHook() {
final int INVALID = -1;
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
MotionEvent ev = (MotionEvent) param.args[0];
if ((ev.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
if (downX == INVALID || downY == INVALID) {
downX = ev.getRawX();
downY = ev.getRawY();
} else if (Math.abs(ev.getRawX() - downX) > closeThreshold
|| Math.abs(ev.getRawY() - downY) > closeThreshold) {
closeAndRemove();
}
} else if ((ev.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
downX = downY = INVALID;
}
}
});
XC_MethodHook hook;
if (Common.GNL_VERSION >= ObfuscationHelper.GNL_5_3_23) {
hook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// onDragEnd will move the page, so check whether we are moving or not
if (isOpen && !getBooleanField(Common.WORKSPACE_INSTANCE, "mIsDragOccuring")) {
closeAndRemove();
}
}
};
} else {
hook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (isOpen) {
closeAndRemove();
}
}
};
}
hookAllMethods(Classes.PagedView, Methods.pvPageBeginMoving, hook);
if (Common.GNL_VERSION >= ObfuscationHelper.GNL_5_4_24) {
hook = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
switch (param.method.getName()) {
case "onClick":
if (isOpen && param.args[0].getClass().equals(Classes.CellLayout)) {
closeAndRemove();
}
break;
case "showOverviewMode":
if (isOpen) {
closeAndRemove();
}
break;
case "handleTouchDown":
if (isOpen && callMethod(Common.WORKSPACE_INSTANCE, Methods.wGetOpenFolder) != null) {
closeAndRemove();
}
break;
}
}
};
findAndHookMethod(Classes.Launcher, "onClick", View.class, hook);
findAndHookMethod(Classes.DragLayer, "handleTouchDown", MotionEvent.class, boolean.class, hook);
XposedBridge.hookAllMethods(Classes.Launcher, "showOverviewMode", hook);
}
}
public static int getStatusBarHeight() {
int result = 0;
int resourceId = Common.LAUNCHER_CONTEXT.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = Common.LAUNCHER_CONTEXT.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
private static int getAvailableWidth() {
WindowManager wm = (WindowManager) Common.LAUNCHER_CONTEXT.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}
private static float getContextMenuWidth(ViewGroup contextMenu) {
float height = 0.0f;
for (int i = 0; i < contextMenu.getChildCount(); i++) {
View child = contextMenu.getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
height += contextMenuItemWidth;
}
}
return height + 2 * padding;
}
private static void setupMenuItems(ViewGroup contextMenuHolder, final View longPressedItem) {
boolean show;
final boolean isWidget, isFolder, isSystemApp;
final boolean isPremium = checkPremium();
final Object tag = longPressedItem.getTag();
isWidget = isWidget(tag);
isFolder = isFolder(tag);
isSystemApp = isSystemApp(tag);
ImageView uninstall = (ImageView) contextMenuHolder.findViewById(R.id.uninstall);
Utils.setDrawableSelector(uninstall);
uninstall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:" + getPackageName(tag)));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Common.LAUNCHER_CONTEXT.startActivity(intent);
}
});
show = isSystemApp || isFolder || getPackageName(tag) == null;
uninstall.setVisibility(show ? View.GONE : View.VISIBLE);
ImageView gesture = (ImageView) contextMenuHolder.findViewById(R.id.gesture);
Utils.setDrawableSelector(gesture);
gesture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.setComponent(new ComponentName(Common.PACKAGE_NAME, SaveActivity.class.getName()));
intent.putExtra("mode", SaveActivity.MODE_PICK_COLOR);
intent.putExtra("itemid", getLongField(tag, Fields.iiID));
Common.LAUNCHER_CONTEXT.startActivity(intent);
}
});
show = !isFolder;
gesture.setVisibility(View.GONE);
ImageView appInfo = (ImageView) contextMenuHolder.findViewById(R.id.appinfo);
Utils.setDrawableSelector(appInfo);
appInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeContextMenu();
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
try {
intent.setData(Uri.parse("package:" + getPackageName(tag)));
} catch (Exception ex) {
intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Common.LAUNCHER_CONTEXT.startActivity(intent);
}
});
show = isFolder || getPackageName(tag) == null;
appInfo.setVisibility(show ? View.GONE : View.VISIBLE);
final ImageView editName = (ImageView) contextMenuHolder.findViewById(R.id.appname);
Utils.setDrawableSelector(editName);
editName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeContextMenu();
final String curName = String.valueOf(getObjectField(tag, "title"));
final AlertDialog editNameDialog = new AlertDialog.Builder(Common.LAUNCHER_INSTANCE, AlertDialog.THEME_DEVICE_DEFAULT_DARK).create();
final ViewGroup editNameView = (ViewGroup) LayoutInflater.from(XGELSContext).inflate(R.layout.edit_app_name, null);
final EditText editText = (EditText) editNameView.findViewById(R.id.edit_app_name_edittext);
editText.setHint(curName);
int padding = Math.round(XGELSContext.getResources().getDimension(R.dimen.edit_app_name_padding));
editNameDialog.setView(editNameView, padding, padding, padding, padding);
editNameView.findViewById(R.id.edit_app_name_save).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String newName = editText.getText().toString().trim();
if (newName.length() == 0) {
editNameDialog.dismiss();
return;
}
if (!curName.equals(newName)) {
String itemId = String.valueOf(getLongField(tag, Fields.iiID));
setObjectField(tag, "title", newName);
((TextView) longPressedItem).setText(newName);
Iterator<String> it = PreferencesHelper.appNames.iterator();
while (it.hasNext()) {
String next = it.next();
String[] split = next.split("\\|");
if (split[0].equals(itemId)) {
it.remove();
break;
}
}
PreferencesHelper.appNames.add(itemId + "|shortcut|" + newName);
Utils.saveToSettings(Common.LAUNCHER_CONTEXT, "appnames", PreferencesHelper.appNames);
}
editNameDialog.dismiss();
}
});
editNameView.findViewById(R.id.edit_app_name_restore).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager();
Intent intent = (Intent) callMethod(tag, "getIntent");
String title = null;
String itemId = String.valueOf(getLongField(tag, Fields.iiID));
if (intent != null && intent.getComponent() != null) {
title = String.valueOf(pm.resolveActivity(intent, 0).activityInfo.loadLabel(pm));
}
if (!TextUtils.isEmpty(title)) {
setObjectField(tag, "title", title);
((TextView) longPressedItem).setText(title);
}
Iterator<String> it = PreferencesHelper.appNames.iterator();
while (it.hasNext()) {
String next = it.next();
String[] split = next.split("\\|");
if (split[0].equals(itemId)) {
it.remove();
break;
}
}
Utils.saveToSettings(Common.LAUNCHER_CONTEXT, "appnames", PreferencesHelper.appNames);
editNameDialog.dismiss();
}
});
String title = curName;
PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager();
Intent intent = (Intent) callMethod(tag, "getIntent");
if (intent != null
&& intent.getComponent() != null) {
title = String.valueOf(pm.resolveActivity(intent, 0).activityInfo.loadLabel(pm));
}
editNameDialog.setTitle(title);
editNameDialog.show();
}
});
show = !isFolder && !isWidget;
editName.setVisibility(show ? View.VISIBLE : View.GONE);
ImageView remove = (ImageView) contextMenuHolder.findViewById(R.id.remove);
Utils.setDrawableSelector(remove);
remove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
try {
Animation animation = AnimationUtils.loadAnimation(Common.XGELS_CONTEXT, R.anim.delete_item_anim);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation) {
((ViewGroup) longPressedItem.getParent()).post(new Runnable() {
@Override
public void run() {
((ViewGroup) longPressedItem.getParent()).removeView(longPressedItem);
if (Common.IS_KK_TREBUCHET) {
callStaticMethod(Classes.LauncherModel, "deleteItemFromDatabase", Common.LAUNCHER_INSTANCE, longPressedItem.getTag());
} else if (Common.IS_PRE_GNL_4) {
callStaticMethod(Classes.LauncherModel, Methods.lmDeleteItemsFromDatabase, Common.LAUNCHER_INSTANCE, longPressedItem.getTag());
} else {
ArrayList array = new ArrayList();
array.add(longPressedItem.getTag());
callStaticMethod(Classes.LauncherModel, Methods.lmDeleteItemsFromDatabase, Common.LAUNCHER_CONTEXT, array);
}
}
});
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
longPressedItem.startAnimation(animation);
} catch(Exception e) { }
}
});
// TODO: widgets need more than deleteItemFromDatabase, defer this for later
// http://androidxref.com/4.4.2_r1/xref/packages/apps/Launcher3/src/com/android/launcher3/DeleteDropTarget.java#327
show = isWidget || isFolder;
remove.setVisibility(show ? View.GONE : View.VISIBLE);
ImageView manageFolder = (ImageView) contextMenuHolder.findViewById(R.id.managefolder);
Utils.setDrawableSelector(manageFolder);
manageFolder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeContextMenu();
Common.CURRENT_CONTEXT_MENU_ITEM = longPressedItem;
ArrayList<String> items = new ArrayList<String>();
Object mFolder = getObjectField(longPressedItem, Fields.fiFolder);
ArrayList<View> folderItems = (ArrayList<View>) callMethod(mFolder, Methods.fGetItemsInReadingOrder);
for (View item : folderItems) {
items.add(((Intent) callMethod(item.getTag(), "getIntent")).getComponent().flattenToString());
}
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.setComponent(new ComponentName(Common.PACKAGE_NAME, AllAppsList.class.getName()));
intent.putExtra("mode", AllAppsList.MODE_SELECT_FOLDER_APPS);
intent.putExtra("foldername", ((TextView) getObjectField(longPressedItem, Fields.fiFolderName)).getText());
intent.putExtra("itemid", getLongField(tag, Fields.iiID));
intent.putExtra("homescreen", true);
intent.putStringArrayListExtra("items", items);
Common.LAUNCHER_CONTEXT.startActivity(intent);
}
});
show = isFolder && (Common.GNL_VERSION < ObfuscationHelper.GNL_5_3_23);
manageFolder.setVisibility(show ? View.VISIBLE : View.GONE);
ImageView sort = (ImageView) contextMenuHolder.findViewById(R.id.sortapps);
Utils.setDrawableSelector(sort);
sort.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
Object folder = getObjectField(longPressedItem, Fields.fiFolder);
ArrayList tagList = new ArrayList();
ArrayList<View> apps = (ArrayList<View>) callMethod(folder, Methods.fGetItemsInReadingOrder);
for (View app : apps) {
tagList.add(app.getTag());
}
callMethod(folder, "h", tagList);
callMethod(folder, "aU", 6);
}
});
show = false;
sort.setVisibility(show ? View.VISIBLE : View.GONE);
ImageView iconPicker = (ImageView) contextMenuHolder.findViewById(R.id.settings);
Utils.setDrawableSelector(iconPicker);
iconPicker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeContextMenu();
Common.CURRENT_CONTEXT_MENU_ITEM = longPressedItem;
if (!isPremium) {
Utils.showPremiumOnly();
return;
}
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.setComponent(new ComponentName(Common.PACKAGE_NAME, FragmentSelectiveIcon.class.getName()));
intent.putExtra("mode", isFolder ? FragmentSelectiveIcon.MODE_PICK_FOLDER_ICON : FragmentSelectiveIcon.MODE_PICK_SHORTCUT_ICON);
intent.putExtra("name", getObjectField(tag, "title").toString());
intent.putExtra("itemtid", getLongField(tag, Fields.iiID));
Common.LAUNCHER_CONTEXT.startActivity(intent);
}
});
show = isWidget;
iconPicker.setVisibility(show ? View.GONE : View.VISIBLE);
ImageView resize = (ImageView) contextMenuHolder.findViewById(R.id.resize);
Utils.setDrawableSelector(remove);
resize.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
if (Common.GNL_VERSION >= ObfuscationHelper.GNL_5_3_23) {
setAdditionalInstanceField(longPressedItem.getTag(), "resize", true);
callMethod(Common.WORKSPACE_INSTANCE, "onDrop", dragObject);
setObjectField(getObjectField(Common.WORKSPACE_INSTANCE, "mDragController"), "mDragging", false);
} else {
setAdditionalInstanceField(longPressedItem, "resize", true);
if (Common.PACKAGE_OBFUSCATED && Common.GNL_VERSION < ObfuscationHelper.GNL_4_2_16) {
callMethod(getDragLayer(), Methods.dlAddResizeFrame, longPressedItem, longPressedItem.getParent().getParent());
} else {
callMethod(getDragLayer(), Methods.dlAddResizeFrame, longPressedItem.getTag(), longPressedItem, longPressedItem.getParent().getParent());
}
}
}
});
show = isWidget && (Common.GNL_VERSION < ObfuscationHelper.GNL_5_3_23);
resize.setVisibility(show ? View.VISIBLE : View.GONE);
ImageView layerUp = (ImageView) contextMenuHolder.findViewById(R.id.layerup);
Utils.setDrawableSelector(layerUp);
layerUp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
longPressedItem.bringToFront();
boolean dirty = false;
long id = getLongField(tag, Fields.iiID);
ArrayList<String> positions = new ArrayList<String>(PreferencesHelper.layerPositions);
for (String pos : positions) {
log("Saved " + pos);
}
ViewGroup shortcutAndWidgetsContainer = (ViewGroup) longPressedItem.getParent();
for (int j = 0; j < shortcutAndWidgetsContainer.getChildCount(); j++) {
View child = shortcutAndWidgetsContainer.getChildAt(j);
log("Child " + child.getTag());
}
for (int j = 0; j < shortcutAndWidgetsContainer.getChildCount(); j++) {
View child = shortcutAndWidgetsContainer.getChildAt(j);
long childId = getLongField(child.getTag(), Fields.iiID);
if (childId != id && Utils.isIntersecting(longPressedItem)) {
positions.remove("" + childId);
positions.remove("" + id);
positions.add("" + id);
dirty = true;
log("Layer up Removed " + childId);
log("Layer up Added " + id);
}
}
if (dirty) {
savePositionInLayer(positions);
}
}
});
show = (PreferencesHelper.overlappingWidgets && isWidget) || Utils.isIntersecting(longPressedItem);
layerUp.setVisibility(show ? View.VISIBLE : View.GONE);
ImageView layerDown = (ImageView) contextMenuHolder.findViewById(R.id.layerdown);
Utils.setDrawableSelector(layerDown);
layerDown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeAndRemove();
boolean dirty = false;
long id = getLongField(tag, Fields.iiID);
ArrayList<String> positions = new ArrayList<String>(PreferencesHelper.layerPositions);
for (String pos : positions) {
log("Saved " + pos);
}
ViewGroup shortcutAndWidgetsContainer = (ViewGroup) longPressedItem.getParent();
for (int j = 0; j < shortcutAndWidgetsContainer.getChildCount(); j++) {
View child = shortcutAndWidgetsContainer.getChildAt(j);
log("Child " + child.getTag());
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < shortcutAndWidgetsContainer.getChildCount(); j++) {
View child = shortcutAndWidgetsContainer.getChildAt(j);
long childId = getLongField(child.getTag(), Fields.iiID);
if (intersects(child) && childId != id) {
child.bringToFront();
positions.remove("" + id);
positions.remove("" + childId);
positions.add("" + childId);
dirty = true;
log("Layer down Removed " + id);
log("Layer down Added " + childId);
}
}
}
if (dirty) {
savePositionInLayer(positions);
}
}
private boolean intersects(View child) {
Rect myViewRect = new Rect();
longPressedItem.getHitRect(myViewRect);
Rect otherViewRect1 = new Rect();
child.getHitRect(otherViewRect1);
return Rect.intersects(myViewRect, otherViewRect1);
}
});
show = (PreferencesHelper.overlappingWidgets && isWidget) || isIntersecting(longPressedItem);
layerDown.setVisibility(show ? View.VISIBLE : View.GONE);
}
private static void savePositionInLayer(ArrayList<String> positions) {
Utils.saveToSettings(Common.LAUNCHER_CONTEXT, "layerpositions", positions);
}
private static String getPackageName(Object tag) {
try {
return getComponentName(tag).getPackageName();
} catch (Error e) {
// Oh dear what happened?
} catch (Exception e) {
// Oh dear what happened?
}
return null;
}
private static ComponentName getComponentName(Object tag) {
try {
if (isWidget(tag)) {
return ((ComponentName) getObjectField(tag, Fields.lawiProviderName));
} else {
Intent i = (Intent) callMethod(tag, "getIntent");
return i.getComponent();
}
} catch (Error e) {
// Oh dear what happened?
} catch (Exception e) {
// Oh dear what happened?
}
return null;
}
private static boolean isWidget(View longPressedItem) {
return isWidget(longPressedItem.getTag());
}
private static boolean isWidget(Object tag) {
return tag.getClass().equals(Classes.LauncherAppWidgetInfo);
}
private static boolean isFolder(View longPressedItem) {
return isFolder(longPressedItem.getTag());
}
private static boolean isFolder(Object tag) {
return tag.getClass().equals(Classes.FolderInfo);
}
private static boolean isSystemApp(Object tag) {
int flags;
try {
String pkg = getPackageName(tag);
PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager();
flags = pm.getPackageInfo(pkg, 0).applicationInfo.flags;
} catch (Error e) {
// Oh dear what happened?
return false;
} catch (Exception e) {
// Oh dear what happened?
return false;
}
// SYSTEM - 0x1
// FLAG_UPDATED_SYSTEM_APP - 0x80
return (flags & 0x81) > 0;
}
private static ViewGroup getDragLayer() {
return Common.GNL_VERSION >= ObfuscationHelper.GNL_5_3_23
? ((ViewGroup) Common.DRAG_LAYER.getParent())
: Common.DRAG_LAYER;
}
private static void removeContextMenu() {
ViewGroup dragLayer = getDragLayer();
View v = dragLayer.findViewWithTag(HOLDER_TAG);
if (v != null) {
dragLayer.removeView(v);
}
}
private static void animateOpen(final ViewGroup contextMenu) {
final View menu = contextMenu.findViewById(R.id.contextmenu);
ScaleAnimation scale = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, contextMenuWidth / 2, contextMenuHeight / 2);
scale.setFillAfter(true);
scale.setDuration(animatingDuration);
scale.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation) {
contextMenu.bringToFront();
isOpen = true;
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
menu.startAnimation(scale);
}
public static void closeAndRemove() {
if (isAnimating) return;
final ViewGroup contextMenuHolder = (ViewGroup) getDragLayer().findViewWithTag(HOLDER_TAG);
if (contextMenuHolder != null) {
final View menu = contextMenuHolder.findViewWithTag(CONTEXT_MENU_TAG);
ScaleAnimation scale = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f, contextMenuWidth / 2, contextMenuHeight / 2);
scale.setDuration(animatingDuration);
scale.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
isAnimating = true;
}
@Override
public void onAnimationEnd(Animation animation) {
removeContextMenu();
isAnimating = isOpen = false;
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
menu.startAnimation(scale);
contextMenuHolder.invalidate();
}
}
public static boolean isOpen() {
return getDragLayer().findViewWithTag(HOLDER_TAG) != null;
}
private static boolean isMode(int mode) {
return PreferencesHelper.contextmenuMode == mode;
}
}