Omnilib: Import omni utils
Change-Id: Ic1a25aaa2b2be77ff0d9f03798e80ebca4a8f620
diff --git a/src/org/omnirom/omnilib/utils/DeviceKeyHandler.java b/src/org/omnirom/omnilib/utils/DeviceKeyHandler.java
new file mode 100644
index 0000000..699ea76
--- /dev/null
+++ b/src/org/omnirom/omnilib/utils/DeviceKeyHandler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ * Copyright (C) 2015-2021 The OmniROM 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.omnirom.omnilib.utils;
+
+import android.content.Intent;
+import android.hardware.SensorEvent;
+import android.view.KeyEvent;
+
+public interface DeviceKeyHandler {
+
+ /**
+ * Invoked when an unknown key was detected by the system, letting the device handle
+ * this special keys prior to pass the key to the active app.
+ *
+ * @param event The key event to be handled
+ * @return If the event is consume
+ */
+ public boolean handleKeyEvent(KeyEvent event);
+
+ /**
+ * Invoked when an unknown key was detected by the system,
+ * this should NOT handle the key just return if it WOULD be handled
+ *
+ * @param event The key event to be handled
+ * @return If the event will be consumed
+ */
+ public boolean canHandleKeyEvent(KeyEvent event);
+
+ /**
+ * Special key event that should be treated as
+ * a camera launch event
+ *
+ * @param event The key event to be handled
+ * @return If the event is a camera launch event
+ */
+ public boolean isCameraLaunchEvent(KeyEvent event);
+
+ /**
+ * Special key event that should be treated as
+ * a wake event
+ *
+ * @param event The key event to be handled
+ * @return If the event is a wake event
+ */
+ public boolean isWakeEvent(KeyEvent event);
+
+ /**
+ * Return false if this event should be ignored
+ *
+ * @param event The key event to be handled
+ * @return If the event should be ignored
+ */
+ public boolean isDisabledKeyEvent(KeyEvent event);
+
+ /**
+ * Return an Intent that should be launched for that KeyEvent
+ *
+ * @param event The key event to be handled
+ * @return an Intent or null
+ */
+ public Intent isActivityLaunchEvent(KeyEvent event);
+
+ default public String getCustomProxiSensor() {
+ return null;
+ }
+
+ default public boolean getCustomProxiIsNear(SensorEvent event) {
+ return false;
+ }
+}
diff --git a/src/org/omnirom/omnilib/utils/DeviceUtils.java b/src/org/omnirom/omnilib/utils/DeviceUtils.java
new file mode 100644
index 0000000..5c1188c
--- /dev/null
+++ b/src/org/omnirom/omnilib/utils/DeviceUtils.java
@@ -0,0 +1,135 @@
+/*
+* Copyright (C) 2014-2021 The OmniROM 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.omnirom.omnilib.utils;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.SensorManager;
+import android.net.ConnectivityManager;
+import android.nfc.NfcAdapter;
+import android.os.SystemProperties;
+import android.os.Vibrator;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.DisplayMetrics;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+import android.provider.Settings;
+
+import com.android.internal.telephony.PhoneConstants;
+import static android.hardware.Sensor.TYPE_LIGHT;
+import static android.hardware.Sensor.TYPE_PROXIMITY;
+
+import java.util.List;
+
+public class DeviceUtils {
+
+ // Device types
+ public static final int DEVICE_PHONE = 0;
+ public static final int DEVICE_HYBRID = 1;
+ public static final int DEVICE_TABLET = 2;
+
+ public static boolean deviceSupportsNfc(Context context) {
+ return (NfcAdapter.getDefaultAdapter(context) != null) ||
+ context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
+ }
+
+ public static boolean deviceSupportsVibrator(Context ctx) {
+ Vibrator vibrator = (Vibrator) ctx.getSystemService(Context.VIBRATOR_SERVICE);
+ return vibrator.hasVibrator();
+ }
+
+ public static boolean deviceSupportsProximitySensor(Context context) {
+ SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ return sm.getDefaultSensor(TYPE_PROXIMITY) != null;
+ }
+
+ public static boolean deviceSupportsLightSensor(Context context) {
+ SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ return sm.getDefaultSensor(TYPE_LIGHT) != null;
+ }
+
+ public static boolean deviceSupportNavigationBar(Context context) {
+ return deviceSupportNavigationBarForUser(context, UserHandle.USER_CURRENT);
+ }
+
+ public static boolean deviceSupportNavigationBarForUser(Context context, int userId) {
+ final boolean showByDefault = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_showNavigationBar);
+ final int hasNavigationBar = Settings.System.getIntForUser(
+ context.getContentResolver(),
+ Settings.System.OMNI_NAVIGATION_BAR_SHOW, -1, userId);
+ //final int hasNavigationBar = -1;
+ if (hasNavigationBar == -1) {
+ String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ return false;
+ } else if ("0".equals(navBarOverride)) {
+ return true;
+ } else {
+ return showByDefault;
+ }
+ } else {
+ return hasNavigationBar == 1;
+ }
+ }
+
+ private static int getScreenType(Context con) {
+ WindowManager wm = (WindowManager)con.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) {
+ return DEVICE_PHONE;
+ } else if (shortSizeDp < 720) {
+ return DEVICE_HYBRID;
+ } else {
+ return DEVICE_TABLET;
+ }
+ }
+
+ public static boolean isPhone(Context con) {
+ return getScreenType(con) == DEVICE_PHONE;
+ }
+
+ public static boolean isHybrid(Context con) {
+ return getScreenType(con) == DEVICE_HYBRID;
+ }
+
+ public static boolean isTablet(Context con) {
+ return getScreenType(con) == DEVICE_TABLET;
+ }
+
+ public static boolean isLandscapePhone(Context context) {
+ Configuration config = context.getResources().getConfiguration();
+ return config.orientation == Configuration.ORIENTATION_LANDSCAPE
+ && config.smallestScreenWidthDp < 600;
+ }
+
+ public static boolean isDataEncrypted() {
+ String voldState = SystemProperties.get("vold.decrypt");
+ return "1".equals(voldState) || "trigger_restart_min_framework".equals(voldState);
+ }
+}
diff --git a/src/org/omnirom/omnilib/utils/OmniServiceLocator.java b/src/org/omnirom/omnilib/utils/OmniServiceLocator.java
index 4348751..db1736d 100644
--- a/src/org/omnirom/omnilib/utils/OmniServiceLocator.java
+++ b/src/org/omnirom/omnilib/utils/OmniServiceLocator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The OmniROM Project
+ * Copyright (C) 2021 The OmniROM Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/org/omnirom/omnilib/utils/OmniUtils.java b/src/org/omnirom/omnilib/utils/OmniUtils.java
new file mode 100644
index 0000000..a144532
--- /dev/null
+++ b/src/org/omnirom/omnilib/utils/OmniUtils.java
@@ -0,0 +1,161 @@
+/*
+* Copyright (C) 2017-2021 The OmniROM Project
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.omnirom.omnilib.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Vibrator;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+public class OmniUtils {
+ /**
+ * @hide
+ */
+ public static final String OMNILIB_PACKAGE_NAME = "org.omnirom.omnilib";
+
+ /**
+ * @hide
+ */
+ public static final String ACTION_DISMISS_KEYGUARD = OMNILIB_PACKAGE_NAME +".ACTION_DISMISS_KEYGUARD";
+
+ /**
+ * @hide
+ */
+ public static final String DISMISS_KEYGUARD_EXTRA_INTENT = "launch";
+
+ /**
+ * @hide
+ */
+ public static void launchKeyguardDismissIntent(Context context, UserHandle user, Intent launchIntent) {
+ Intent keyguardIntent = new Intent(ACTION_DISMISS_KEYGUARD);
+ keyguardIntent.setPackage(OMNILIB_PACKAGE_NAME);
+ keyguardIntent.putExtra(DISMISS_KEYGUARD_EXTRA_INTENT, launchIntent);
+ context.sendBroadcastAsUser(keyguardIntent, user);
+ }
+
+ /**
+ * @hide
+ */
+ public static void sendKeycode(int keycode) {
+ sendKeycode(keycode, false);
+ }
+
+ /**
+ * @hide
+ */
+ public static void sendKeycode(int keycode, boolean longpress) {
+ long when = SystemClock.uptimeMillis();
+ final KeyEvent evDown = new KeyEvent(when, when, KeyEvent.ACTION_DOWN, keycode, 0,
+ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_FROM_SYSTEM,
+ InputDevice.SOURCE_KEYBOARD);
+ final KeyEvent evUp = KeyEvent.changeAction(evDown, KeyEvent.ACTION_UP);
+
+ final Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ InputManager.getInstance().injectInputEvent(evDown,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
+ });
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ InputManager.getInstance().injectInputEvent(evUp,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
+ }, longpress ? 750 : 20);
+ }
+
+ public static void goToSleep(Context context) {
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ if(pm != null) {
+ pm.goToSleep(SystemClock.uptimeMillis());
+ }
+ }
+
+ /* e.g.
+ <integer-array name="config_defaultNotificationVibePattern">
+ <item>0</item>
+ <item>350</item>
+ <item>250</item>
+ <item>350</item>
+ </integer-array>
+ */
+ public static void vibrateResourcePattern(Context context, int resId) {
+ if (DeviceUtils.deviceSupportsVibrator(context)) {
+ int[] pattern = context.getResources().getIntArray(resId);
+ if (pattern == null) {
+ return;
+ }
+ long[] out = new long[pattern.length];
+ for (int i=0; i<pattern.length; i++) {
+ out[i] = pattern[i];
+ }
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(out, -1);
+ }
+ }
+
+ public static void vibratePattern(Context context, long[] pattern) {
+ if (DeviceUtils.deviceSupportsVibrator(context)) {
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(pattern, -1);
+ }
+ }
+
+ public static Bitmap scaleCenterInside(final Bitmap source, final int newWidth, final int newHeight) {
+ int sourceWidth = source.getWidth();
+ int sourceHeight = source.getHeight();
+
+ float widthRatio = (float) newWidth / sourceWidth;
+ float heightRatio = (float) newHeight / sourceHeight;
+ float ratio = Math.max(widthRatio, heightRatio);
+ float scaledWidth = sourceWidth * ratio;
+ float scaledHeight = sourceHeight * ratio;
+
+ //Bitmap scaled = Bitmap.createScaledBitmap(source, (int)scaledWidth, (int)scaledHeight, true);
+
+ RectF targetRect = null;
+ if (newWidth > newHeight) {
+ float inset = (scaledHeight - newHeight) / 2;
+ targetRect = new RectF(0, -inset, newWidth, newHeight + inset);
+ } else {
+ float inset = (scaledWidth - newWidth) / 2;
+ targetRect = new RectF(-inset, 0, newWidth + inset, newHeight);
+ }
+ Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
+ Canvas canvas = new Canvas(dest);
+ canvas.drawBitmap(source, null, targetRect, null);
+ return dest;
+ }
+}
diff --git a/src/org/omnirom/omnilib/utils/OmniVibe.java b/src/org/omnirom/omnilib/utils/OmniVibe.java
index 9c89597..c57fe27 100644
--- a/src/org/omnirom/omnilib/utils/OmniVibe.java
+++ b/src/org/omnirom/omnilib/utils/OmniVibe.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The OmniROM Project
+ * Copyright (C) 2021 The OmniROM Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,6 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.view.HapticFeedbackConstants;
-//import com.android.internal.util.omni.DeviceUtils;
public class OmniVibe{
diff --git a/src/org/omnirom/omnilib/utils/PackageUtils.java b/src/org/omnirom/omnilib/utils/PackageUtils.java
new file mode 100644
index 0000000..fb586a3
--- /dev/null
+++ b/src/org/omnirom/omnilib/utils/PackageUtils.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (C) 2014-2021 The OmniROM 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.omnirom.omnilib.utils;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+public class PackageUtils {
+
+ 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 boolean isAvailableApp(String packageName, Context context) {
+ Context mContext = context;
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
+ int enabled = pm.getApplicationEnabledSetting(packageName);
+ return enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED &&
+ enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/src/org/omnirom/omnilib/utils/SystemKeyEventHandler.java b/src/org/omnirom/omnilib/utils/SystemKeyEventHandler.java
new file mode 100644
index 0000000..2ba2bc0
--- /dev/null
+++ b/src/org/omnirom/omnilib/utils/SystemKeyEventHandler.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The OmniROM Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package org.omnirom.omnilib.utils;
+
+import android.os.Handler;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+public class SystemKeyEventHandler {
+ private static final String TAG = "SystemKeyEventHandler";
+ private static final boolean DEBUG = false;
+ private boolean mDoubleTapPending;
+ private boolean mKeyPressed;
+ private boolean mKeyConsumed;
+ private Runnable mPressedAction;
+ private Runnable mDoubleTapAction;
+ private Runnable mLongPressAction;
+
+ private final Runnable mDoubleTapTimeoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mDoubleTapPending) {
+ mDoubleTapPending = false;
+ if (mPressedAction != null) {
+ mPressedAction.run();
+ }
+ }
+ }
+ };
+
+ public SystemKeyEventHandler(Runnable pressedAction, Runnable doubleTapAction,
+ Runnable longPressAction) {
+ mPressedAction = pressedAction;
+ mDoubleTapAction = doubleTapAction;
+ mLongPressAction = longPressAction;
+ }
+
+ public int handleKeyEvent(Handler handler, KeyEvent event) {
+ final int repeatCount = event.getRepeatCount();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
+
+ if (DEBUG) {
+ Log.d(TAG, "handleKeyEvent " + event + " down = " + down + " repeatCount = " + repeatCount);
+ }
+ // If we have released the home key, and didn't do anything else
+ // while it was pressed, then it is time to go home!
+ if (!down) {
+ mKeyPressed = false;
+ if (mKeyConsumed) {
+ mKeyConsumed = false;
+ return -1;
+ }
+
+ if (canceled) {
+ return -1;
+ }
+
+ // Delay handling home if a double-tap is possible.
+ if (mDoubleTapAction != null) {
+ handler.removeCallbacks(mDoubleTapTimeoutRunnable); // just in case
+ mDoubleTapPending = true;
+ handler.postDelayed(mDoubleTapTimeoutRunnable,
+ ViewConfiguration.getDoubleTapTimeout());
+ return -1;
+ }
+
+ if (mPressedAction != null) {
+ // Post to main thread to avoid blocking input pipeline.
+ handler.post(() -> {
+ mPressedAction.run();
+ });
+ }
+ return -1;
+ }
+
+
+ if (repeatCount == 0) {
+ mKeyPressed = true;
+ if (mDoubleTapPending) {
+ mDoubleTapPending = false;
+ handler.removeCallbacks(mDoubleTapTimeoutRunnable);
+ handleDoubleTapOnKey();
+ }
+ } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ if (mLongPressAction != null) {
+ // Post to main thread to avoid blocking input pipeline.
+ handler.post(() -> {
+ mLongPressAction.run();
+ });
+ }
+ }
+ return -1;
+ }
+
+ private void handleDoubleTapOnKey() {
+ mKeyConsumed = true;
+ if (mDoubleTapAction != null) {
+ mDoubleTapAction.run();
+ }
+ }
+}