lineage-compat: Import all utility classes from lineage-sdk

* Most device modules like doze only depend on these
* Exclude ActionUtils, DeviceKeyConstants, LineageLockPatternUtils, PowerMenuUtils

Change-Id: Id9b5e3d81bd4ac00dbe8a3c5beb8b7373bbc4774
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..40a1d2a
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2022 The LeafOS Project
+//
+// 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.
+//
+
+java_library {
+    name: "org.lineageos.platform.internal",
+
+    srcs: ["src/**/*.java"],
+}
diff --git a/src/org/lineageos/internal/util/FileUtils.java b/src/org/lineageos/internal/util/FileUtils.java
new file mode 100644
index 0000000..efe6071
--- /dev/null
+++ b/src/org/lineageos/internal/util/FileUtils.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * 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 org.lineageos.internal.util;
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public final class FileUtils {
+    private static final String TAG = "FileUtils";
+
+    private FileUtils() {
+        // This class is not supposed to be instantiated
+    }
+
+    /**
+     * Reads the first line of text from the given file.
+     * Reference {@link BufferedReader#readLine()} for clarification on what a line is
+     *
+     * @return the read line contents, or null on failure
+     */
+    public static String readOneLine(String fileName) {
+        String line = null;
+        BufferedReader reader = null;
+
+        try {
+            reader = new BufferedReader(new FileReader(fileName), 512);
+            line = reader.readLine();
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "No such file " + fileName + " for reading", e);
+        } catch (IOException e) {
+            Log.e(TAG, "Could not read from file " + fileName, e);
+        } finally {
+            try {
+                if (reader != null) {
+                    reader.close();
+                }
+            } catch (IOException e) {
+                // Ignored, not much we can do anyway
+            }
+        }
+
+        return line;
+    }
+
+    /**
+     * Writes the given value into the given file
+     *
+     * @return true on success, false on failure
+     */
+    public static boolean writeLine(String fileName, String value) {
+        BufferedWriter writer = null;
+
+        try {
+            writer = new BufferedWriter(new FileWriter(fileName));
+            writer.write(value);
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "No such file " + fileName + " for writing", e);
+            return false;
+        } catch (IOException e) {
+            Log.e(TAG, "Could not write to file " + fileName, e);
+            return false;
+        } finally {
+            try {
+                if (writer != null) {
+                    writer.close();
+                }
+            } catch (IOException e) {
+                // Ignored, not much we can do anyway
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Checks whether the given file exists
+     *
+     * @return true if exists, false if not
+     */
+    public static boolean fileExists(String fileName) {
+        final File file = new File(fileName);
+        return file.exists();
+    }
+
+    /**
+     * Checks whether the given file is readable
+     *
+     * @return true if readable, false if not
+     */
+    public static boolean isFileReadable(String fileName) {
+        final File file = new File(fileName);
+        return file.exists() && file.canRead();
+    }
+
+    /**
+     * Checks whether the given file is writable
+     *
+     * @return true if writable, false if not
+     */
+    public static boolean isFileWritable(String fileName) {
+        final File file = new File(fileName);
+        return file.exists() && file.canWrite();
+    }
+
+    /**
+     * Deletes an existing file
+     *
+     * @return true if the delete was successful, false if not
+     */
+    public static boolean delete(String fileName) {
+        final File file = new File(fileName);
+        boolean ok = false;
+        try {
+            ok = file.delete();
+        } catch (SecurityException e) {
+            Log.w(TAG, "SecurityException trying to delete " + fileName, e);
+        }
+        return ok;
+    }
+
+    /**
+     * Renames an existing file
+     *
+     * @return true if the rename was successful, false if not
+     */
+    public static boolean rename(String srcPath, String dstPath) {
+        final File srcFile = new File(srcPath);
+        final File dstFile = new File(dstPath);
+        boolean ok = false;
+        try {
+            ok = srcFile.renameTo(dstFile);
+        } catch (SecurityException e) {
+            Log.w(TAG, "SecurityException trying to rename " + srcPath + " to " + dstPath, e);
+        } catch (NullPointerException e) {
+            Log.e(TAG, "NullPointerException trying to rename " + srcPath + " to " + dstPath, e);
+        }
+        return ok;
+    }
+}
diff --git a/src/org/lineageos/internal/util/ImageUtils.java b/src/org/lineageos/internal/util/ImageUtils.java
new file mode 100644
index 0000000..5b5567a
--- /dev/null
+++ b/src/org/lineageos/internal/util/ImageUtils.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013-2014 The CyanogenMod Project
+ *
+ * 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 org.lineageos.internal.util;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.util.Log;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+public class ImageUtils {
+    private static final String TAG = ImageUtils.class.getSimpleName();
+
+    private static final String ASSET_URI_PREFIX = "file:///android_asset/";
+    private static final int DEFAULT_IMG_QUALITY = 100;
+
+    /**
+     * Gets the Width and Height of the image
+     *
+     * @param inputStream The input stream of the image
+     *
+     * @return A point structure that holds the Width and Height (x and y)/*"
+     */
+    public static Point getImageDimension(InputStream inputStream) {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("'inputStream' cannot be null!");
+        }
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeStream(inputStream, null, options);
+        Point point = new Point(options.outWidth,options.outHeight);
+        return point;
+    }
+
+    /**
+     * Crops the input image and returns a new InputStream of the cropped area
+     *
+     * @param inputStream The input stream of the image
+     * @param imageWidth Width of the input image
+     * @param imageHeight Height of the input image
+     * @param inputStream Desired Width
+     * @param inputStream Desired Width
+     *
+     * @return a new InputStream of the cropped area/*"
+     */
+    public static InputStream cropImage(InputStream inputStream, int imageWidth, int imageHeight,
+            int outWidth, int outHeight) throws IllegalArgumentException {
+        if (inputStream == null){
+            throw new IllegalArgumentException("inputStream cannot be null");
+        }
+
+        if (imageWidth <= 0 || imageHeight <= 0) {
+            throw new IllegalArgumentException(
+                    String.format("imageWidth and imageHeight must be > 0: imageWidth=%d" +
+                            " imageHeight=%d", imageWidth, imageHeight));
+        }
+
+        if (outWidth <= 0 || outHeight <= 0) {
+            throw new IllegalArgumentException(
+                    String.format("outWidth and outHeight must be > 0: outWidth=%d" +
+                            " outHeight=%d", imageWidth, outHeight));
+        }
+
+        int scaleDownSampleSize = Math.min(imageWidth / outWidth, imageHeight / outHeight);
+        if (scaleDownSampleSize > 0) {
+            imageWidth /= scaleDownSampleSize;
+            imageHeight /= scaleDownSampleSize;
+        } else {
+            float ratio = (float) outWidth / outHeight;
+            if (imageWidth < imageHeight * ratio) {
+                outWidth = imageWidth;
+                outHeight = (int) (outWidth / ratio);
+            } else {
+                outHeight = imageHeight;
+                outWidth = (int) (outHeight * ratio);
+            }
+        }
+        int left = (imageWidth - outWidth) / 2;
+        int top = (imageHeight - outHeight) / 2;
+        InputStream compressed = null;
+        try {
+            BitmapFactory.Options options = new BitmapFactory.Options();
+            if (scaleDownSampleSize > 1) {
+                options.inSampleSize = scaleDownSampleSize;
+            }
+            Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
+            if (bitmap == null) {
+                return null;
+            }
+            Bitmap cropped = Bitmap.createBitmap(bitmap, left, top, outWidth, outHeight);
+            ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+            if (cropped.compress(Bitmap.CompressFormat.PNG, DEFAULT_IMG_QUALITY, tmpOut)) {
+                byte[] outByteArray = tmpOut.toByteArray();
+                compressed = new ByteArrayInputStream(outByteArray);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Exception " + e);
+        }
+        return compressed;
+    }
+}
diff --git a/src/org/lineageos/internal/util/MathUtils.java b/src/org/lineageos/internal/util/MathUtils.java
new file mode 100644
index 0000000..d4a2639
--- /dev/null
+++ b/src/org/lineageos/internal/util/MathUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * 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 org.lineageos.internal.util;
+
+public final class MathUtils {
+
+    /**
+     * Given a range of values which change continuously in a non-linear way,
+     * we can map back and forth to a linear scale using some quadratic equations.
+     *
+     * The linear scale ranges from 0 -> 1. This method will calculate the
+     * coefficients needed to solve the conversion functions in the next two methods.
+     *
+     * lower = actual value when linear value = 0
+     * mid = actual value when linear value = .5
+     * upper actual value when linear value = 1
+     *
+     * @param lower
+     * @param mid
+     * @param upper
+     * @return array of coefficients
+     */
+    public static double[] powerCurve(double lower, double mid, double upper) {
+        final double[] curve = new double[3];
+        curve[0] = ((lower * upper) - (mid * mid)) / (lower - (2 * mid) + upper);
+        curve[1] = Math.pow((mid - lower), 2) / (lower - (2 * mid) + upper);
+        curve[2] = 2 * Math.log((upper - mid) / (mid - lower));
+        return curve;
+    }
+
+    /**
+     * Map a value on a power curve to a linear value
+     *
+     * @param curve obtained from powerCurve()
+     * @param value to convert to linear scale
+     * @return linear value from 0 -> 1
+     */
+    public static double powerCurveToLinear(final double[] curve, double value) {
+        return Math.log((value - curve[0]) / curve[1]) / curve[2];
+    }
+
+    /**
+     * Map a value on a linear scale to a value on a power curve
+     *
+     * @param curve obtained from powerCurve()
+     * @param value from 0 -> 1 to map onto power curve
+     * @return actual value on the given curve
+     */
+    public static double linearToPowerCurve(final double[] curve, double value) {
+        return curve[0] + curve[1] * Math.exp(curve[2] * value);
+    }
+
+
+}
diff --git a/src/org/lineageos/internal/util/PackageManagerUtils.java b/src/org/lineageos/internal/util/PackageManagerUtils.java
new file mode 100644
index 0000000..075dd5c
--- /dev/null
+++ b/src/org/lineageos/internal/util/PackageManagerUtils.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * 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 org.lineageos.internal.util;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+public final class PackageManagerUtils {
+    private static final int FLAG_SUSPENDED = 1 << 30;
+
+    private PackageManagerUtils() {
+        // This class is not supposed to be instantiated
+    }
+
+    /**
+     * Checks whether a given package exists
+     *
+     * @param context
+     * @param packageName
+     * @return true if the package exists
+     */
+    public static boolean isAppInstalled(final Context context, final String packageName) {
+        return getApplicationInfo(context, packageName, 0) != null;
+    }
+
+    /**
+     * Check whether a package with specific flags is enabled
+     *
+     * @param context
+     * @param packageName
+     * @param flags
+     * @return true if the package is enabled
+     */
+    public static boolean isAppEnabled(final Context context,
+                                       final String packageName, final int flags) {
+        final ApplicationInfo info = getApplicationInfo(context, packageName, flags);
+        return info != null && info.enabled;
+    }
+
+    /**
+     * Check whether a package is enabled
+     *
+     * @param context
+     * @param packageName
+     * @return true if the package is enabled
+     */
+    public static boolean isAppEnabled(final Context context, final String packageName) {
+        return isAppEnabled(context, packageName, 0);
+    }
+
+    /**
+     * Check if a package can possibly be on the SDCard
+     * This is just a workaround and doesn't guarantee that the app is on SD card
+     *
+     * @param context
+     * @param packageName
+     * @return true if the package is on the SDCard
+     */
+    public static boolean isAppOnSdcard(final Context context, final String packageName) {
+        return isAppEnabled(context, packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+    }
+
+    /**
+     * Check if a package is suspended
+     *
+     * @param context
+     * @param packageName
+     * @return true if the package is suspended
+     */
+    public static boolean isAppSuspended(final Context context, final String packageName) {
+        return isAppSuspended(getApplicationInfo(context, packageName, 0));
+    }
+
+    /**
+     * Check if a package is suspended
+     *
+     * @param info
+     * @return true if the package is suspended
+     */
+    public static boolean isAppSuspended(final ApplicationInfo info) {
+        return info != null && (info.flags & FLAG_SUSPENDED) != 0;
+    }
+
+    /**
+     * Get the ApplicationInfo of a package
+     *
+     * @param context
+     * @param packageName
+     * @param flags
+     * @return null if the package cannot be found or the ApplicationInfo is null
+     */
+    public static ApplicationInfo getApplicationInfo(final Context context,
+                                                     final String packageName, final int flags) {
+        final PackageManager packageManager = context.getPackageManager();
+        ApplicationInfo info;
+        try {
+            info = packageManager.getApplicationInfo(packageName, flags);
+        } catch (PackageManager.NameNotFoundException e) {
+            info = null;
+        }
+        return info;
+    }
+}
diff --git a/src/org/lineageos/internal/util/PowerMenuConstants.java b/src/org/lineageos/internal/util/PowerMenuConstants.java
new file mode 100644
index 0000000..b04deb2
--- /dev/null
+++ b/src/org/lineageos/internal/util/PowerMenuConstants.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ * Copyright (C) 2017-2022 The LineageOS Project
+ *
+ * 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 org.lineageos.internal.util;
+
+/* Master list of all actions for the power menu */
+public class PowerMenuConstants {
+    public static final String GLOBAL_ACTION_KEY_POWER = "power";
+    public static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+    public static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
+    public static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+    public static final String GLOBAL_ACTION_KEY_USERS = "users";
+    public static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+    public static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+    public static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+    public static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+    public static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+    public static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
+    public static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
+    public static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
+    public static final String GLOBAL_ACTION_KEY_DEVICECONTROLS = "devicecontrols";
+
+    /**
+     * Advanced restart menu actions
+     */
+    public static final String GLOBAL_ACTION_KEY_RESTART_RECOVERY = "restart_recovery";
+    public static final String GLOBAL_ACTION_KEY_RESTART_BOOTLOADER = "restart_bootloader";
+    public static final String GLOBAL_ACTION_KEY_RESTART_DOWNLOAD = "restart_download";
+    public static final String GLOBAL_ACTION_KEY_RESTART_FASTBOOT = "restart_fastboot";
+
+    private static String[] ALL_ACTIONS = {
+        GLOBAL_ACTION_KEY_EMERGENCY,
+        GLOBAL_ACTION_KEY_LOCKDOWN,
+        GLOBAL_ACTION_KEY_POWER,
+        GLOBAL_ACTION_KEY_RESTART,
+        GLOBAL_ACTION_KEY_SCREENSHOT,
+        GLOBAL_ACTION_KEY_AIRPLANE,
+        GLOBAL_ACTION_KEY_USERS,
+        GLOBAL_ACTION_KEY_SETTINGS,
+        GLOBAL_ACTION_KEY_BUGREPORT,
+        GLOBAL_ACTION_KEY_SILENT,
+        GLOBAL_ACTION_KEY_VOICEASSIST,
+        GLOBAL_ACTION_KEY_ASSIST,
+        GLOBAL_ACTION_KEY_DEVICECONTROLS,
+        GLOBAL_ACTION_KEY_LOGOUT,
+    };
+
+    public static String[] getAllActions() {
+        return ALL_ACTIONS;
+    }
+}
diff --git a/src/org/lineageos/internal/util/ScreenType.java b/src/org/lineageos/internal/util/ScreenType.java
new file mode 100644
index 0000000..d1729f1
--- /dev/null
+++ b/src/org/lineageos/internal/util/ScreenType.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ *
+ * 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 org.lineageos.internal.util;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+public class ScreenType {
+    // Device type reference
+    private static int sDeviceType = -1;
+
+    // Device types
+    private static final int DEVICE_PHONE = 0;
+    private static final int DEVICE_HYBRID = 1;
+    private static final int DEVICE_TABLET = 2;
+
+    private static int getScreenType(Context context) {
+        if (sDeviceType == -1) {
+            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+            DisplayInfo outDisplayInfo = new DisplayInfo();
+            wm.getDefaultDisplay().getDisplayInfo(outDisplayInfo);
+            int shortSize = Math.min(outDisplayInfo.logicalHeight, outDisplayInfo.logicalWidth);
+            int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT
+                    / outDisplayInfo.logicalDensityDpi;
+            if (shortSizeDp < 600) {
+                // 0-599dp: "phone" UI with a separate status & navigation bar
+                sDeviceType =  DEVICE_PHONE;
+            } else if (shortSizeDp < 720) {
+                // 600-719dp: "phone" UI with modifications for larger screens
+                sDeviceType = DEVICE_HYBRID;
+            } else {
+                // 720dp: "tablet" UI with a single combined status & navigation bar
+                sDeviceType = DEVICE_TABLET;
+            }
+        }
+        return sDeviceType;
+    }
+
+    public static boolean isPhone(Context context) {
+        return getScreenType(context) == DEVICE_PHONE;
+    }
+
+    public static boolean isHybrid(Context context) {
+        return getScreenType(context) == DEVICE_HYBRID;
+    }
+
+    public static boolean isTablet(Context context) {
+        return getScreenType(context) == DEVICE_TABLET;
+    }
+}