/* * Copyright (C) 2013 Peter Gregus for GravityBox Project (C3C076@xda) * 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 hello.dcsms.omzen.PowerMenu; import static de.robv.android.xposed.XposedHelpers.callStaticMethod; import static de.robv.android.xposed.XposedHelpers.findClass; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.os.Build; import android.os.Vibrator; import android.renderscript.Allocation; import android.renderscript.Allocation.MipmapControl; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; import android.telephony.TelephonyManager; import android.util.DisplayMetrics; import android.view.WindowManager; import de.robv.android.xposed.XposedBridge; public class Utils { private static final String TAG = "GB:Utils"; private static final boolean DEBUG = false; // Device types private static final int DEVICE_PHONE = 0; private static final int DEVICE_HYBRID = 1; private static final int DEVICE_TABLET = 2; // Device type reference private static int mDeviceType = -1; private static Boolean mIsMtkDevice = null; private static Boolean mIsXperiaDevice = null; private static Boolean mHasLenovoCustomUI = null; private static Boolean mHasLenovoVibeUI = null; private static Boolean mIsLenovoROW = null; private static Boolean mIsWifiOnly = null; private static String mDeviceCharacteristics = null; // Device features private static Boolean mHasGeminiSupport = null; private static Boolean mHasTelephonySupport = null; private static Boolean mHasVibrator = null; private static Boolean mHasFlash = null; private static Boolean mHasGPS = null; private static Boolean mHasNfc = null; // Supported MTK devices private static final Set<String> MTK_DEVICES = new HashSet<String>( Arrays.asList(new String[] { // Single-core SoC "mt6575", // Dual-core SoC "mt6572", "mt6577", "mt8377", // Quad-core SoC "mt6582", "mt6589", "mt8389", // Octa-core SoC "mt6592" })); private static void log(String message) { XposedBridge.log(TAG + ": " + message); } private static int getScreenType(Context con) { if (mDeviceType == -1) { WindowManager wm = (WindowManager) con .getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); int shortSize = Math.min(outMetrics.heightPixels, outMetrics.widthPixels); int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / outMetrics.densityDpi; if (shortSizeDp < 600) { // 0-599dp: "phone" UI with a separate status & navigation bar mDeviceType = DEVICE_PHONE; } else if (shortSizeDp < 720) { // 600-719dp: "phone" UI with modifications for larger screens mDeviceType = DEVICE_HYBRID; } else { // 720dp: "tablet" UI with a single combined status & navigation // bar mDeviceType = DEVICE_TABLET; } } return mDeviceType; } public static boolean isPhoneUI(Context con) { return getScreenType(con) == DEVICE_PHONE && !isTablet(); } public static boolean isHybridUI(Context con) { return getScreenType(con) == DEVICE_HYBRID; } public static boolean isTabletUI(Context con) { return getScreenType(con) == DEVICE_TABLET; } public static boolean isTablet() { String deviceCharacteristics = getDeviceCharacteristics(); return deviceCharacteristics != null && deviceCharacteristics .contains("tablet"); } public static enum MethodState { UNKNOWN, METHOD_ENTERED, METHOD_EXITED } public static boolean isMtkDevice() { if (mIsMtkDevice != null) return mIsMtkDevice; mIsMtkDevice = MTK_DEVICES.contains(Build.HARDWARE.toLowerCase()); return mIsMtkDevice; } public static boolean isMt65x2Device() { return Build.HARDWARE.toLowerCase().contains("mt6572") || Build.HARDWARE.toLowerCase().contains("mt6582") || Build.HARDWARE .toLowerCase().contains("mt6592"); } public static boolean isXperiaDevice() { if (mIsXperiaDevice != null) return mIsXperiaDevice; mIsXperiaDevice = Build.MANUFACTURER.equalsIgnoreCase("sony") && !isMtkDevice(); return mIsXperiaDevice; } public static boolean hasLenovoCustomUI() { if (mHasLenovoCustomUI != null) return mHasLenovoCustomUI; File f = new File("/system/framework/lenovo-res.apk"); mHasLenovoCustomUI = f.exists(); return mHasLenovoCustomUI; } public static boolean hasLenovoVibeUI() { if (mHasLenovoVibeUI != null) return mHasLenovoVibeUI; File f = new File("/system/framework/lenovosystemuiadapter.jar"); mHasLenovoVibeUI = hasLenovoCustomUI() && f.exists(); return mHasLenovoVibeUI; } public static boolean isLenovoROW() { // Lenovo releases ROW (Rest Of the World) firmware for European // versions of their devices if (mIsLenovoROW != null) return mIsLenovoROW; mIsLenovoROW = hasLenovoCustomUI() && SystemProp.get("ro.product.device").toUpperCase(Locale.US) .endsWith("_ROW"); return mIsLenovoROW; } public static boolean hasGeminiSupport() { if (mHasGeminiSupport != null) return mHasGeminiSupport; mHasGeminiSupport = SystemProp.getBoolean("ro.mediatek.gemini_support", false); return mHasGeminiSupport; } public static boolean isWifiOnly(Context con) { // returns true if device doesn't support mobile data (is wifi only) if (mIsWifiOnly != null) return mIsWifiOnly; try { ConnectivityManager cm = (ConnectivityManager) con .getSystemService(Context.CONNECTIVITY_SERVICE); mIsWifiOnly = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null; return mIsWifiOnly; } catch (Throwable t) { mIsWifiOnly = null; return false; } } // to be called from settings or other user activities public static boolean hasTelephonySupport(Context con) { // returns false if device has no phone radio (no telephony support) if (mHasTelephonySupport != null) return mHasTelephonySupport; try { TelephonyManager tm = (TelephonyManager) con .getSystemService(Context.TELEPHONY_SERVICE); mHasTelephonySupport = tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; return mHasTelephonySupport; } catch (Throwable t) { mHasTelephonySupport = null; return false; } } // to be called from system context only public static boolean hasTelephonySupport() { try { Resources res = Resources.getSystem(); return res.getBoolean(res.getIdentifier("config_voice_capable", "bool", "android")); } catch (Throwable t) { log("hasTelephonySupport(): " + t.getMessage()); return false; } } @SuppressLint("NewApi") public static boolean hasVibrator(Context con) { if (mHasVibrator != null) return mHasVibrator; try { Vibrator v = (Vibrator) con .getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = v.hasVibrator(); return mHasVibrator; } catch (Throwable t) { mHasVibrator = null; return false; } } public static boolean hasFlash(Context con) { if (mHasFlash != null) return mHasFlash; try { PackageManager pm = con.getPackageManager(); mHasFlash = pm .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); return mHasFlash; } catch (Throwable t) { mHasFlash = null; return false; } } public static boolean hasGPS(Context con) { if (mHasGPS != null) return mHasGPS; try { PackageManager pm = con.getPackageManager(); mHasGPS = pm.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS); return mHasGPS; } catch (Throwable t) { mHasGPS = null; return false; } } public static boolean hasNfc(Context con) { if (mHasNfc != null) return mHasNfc; try { PackageManager pm = con.getPackageManager(); mHasNfc = pm.hasSystemFeature(PackageManager.FEATURE_NFC); return mHasNfc; } catch (Throwable t) { mHasNfc = null; return false; } } public static String getDeviceCharacteristics() { if (mDeviceCharacteristics != null) return mDeviceCharacteristics; mDeviceCharacteristics = SystemProp.get("ro.build.characteristics"); return mDeviceCharacteristics; } public static boolean shouldAllowMoreVolumeSteps() { return !("GT-I9505G".equals(Build.MODEL) && !isMtkDevice()); } @SuppressLint("NewApi") public static String join(String[] stringArray, String separator) { String buf = ""; for (String s : stringArray) { if (!buf.isEmpty()) { buf += separator; } buf += s; } return buf; } public static boolean isAppInstalled(Context context, String appUri) { try { PackageManager pm = context.getPackageManager(); pm.getPackageInfo(appUri, PackageManager.GET_ACTIVITIES); return true; } catch (Exception e) { return false; } } public static void copyFile(File source, File dest) throws IOException { InputStream input = null; OutputStream output = null; try { input = new FileInputStream(source); output = new FileOutputStream(dest); byte[] buf = new byte[1024]; int bytesRead; while ((bytesRead = input.read(buf)) > 0) { output.write(buf, 0, bytesRead); } } finally { if (input != null) { input.close(); } if (output != null) { output.close(); } } } public static boolean writeAssetToFile(Context context, String assetName, File outFile) { try { AssetManager am = context.getAssets(); InputStream input = am.open(assetName); FileOutputStream output = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) > 0) { output.write(buffer, 0, len); } input.close(); output.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public static Bitmap drawableToBitmap(Drawable drawable) { if (drawable == null) return null; if (drawable instanceof BitmapDrawable) return ((BitmapDrawable) drawable).getBitmap(); int width = drawable.getIntrinsicWidth(); width = width > 0 ? width : 1; int height = drawable.getIntrinsicHeight(); height = height > 0 ? height : 1; Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } @SuppressLint("NewApi") public static Bitmap blurBitmap(Context context, Bitmap bmp) { return blurBitmap(context, bmp, 14); } @SuppressLint("NewApi") public static Bitmap blurBitmap(Context context, Bitmap bmp, float radius) { Bitmap out = Bitmap.createBitmap(bmp); RenderScript rs = RenderScript.create(context); radius = Math.min(Math.max(radius, 0), 25); Allocation input = Allocation.createFromBitmap(rs, bmp, MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); Allocation output = Allocation.createTyped(rs, input.getType()); ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); script.setInput(input); script.setRadius(radius); script.forEach(output); output.copyTo(out); rs.destroy(); return out; } @SuppressLint("UseSparseArrays") public static int getBitmapPredominantColor(Bitmap bmp) { int width = bmp.getWidth(); int height = bmp.getHeight(); int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); Map<Integer, Integer> tmpMap = new HashMap<Integer, Integer>(); for (int i = 0; i < pixels.length; i++) { Integer counter = tmpMap.get(pixels[i]); if (counter == null) { counter = 0; } counter++; tmpMap.put(pixels[i], counter); } Entry<Integer, Integer> maxEntry = null; for (Entry<Integer, Integer> entry : tmpMap.entrySet()) { // discard transparent pixels if (entry.getKey() == Color.TRANSPARENT) { continue; } if (maxEntry == null || entry.getValue() > maxEntry.getValue()) { maxEntry = entry; } } return maxEntry.getKey(); } public static void performSoftReboot() { try { SystemProp.set("ctl.restart", "surfaceflinger"); SystemProp.set("ctl.restart", "zygote"); } catch (Throwable t) { XposedBridge.log(t); } } public static String intArrayToString(int[] array) { String buf = "["; for (int i = 0; i < array.length; i++) { if (buf.length() > 1) { buf += ","; } buf += array[i]; } buf += "]"; return buf; } public static long[] csvToLongArray(String csv) throws Exception { String[] vals = csv.split(","); long[] arr = new long[vals.length]; for (int i = 0; i < arr.length; i++) { arr[i] = Long.valueOf(vals[i]); } return arr; } public static boolean isTimeOfDayInRange(long timeMs, int startMin, int endMin) { Calendar c = new GregorianCalendar(); c.setTimeInMillis(timeMs); int timeMin = c.get(Calendar.HOUR_OF_DAY) * 60 + c.get(Calendar.MINUTE); if (startMin == endMin) return false; else if (startMin > endMin) return timeMin >= startMin || timeMin < endMin; else return timeMin >= startMin && timeMin < endMin; } public static int alphaPercentToInt(int percentAlpha) { percentAlpha = Math.min(Math.max(percentAlpha, 0), 100); float alpha = percentAlpha / 100f; return alpha == 0 ? 255 : (int) (1 - alpha * 255); } static class SystemProp extends Utils { private SystemProp() { } // Get the value for the given key // @param key: key to lookup // @return null if the key isn't found public static String get(String key) { String ret; try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); ret = (String) callStaticMethod(classSystemProperties, "get", key); } catch (Throwable t) { log("SystemProp.get failed: " + t.getMessage()); ret = null; } return ret; } // Get the value for the given key // @param key: key to lookup // @param def: default value to return // @return if the key isn't found, return def if it isn't null, or an // empty string otherwise public static String get(String key, String def) { String ret = def; try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); ret = (String) callStaticMethod(classSystemProperties, "get", key, def); } catch (Throwable t) { log("SystemProp.get failed: " + t.getMessage()); ret = def; } return ret; } // Get the value for the given key, and return as an integer // @param key: key to lookup // @param def: default value to return // @return the key parsed as an integer, or def if the key isn't found // or cannot be parsed public static Integer getInt(String key, Integer def) { Integer ret = def; try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); ret = (Integer) callStaticMethod(classSystemProperties, "getInt", key, def); } catch (Throwable t) { log("SystemProp.getInt failed: " + t.getMessage()); ret = def; } return ret; } // Get the value for the given key, and return as a long // @param key: key to lookup // @param def: default value to return // @return the key parsed as a long, or def if the key isn't found or // cannot be parsed public static Long getLong(String key, Long def) { Long ret = def; try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); ret = (Long) callStaticMethod(classSystemProperties, "getLong", key, def); } catch (Throwable t) { log("SystemProp.getLong failed: " + t.getMessage()); ret = def; } return ret; } // Get the value (case insensitive) for the given key, returned as a // boolean // Values 'n', 'no', '0', 'false' or 'off' are considered false // Values 'y', 'yes', '1', 'true' or 'on' are considered true // If the key does not exist, or has any other value, then the default // result is returned // @param key: key to lookup // @param def: default value to return // @return the key parsed as a boolean, or def if the key isn't found or // cannot be parsed public static Boolean getBoolean(String key, boolean def) { Boolean ret = def; try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); ret = (Boolean) callStaticMethod(classSystemProperties, "getBoolean", key, def); } catch (Throwable t) { log("SystemProp.getBoolean failed: " + t.getMessage()); ret = def; } return ret; } // Set the value for the given key public static void set(String key, String val) { try { Class<?> classSystemProperties = findClass( "android.os.SystemProperties", null); callStaticMethod(classSystemProperties, "set", key, val); } catch (Throwable t) { log("SystemProp.set failed: " + t.getMessage()); } } } }