2019-12-31 18:19:35 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 The Android Open Source Project
|
2023-10-17 13:44:01 +02:00
|
|
|
* modified
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
2019-12-31 18:19:35 +01:00
|
|
|
*/
|
|
|
|
|
2024-01-31 18:32:43 +01:00
|
|
|
package helium314.keyboard.latin.utils;
|
2019-12-31 18:19:35 +01:00
|
|
|
|
2025-04-11 01:55:17 +03:00
|
|
|
import java.util.function.BiFunction;
|
|
|
|
|
|
|
|
import android.annotation.SuppressLint;
|
2025-01-07 20:38:03 +01:00
|
|
|
import android.content.Context;
|
2023-09-12 14:21:40 +02:00
|
|
|
import android.content.res.Configuration;
|
2019-12-31 18:19:35 +01:00
|
|
|
import android.content.res.Resources;
|
|
|
|
import android.content.res.TypedArray;
|
2025-01-07 20:38:03 +01:00
|
|
|
import android.graphics.Insets;
|
|
|
|
import android.graphics.Rect;
|
|
|
|
import android.os.Build;
|
2019-12-31 18:19:35 +01:00
|
|
|
import android.util.DisplayMetrics;
|
|
|
|
import android.util.TypedValue;
|
2025-01-07 20:38:03 +01:00
|
|
|
import android.view.WindowInsets;
|
|
|
|
import android.view.WindowManager;
|
|
|
|
import android.view.WindowMetrics;
|
2019-12-31 18:19:35 +01:00
|
|
|
|
2025-04-11 01:55:17 +03:00
|
|
|
import androidx.annotation.RequiresApi;
|
2024-01-31 18:32:43 +01:00
|
|
|
import helium314.keyboard.latin.R;
|
|
|
|
import helium314.keyboard.latin.settings.SettingsValues;
|
2019-12-31 18:19:35 +01:00
|
|
|
|
|
|
|
public final class ResourceUtils {
|
|
|
|
|
|
|
|
public static final float UNDEFINED_RATIO = -1.0f;
|
|
|
|
public static final int UNDEFINED_DIMENSION = -1;
|
|
|
|
|
|
|
|
private ResourceUtils() {
|
|
|
|
// This utility class is not publicly instantiable.
|
|
|
|
}
|
|
|
|
|
2025-01-07 20:38:03 +01:00
|
|
|
public static int getKeyboardWidth(final Context ctx, final SettingsValues settingsValues) {
|
|
|
|
final int defaultKeyboardWidth = getDefaultKeyboardWidth(ctx);
|
2022-02-20 16:14:12 +01:00
|
|
|
if (settingsValues.mOneHandedModeEnabled) {
|
2023-12-18 17:30:53 +01:00
|
|
|
return (int) (settingsValues.mOneHandedModeScale * defaultKeyboardWidth);
|
2022-02-20 16:14:12 +01:00
|
|
|
}
|
|
|
|
return defaultKeyboardWidth;
|
|
|
|
}
|
|
|
|
|
2025-01-07 20:38:03 +01:00
|
|
|
public static int getDefaultKeyboardWidth(final Context ctx) {
|
|
|
|
if (Build.VERSION.SDK_INT < 35) {
|
|
|
|
final DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
|
|
|
|
return dm.widthPixels;
|
|
|
|
}
|
|
|
|
// Since Android 15, insets aren't subtracted from DisplayMetrics.widthPixels, despite
|
|
|
|
// targetSdk remaining set to 30.
|
|
|
|
WindowManager wm = ctx.getSystemService(WindowManager.class);
|
|
|
|
WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
|
|
|
|
Rect windowBounds = windowMetrics.getBounds();
|
|
|
|
WindowInsets windowInsets = windowMetrics.getWindowInsets();
|
|
|
|
int insetTypes = WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout();
|
|
|
|
Insets insets = windowInsets.getInsetsIgnoringVisibility(insetTypes);
|
|
|
|
return windowBounds.width() - insets.left - insets.right;
|
2019-12-31 18:19:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public static int getKeyboardHeight(final Resources res, final SettingsValues settingsValues) {
|
2023-12-18 17:30:53 +01:00
|
|
|
final int defaultKeyboardHeight = getDefaultKeyboardHeight(res, settingsValues.mShowsNumberRow);
|
2023-09-06 15:45:41 +02:00
|
|
|
// mKeyboardHeightScale Ranges from [.5,1.5], from xml/prefs_screen_appearance.xml
|
|
|
|
return (int)(defaultKeyboardHeight * settingsValues.mKeyboardHeightScale);
|
2019-12-31 18:19:35 +01:00
|
|
|
}
|
|
|
|
|
2023-12-20 19:46:18 +01:00
|
|
|
public static int getDefaultKeyboardHeight(final Resources res, final boolean showsNumberRow) {
|
2019-12-31 18:19:35 +01:00
|
|
|
final DisplayMetrics dm = res.getDisplayMetrics();
|
2023-12-30 23:38:48 +01:00
|
|
|
final float keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height) * (showsNumberRow ? 1.33f : 1f);
|
2019-12-31 18:19:35 +01:00
|
|
|
final float maxKeyboardHeight = res.getFraction(
|
|
|
|
R.fraction.config_max_keyboard_height, dm.heightPixels, dm.heightPixels);
|
|
|
|
float minKeyboardHeight = res.getFraction(
|
|
|
|
R.fraction.config_min_keyboard_height, dm.heightPixels, dm.heightPixels);
|
|
|
|
if (minKeyboardHeight < 0.0f) {
|
|
|
|
// Specified fraction was negative, so it should be calculated against display
|
|
|
|
// width.
|
|
|
|
minKeyboardHeight = -res.getFraction(
|
|
|
|
R.fraction.config_min_keyboard_height, dm.widthPixels, dm.widthPixels);
|
|
|
|
}
|
|
|
|
// Keyboard height will not exceed maxKeyboardHeight and will not be less than
|
|
|
|
// minKeyboardHeight.
|
|
|
|
return (int)Math.max(Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isValidFraction(final float fraction) {
|
|
|
|
return fraction >= 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// {@link Resources#getDimensionPixelSize(int)} returns at least one pixel size.
|
|
|
|
public static boolean isValidDimensionPixelSize(final int dimension) {
|
|
|
|
return dimension > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static float getFraction(final TypedArray a, final int index, final float defValue) {
|
|
|
|
final TypedValue value = a.peekValue(index);
|
|
|
|
if (value == null || !isFractionValue(value)) {
|
|
|
|
return defValue;
|
|
|
|
}
|
|
|
|
return a.getFraction(index, 1, 1, defValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static float getFraction(final TypedArray a, final int index) {
|
|
|
|
return getFraction(a, index, UNDEFINED_RATIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int getDimensionPixelSize(final TypedArray a, final int index) {
|
|
|
|
final TypedValue value = a.peekValue(index);
|
|
|
|
if (value == null || !isDimensionValue(value)) {
|
|
|
|
return ResourceUtils.UNDEFINED_DIMENSION;
|
|
|
|
}
|
|
|
|
return a.getDimensionPixelSize(index, ResourceUtils.UNDEFINED_DIMENSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static float getDimensionOrFraction(final TypedArray a, final int index, final int base,
|
|
|
|
final float defValue) {
|
|
|
|
final TypedValue value = a.peekValue(index);
|
|
|
|
if (value == null) {
|
|
|
|
return defValue;
|
|
|
|
}
|
|
|
|
if (isFractionValue(value)) {
|
|
|
|
return a.getFraction(index, base, base, defValue);
|
|
|
|
} else if (isDimensionValue(value)) {
|
|
|
|
return a.getDimension(index, defValue);
|
|
|
|
}
|
|
|
|
return defValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isFractionValue(final TypedValue v) {
|
|
|
|
return v.type == TypedValue.TYPE_FRACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isDimensionValue(final TypedValue v) {
|
|
|
|
return v.type == TypedValue.TYPE_DIMENSION;
|
|
|
|
}
|
|
|
|
|
2023-09-12 14:21:40 +02:00
|
|
|
public static boolean isNight(final Resources res) {
|
|
|
|
return (res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
|
|
|
}
|
2025-04-07 00:54:49 +03:00
|
|
|
|
|
|
|
public static int getBottomPaddingAdjustment(Context context) {
|
2025-04-11 01:55:17 +03:00
|
|
|
if (Build.VERSION.SDK_INT < 35) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowManager wm = context.getSystemService(WindowManager.class);
|
|
|
|
logInsets(wm.getMaximumWindowMetrics(), "max-metrics");
|
|
|
|
logInsets(wm.getCurrentWindowMetrics(), "current-metrics");
|
|
|
|
|
|
|
|
WindowMetrics windowMetrics = wm.getMaximumWindowMetrics();
|
|
|
|
WindowInsets windowInsets = windowMetrics.getWindowInsets();
|
|
|
|
int insetTypes = WindowInsets.Type.navigationBars();
|
|
|
|
Insets insets = windowInsets.getInsetsIgnoringVisibility(insetTypes);
|
|
|
|
return insets.bottom + insets.top;
|
|
|
|
}
|
|
|
|
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
|
|
|
private static void logInsets(WindowMetrics metrics, String metricsType) {
|
|
|
|
logInsets(metrics, metricsType, WindowInsets::getInsets, "insets");
|
|
|
|
logInsets(metrics, metricsType, WindowInsets::getInsetsIgnoringVisibility, "insetsIgnoringVisibility");
|
|
|
|
}
|
|
|
|
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
|
|
|
private static void logInsets(WindowMetrics metrics, String metricsType,
|
|
|
|
BiFunction<WindowInsets, Integer, Insets> insetsGetter, String visibility) {
|
|
|
|
logInsets(metrics, metricsType, WindowInsets.Type.navigationBars(),"navigationBars",
|
|
|
|
insetsGetter, visibility);
|
|
|
|
logInsets(metrics, metricsType, WindowInsets.Type.systemBars(), "systemBars", insetsGetter, visibility);
|
|
|
|
logInsets(metrics, metricsType, WindowInsets.Type.statusBars(), "statusBars", insetsGetter, visibility);
|
|
|
|
logInsets(metrics, metricsType, WindowInsets.Type.displayCutout(),"displayCutout",
|
|
|
|
insetsGetter, visibility);
|
|
|
|
}
|
|
|
|
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
|
|
|
@SuppressLint("DefaultLocale")
|
|
|
|
private static void logInsets(WindowMetrics metrics, String metricsType, int insetTypes, String insetsType,
|
|
|
|
BiFunction<WindowInsets, Integer, Insets> insetsGetter, String visibility) {
|
|
|
|
WindowInsets windowInsets = metrics.getWindowInsets();
|
|
|
|
Insets insets = insetsGetter.apply(windowInsets, insetTypes);
|
|
|
|
Log.i("insets", String.format("%s, %s, %s, bottom %d, top %d", metricsType, insetsType, visibility,
|
|
|
|
insets.bottom, insets.top));
|
2025-04-07 00:54:49 +03:00
|
|
|
}
|
2019-12-31 18:19:35 +01:00
|
|
|
}
|