package de.theknut.xposedgelsettings.hooks; import android.app.Activity; import android.app.ActivityOptions; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.support.v4.app.ActivityCompat; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.Toast; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Set; import de.robv.android.xposed.XposedBridge; import de.theknut.xposedgelsettings.R; import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Fields; import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Methods; import de.theknut.xposedgelsettings.hooks.icon.IconPack; import de.theknut.xposedgelsettings.ui.CommonUI; import static de.robv.android.xposed.XposedHelpers.callMethod; import static de.robv.android.xposed.XposedHelpers.callStaticMethod; import static de.robv.android.xposed.XposedHelpers.getLongField; import static de.robv.android.xposed.XposedHelpers.getObjectField; import static de.robv.android.xposed.XposedHelpers.newInstance; /** * Created by Alexander Schulz on 04.08.2014. */ public class Utils { static Random rand = new Random(); static String[] colors = new String[] { "#e84e40", // red_400 "#e51c23", // red_500 "#dd191d", // red_600 "#d01716", // red_700 "#c41411", // red_800 "#b0120a", // red_900 "#5c6bc0", // indigo_400 "#3f51b5", // indigo_500 "#3949ab", // indigo_600 "#303f9f", // indigo_700 "#283593", // indigo_800 "#1a237e", // indigo_900 "#3d5afe", // indigo_A400 "#304ffe", // indigo_A700 "#5677fc", // blue_500 "#4e6cef", // blue_600 "#455ede", // blue_700 "#3b50ce", // blue_800 "#2a36b1", // blue_900 "#4d73ff", // blue_A400 "#4d69ff", // blue_A700 "#039be5", // light_blue_600 "#0288d1", // light_blue_700 "#0277bd", // light_blue_800 "#01579b", // light_blue_900 "#00b0ff", // light_blue_A400 "#0091ea", // light_blue_A700 "#00acc1", // cyan_600 "#0097a7", // cyan_700 "#00838f", // cyan_800 "#006064", // cyan_900 "#26a69a", // teal_400 "#009688", // teal_500 "#00897b", // teal_600 "#00796b", // teal_700 "#00695c", // teal_800 "#004d40", // teal_900 "#2baf2b", // green_400 "#259b24", // green_500 "#0a8f08", // green_600 "#0a7e07", // green_700 "#056f00", // green_800 "#12c700", // green_A700 "#558b2f", // light_green_800 "#33691e", // light_green_900 "#827717", // lime_900 "#e65100", // orange_900 "#f4511e", // deep_orange_600 "#e64a19", // deep_orange_700 "#d84315", // deep_orange_800 "#bf360c", // deep_orange_900 "#ff3d00", // deep_orange_A400 "#dd2c00", // deep_orange_A700 "#8d6e63", // brown_400 "#795548", // brown_500 "#6d4c41", // brown_600 "#5d4037", // brown_700 "#4e342e", // brown_800 "#3e2723", // brown_900 "#757575", // grey_600 "#616161", // grey_700 "#424242", // grey_800 "#212121", // grey_900 "#607d8b", // blue_grey_500 "#546e7a", // blue_grey_600 "#455a64", // blue_grey_700 "#37474f", // blue_grey_800 "#263238" // blue_grey_900 }; // http://stackoverflow.com/a/1855903/809277 public static int getContrastColor(int color) { int d; // Counting the perceptive luminance - human eye favors green color... double a = 1 - ( 0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; if (a < 0.5) d = 0; // bright colors - black font else d = 255; // dark colors - white font return Color.argb(255, d, d, d); } public static int getRandomColor() { return Color.parseColor(colors[rand.nextInt(colors.length - 1)]); } public static boolean isIntersecting(View item) { long id = getLongField(item.getTag(), Fields.iiID); ViewGroup shortcutAndWidgetsContainer = (ViewGroup) item.getParent(); for (int i = 0; i < shortcutAndWidgetsContainer.getChildCount(); i++) { Rect myViewRect = new Rect(); Rect otherViewRect1 = new Rect(); View child = shortcutAndWidgetsContainer.getChildAt(i); item.getHitRect(myViewRect); child.getHitRect(otherViewRect1); if (Rect.intersects(myViewRect, otherViewRect1) && getLongField(child.getTag(), Fields.iiID) != id) { return true; } } return false; } public static boolean should(View item) { long id = getLongField(item.getTag(), Fields.iiID); ViewGroup shortcutAndWidgetsContainer = (ViewGroup) item.getParent(); for (int i = 0; i < shortcutAndWidgetsContainer.getChildCount(); i++) { Rect myViewRect = new Rect(); Rect otherViewRect1 = new Rect(); View child = shortcutAndWidgetsContainer.getChildAt(i); item.getHitRect(myViewRect); child.getHitRect(otherViewRect1); if (Rect.intersects(myViewRect, otherViewRect1) && getLongField(child.getTag(), Fields.iiID) != id) { return true; } } return false; } public static void startActivity(Intent intent) { if (Common.GNL_VERSION >= ObfuscationHelper.GNL_3_5_14) { Resources res = Common.LAUNCHER_CONTEXT.getResources(); int task_open_enter = res.getIdentifier("task_open_enter", "anim", Common.GEL_PACKAGE); int no_anim = res.getIdentifier("no_anim", "anim", Common.GEL_PACKAGE); callMethod(Common.LAUNCHER_INSTANCE, "startActivity", intent, ActivityOptions.makeCustomAnimation(Common.LAUNCHER_CONTEXT, task_open_enter, no_anim).toBundle()); } else { callMethod(Common.LAUNCHER_INSTANCE, "startActivity", intent); } } public static void showPremiumOnly() { Toast.makeText( Common.LAUNCHER_CONTEXT, Common.XGELS_CONTEXT.getResources().getString(R.string.toast_donate_only), Toast.LENGTH_LONG ).show(); } public static void saveToSettings(Context context, String key, Object setting) { saveToSettings(context, key, setting, false); } public static void saveToSettings(Context context, String key, Object setting, boolean restartLauncher) { Intent saveIntent = new Intent(Common.XGELS_ACTION_SAVE_SETTING); saveIntent.putExtra("key", key); saveIntent.putExtra("restart", restartLauncher); if (setting instanceof Boolean) { saveIntent.putExtra("type", "boolean"); saveIntent.putExtra(key, (Boolean) setting); } else if (setting instanceof ArrayList) { saveIntent.putExtra("type", "arraylist"); saveIntent.putStringArrayListExtra(key, (ArrayList<String>) setting); } else if (setting instanceof HashSet) { saveIntent.putExtra("type", "arraylist"); saveIntent.putStringArrayListExtra(key, new ArrayList<String>((HashSet) setting)); } context.sendBroadcast(saveIntent); } public static Object createAppInfo(String pkg) { return createAppInfo(Common.LAUNCHER_CONTEXT.getPackageManager().getLaunchIntentForPackage(pkg)); } public static Object createAppInfo(ComponentName cmp) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(cmp); return createAppInfo(intent); } public static Object createAppInfo(Intent intent) { for (Object appInfo : new ArrayList<>(Common.ALL_APPS)) { try { if (intent.getComponent().equals(((Intent) callMethod(appInfo, "getIntent")).getComponent())) { return appInfo; } } catch (NoSuchMethodError nsme) { } } if (Common.IS_M_GNL) { XposedBridge.log("Bail app " + intent.getComponent().flattenToString()); return null; } if (Common.PACKAGE_OBFUSCATED) { return callMethod(Common.LAUNCHER_INSTANCE, Methods.lCreateAppDragInfo, intent); } PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager(); return newInstance( ObfuscationHelper.Classes.AppInfo, pm, pm.resolveActivity(intent, 0), getObjectField(Common.LAUNCHER_INSTANCE, Fields.lIconCache), new HashMap<Object, CharSequence>()); } public static Object createShortcutInfo(String componentName) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(ComponentName.unflattenFromString(componentName)); if (Common.GNL_VERSION >= ObfuscationHelper.GNL_5_3_23) { Object myUser = callStaticMethod(ObfuscationHelper.Classes.UserHandle, "myUserHandle"); Object launcherApps = callStaticMethod(ObfuscationHelper.Classes.LauncherAppsCompat, "getInstance", Common.LAUNCHER_CONTEXT); Object activityInfo = callMethod(launcherApps, "resolveActivity", intent, myUser); if (activityInfo == null) { return null; } Object appInfo = newInstance( ObfuscationHelper.Classes.AppInfo, Common.LAUNCHER_INSTANCE, activityInfo, myUser, getObjectField(Common.LAUNCHER_INSTANCE, Fields.lIconCache), null); return callMethod(appInfo, Methods.aiMakeShortcut); } else if (Common.PACKAGE_OBFUSCATED) { return callMethod(callMethod(Common.LAUNCHER_INSTANCE, Methods.lCreateAppDragInfo, intent), Methods.aiMakeShortcut); } else { PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager(); Object appInfo = newInstance( ObfuscationHelper.Classes.AppInfo, pm, pm.resolveActivity(intent, 0), getObjectField(Common.LAUNCHER_INSTANCE, Fields.lIconCache), new HashMap<Object, CharSequence>() ); return callMethod(appInfo, Methods.aiMakeShortcut); } } public static List<ResolveInfo> getAllApps() { PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager(); final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); final List<ResolveInfo> apps = pm.queryIntentActivities(mainIntent, 0); Collections.sort(apps, new ResolveInfo.DisplayNameComparator(pm)); return apps; } public static String[] getDataByTag(Set<String> preference, Object tag) { if (tag == null) return null; long id = getLongField(tag, Fields.iiID); Iterator it = preference.iterator(); while (it.hasNext()) { String[] name = it.next().toString().split("\\|"); if (name[0].equals(String.valueOf(id))) { return name; } } return null; } public static Drawable loadIconByTag(IconPack iconPack, Set<String> preference, Object tag) { String[] data = Utils.getDataByTag(preference, tag); if (data == null) return null; return iconPack.loadSingleIconFromIconPack(data[1], null, data[2], false); } public static int dpToPx(int dp) { return dpToPx(dp, Resources.getSystem().getDisplayMetrics()); } public static float dpToPxExact(int dp) { return dp * Resources.getSystem().getDisplayMetrics().density; } public static int dpToPx(int dp, DisplayMetrics displayMetrics) { return Math.round(dp * displayMetrics.density); } public static void setDrawableSelector(ImageView view) { Drawable icon = view.getDrawable(); Bitmap tmpIcon = CommonUI.drawableToBitmap(icon); Bitmap iconPressed = Bitmap.createBitmap(tmpIcon.getWidth(), tmpIcon.getHeight(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(iconPressed); Paint p = new Paint(); p.setAlpha(0x80); c.drawBitmap(tmpIcon, 0, 0, p); Drawable pressedIcon = new BitmapDrawable(iconPressed); StateListDrawable states = new StateListDrawable(); states.addState(new int[] {android.R.attr.state_pressed}, pressedIcon); states.addState(new int[] {android.R.attr.state_focused}, pressedIcon); states.addState(new int[] { }, icon); view.setImageDrawable(states); } public static void requestPermission(final Activity activity, final String[] permissions, final int requestCode) { new AlertDialog.Builder(activity) .setTitle(Common.XGELS_CONTEXT.getResources().getString(R.string.alert_grant_permission_title)) .setMessage(Common.XGELS_CONTEXT.getResources().getString(R.string.alert_grant_permission_summary)) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(activity, permissions, requestCode); dialog.cancel(); } }).show(); } }