convert compat utils to kotlin and cleanup

This commit is contained in:
dslul 2020-01-21 20:30:29 +01:00
parent fa36013750
commit bb88c6ec00
115 changed files with 977 additions and 2235 deletions

View file

@ -13,7 +13,6 @@ import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import android.view.inputmethod.EditorInfo
import androidx.core.view.accessibility.AccessibilityEventCompat
import org.dslul.openboard.inputmethod.compat.SettingsSecureCompatUtils
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.SuggestedWords
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils
@ -61,9 +60,9 @@ class AccessibilityUtils private constructor() {
fun shouldObscureInput(editorInfo: EditorInfo?): Boolean {
if (editorInfo == null) return false
// The user can optionally force speaking passwords.
if (SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD != null) {
if (Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD != null) {
val speakPassword = Settings.Secure.getInt(mContext!!.contentResolver,
SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0
if (speakPassword) return false
}
// Always speak if the user is listening through headphones.

View file

@ -1,46 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.app.ActivityManager;
import android.content.Context;
import java.lang.reflect.Method;
public class ActivityManagerCompatUtils {
private static final Object LOCK = new Object();
private static volatile Boolean sBoolean = null;
private static final Method METHOD_isLowRamDevice = CompatUtils.getMethod(
ActivityManager.class, "isLowRamDevice");
private ActivityManagerCompatUtils() {
// Do not instantiate this class.
}
public static boolean isLowRamDevice(Context context) {
if (sBoolean == null) {
synchronized(LOCK) {
if (sBoolean == null) {
final ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
sBoolean = (Boolean)CompatUtils.invoke(am, false, METHOD_isLowRamDevice);
}
}
}
return sBoolean;
}
}

View file

@ -1,30 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.pm.PackageInfo;
@SuppressWarnings("unused")
public class AppWorkaroundsHelper {
private AppWorkaroundsHelper() {
// This helper class is not publicly instantiable.
}
public static boolean evaluateIsBrokenByRecorrection(final PackageInfo info) {
return false;
}
}

View file

@ -1,60 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.pm.PackageInfo;
import android.os.Build.VERSION_CODES;
/**
* A class to encapsulate work-arounds specific to particular apps.
*/
public class AppWorkaroundsUtils {
private final PackageInfo mPackageInfo; // May be null
private final boolean mIsBrokenByRecorrection;
public AppWorkaroundsUtils(final PackageInfo packageInfo) {
mPackageInfo = packageInfo;
mIsBrokenByRecorrection = AppWorkaroundsHelper.evaluateIsBrokenByRecorrection(
packageInfo);
}
public boolean isBrokenByRecorrection() {
return mIsBrokenByRecorrection;
}
public boolean isBeforeJellyBean() {
if (null == mPackageInfo || null == mPackageInfo.applicationInfo) {
return false;
}
return mPackageInfo.applicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN;
}
@Override
public String toString() {
if (null == mPackageInfo || null == mPackageInfo.applicationInfo) {
return "";
}
final StringBuilder s = new StringBuilder();
s.append("Target application : ")
.append(mPackageInfo.applicationInfo.name)
.append("\nPackage : ")
.append(mPackageInfo.applicationInfo.packageName)
.append("\nTarget app sdk version : ")
.append(mPackageInfo.applicationInfo.targetSdkVersion);
return s.toString();
}
}

View file

@ -0,0 +1,23 @@
package org.dslul.openboard.inputmethod.compat
import android.content.pm.PackageInfo
/**
* A class to encapsulate work-arounds specific to particular apps.
*/
class AppWorkaroundsUtils(private val mPackageInfo: PackageInfo?) {
override fun toString(): String {
if (mPackageInfo?.applicationInfo == null) {
return ""
}
val s = StringBuilder()
s.append("Target application : ")
.append(mPackageInfo.applicationInfo.name)
.append("\nPackage : ")
.append(mPackageInfo.applicationInfo.packageName)
.append("\nTarget app sdk version : ")
.append(mPackageInfo.applicationInfo.targetSdkVersion)
return s.toString()
}
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.os.Build;
public final class BuildCompatUtils {
private BuildCompatUtils() {
// This utility class is not publicly instantiable.
}
private static final boolean IS_RELEASE_BUILD = Build.VERSION.CODENAME.equals("REL");
/**
* The "effective" API version.
* {@link android.os.Build.VERSION#SDK_INT} if the platform is a release build.
* {@link android.os.Build.VERSION#SDK_INT} plus 1 if the platform is a development build.
*/
public static final int EFFECTIVE_SDK_INT = IS_RELEASE_BUILD
? Build.VERSION.SDK_INT
: Build.VERSION.SDK_INT + 1;
}

View file

@ -1,47 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import java.lang.reflect.Method;
public final class CharacterCompat {
// Note that Character.isAlphabetic(int), has been introduced in API level 19
// (Build.VERSION_CODE.KITKAT).
private static final Method METHOD_isAlphabetic = CompatUtils.getMethod(
Character.class, "isAlphabetic", int.class);
private CharacterCompat() {
// This utility class is not publicly instantiable.
}
public static boolean isAlphabetic(final int code) {
if (METHOD_isAlphabetic != null) {
return (Boolean)CompatUtils.invoke(null, false, METHOD_isAlphabetic, code);
}
switch (Character.getType(code)) {
case Character.UPPERCASE_LETTER:
case Character.LOWERCASE_LETTER:
case Character.TITLECASE_LETTER:
case Character.MODIFIER_LETTER:
case Character.OTHER_LETTER:
case Character.LETTER_NUMBER:
return true;
default:
return false;
}
}
}

View file

@ -1,218 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.text.TextUtils;
import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class CompatUtils {
private static final String TAG = CompatUtils.class.getSimpleName();
private CompatUtils() {
// This utility class is not publicly instantiable.
}
public static Class<?> getClass(final String className) {
try {
return Class.forName(className);
} catch (final ClassNotFoundException e) {
return null;
}
}
public static Method getMethod(final Class<?> targetClass, final String name,
final Class<?>... parameterTypes) {
if (targetClass == null || TextUtils.isEmpty(name)) {
return null;
}
try {
return targetClass.getMethod(name, parameterTypes);
} catch (final SecurityException | NoSuchMethodException e) {
// ignore
}
return null;
}
public static Field getField(final Class<?> targetClass, final String name) {
if (targetClass == null || TextUtils.isEmpty(name)) {
return null;
}
try {
return targetClass.getField(name);
} catch (final SecurityException | NoSuchFieldException e) {
// ignore
}
return null;
}
public static Constructor<?> getConstructor(final Class<?> targetClass,
final Class<?> ... types) {
if (targetClass == null || types == null) {
return null;
}
try {
return targetClass.getConstructor(types);
} catch (final SecurityException | NoSuchMethodException e) {
// ignore
}
return null;
}
public static Object newInstance(final Constructor<?> constructor, final Object ... args) {
if (constructor == null) {
return null;
}
try {
return constructor.newInstance(args);
} catch (final InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
Log.e(TAG, "Exception in newInstance", e);
}
return null;
}
public static Object invoke(final Object receiver, final Object defaultValue,
final Method method, final Object... args) {
if (method == null) {
return defaultValue;
}
try {
return method.invoke(receiver, args);
} catch (final IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
Log.e(TAG, "Exception in invoke", e);
}
return defaultValue;
}
public static Object getFieldValue(final Object receiver, final Object defaultValue,
final Field field) {
if (field == null) {
return defaultValue;
}
try {
return field.get(receiver);
} catch (final IllegalAccessException | IllegalArgumentException e) {
Log.e(TAG, "Exception in getFieldValue", e);
}
return defaultValue;
}
public static void setFieldValue(final Object receiver, final Field field, final Object value) {
if (field == null) {
return;
}
try {
field.set(receiver, value);
} catch (final IllegalAccessException | IllegalArgumentException e) {
Log.e(TAG, "Exception in setFieldValue", e);
}
}
public static ClassWrapper getClassWrapper(final String className) {
return new ClassWrapper(getClass(className));
}
public static final class ClassWrapper {
private final Class<?> mClass;
public ClassWrapper(final Class<?> targetClass) {
mClass = targetClass;
}
public boolean exists() {
return mClass != null;
}
public <T> ToObjectMethodWrapper<T> getMethod(final String name,
final T defaultValue, final Class<?>... parameterTypes) {
return new ToObjectMethodWrapper<>(CompatUtils.getMethod(mClass, name, parameterTypes),
defaultValue);
}
public ToIntMethodWrapper getPrimitiveMethod(final String name, final int defaultValue,
final Class<?>... parameterTypes) {
return new ToIntMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
defaultValue);
}
public ToFloatMethodWrapper getPrimitiveMethod(final String name, final float defaultValue,
final Class<?>... parameterTypes) {
return new ToFloatMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
defaultValue);
}
public ToBooleanMethodWrapper getPrimitiveMethod(final String name,
final boolean defaultValue, final Class<?>... parameterTypes) {
return new ToBooleanMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
defaultValue);
}
}
public static final class ToObjectMethodWrapper<T> {
private final Method mMethod;
private final T mDefaultValue;
public ToObjectMethodWrapper(final Method method, final T defaultValue) {
mMethod = method;
mDefaultValue = defaultValue;
}
@SuppressWarnings("unchecked")
public T invoke(final Object receiver, final Object... args) {
return (T) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
}
}
public static final class ToIntMethodWrapper {
private final Method mMethod;
private final int mDefaultValue;
public ToIntMethodWrapper(final Method method, final int defaultValue) {
mMethod = method;
mDefaultValue = defaultValue;
}
public int invoke(final Object receiver, final Object... args) {
return (int) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
}
}
public static final class ToFloatMethodWrapper {
private final Method mMethod;
private final float mDefaultValue;
public ToFloatMethodWrapper(final Method method, final float defaultValue) {
mMethod = method;
mDefaultValue = defaultValue;
}
public float invoke(final Object receiver, final Object... args) {
return (float) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
}
}
public static final class ToBooleanMethodWrapper {
private final Method mMethod;
private final boolean mDefaultValue;
public ToBooleanMethodWrapper(final Method method, final boolean defaultValue) {
mMethod = method;
mDefaultValue = defaultValue;
}
public boolean invoke(final Object receiver, final Object... args) {
return (boolean) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
}
}
}

View file

@ -0,0 +1,183 @@
package org.dslul.openboard.inputmethod.compat
import android.text.TextUtils
import android.util.Log
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
object CompatUtils {
private val TAG = CompatUtils::class.java.simpleName
fun getClass(className: String?): Class<*>? {
return try {
Class.forName(className!!)
} catch (e: ClassNotFoundException) {
null
}
}
fun getMethod(targetClass: Class<*>?, name: String?,
vararg parameterTypes: Class<*>?): Method? {
if (targetClass == null || TextUtils.isEmpty(name)) {
return null
}
try {
return targetClass.getMethod(name!!, *parameterTypes)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchMethodException) {
}
return null
}
fun getField(targetClass: Class<*>?, name: String?): Field? {
if (targetClass == null || TextUtils.isEmpty(name)) {
return null
}
try {
return targetClass.getField(name!!)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchFieldException) {
}
return null
}
fun getConstructor(targetClass: Class<*>?,
vararg types: Class<*>?): Constructor<*>? {
if (targetClass == null || types == null) {
return null
}
try {
return targetClass.getConstructor(*types)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchMethodException) {
}
return null
}
fun newInstance(constructor: Constructor<*>?, vararg args: Any?): Any? {
if (constructor == null) {
return null
}
try {
return constructor.newInstance(*args)
} catch (e: InstantiationException) {
Log.e(TAG, "Exception in newInstance", e)
} catch (e: IllegalAccessException) {
Log.e(TAG, "Exception in newInstance", e)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Exception in newInstance", e)
} catch (e: InvocationTargetException) {
Log.e(TAG, "Exception in newInstance", e)
}
return null
}
operator fun invoke(receiver: Any?, defaultValue: Any?,
method: Method?, vararg args: Any?): Any? {
if (method == null) {
return defaultValue
}
try {
return method.invoke(receiver, *args)
} catch (e: IllegalAccessException) {
Log.e(TAG, "Exception in invoke", e)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Exception in invoke", e)
} catch (e: InvocationTargetException) {
Log.e(TAG, "Exception in invoke", e)
}
return defaultValue
}
fun getFieldValue(receiver: Any?, defaultValue: Any?,
field: Field?): Any? {
if (field == null) {
return defaultValue
}
try {
return field[receiver]
} catch (e: IllegalAccessException) {
Log.e(TAG, "Exception in getFieldValue", e)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Exception in getFieldValue", e)
}
return defaultValue
}
fun setFieldValue(receiver: Any?, field: Field?, value: Any?) {
if (field == null) {
return
}
try {
field[receiver] = value
} catch (e: IllegalAccessException) {
Log.e(TAG, "Exception in setFieldValue", e)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Exception in setFieldValue", e)
}
}
fun getClassWrapper(className: String?): ClassWrapper {
return ClassWrapper(getClass(className))
}
class ClassWrapper(private val mClass: Class<*>?) {
fun exists(): Boolean {
return mClass != null
}
fun <T> getMethod(name: String?,
defaultValue: T, vararg parameterTypes: Class<*>?): ToObjectMethodWrapper<T> {
return ToObjectMethodWrapper(getMethod(mClass, name, *parameterTypes),
defaultValue)
}
fun getPrimitiveMethod(name: String?, defaultValue: Int,
vararg parameterTypes: Class<*>?): ToIntMethodWrapper {
return ToIntMethodWrapper(getMethod(mClass, name, *parameterTypes),
defaultValue)
}
fun getPrimitiveMethod(name: String?, defaultValue: Float,
vararg parameterTypes: Class<*>?): ToFloatMethodWrapper {
return ToFloatMethodWrapper(getMethod(mClass, name, *parameterTypes),
defaultValue)
}
fun getPrimitiveMethod(name: String?,
defaultValue: Boolean, vararg parameterTypes: Class<*>?): ToBooleanMethodWrapper {
return ToBooleanMethodWrapper(getMethod(mClass, name, *parameterTypes),
defaultValue)
}
}
class ToObjectMethodWrapper<T>(private val mMethod: Method?, private val mDefaultValue: T) {
operator fun invoke(receiver: Any?, vararg args: Any?): T {
return CompatUtils.invoke(receiver, mDefaultValue!!, mMethod, *args) as T
}
}
class ToIntMethodWrapper(private val mMethod: Method?, private val mDefaultValue: Int) {
operator fun invoke(receiver: Any?, vararg args: Any?): Int {
return CompatUtils.invoke(receiver, mDefaultValue, mMethod, *args) as Int
}
}
class ToFloatMethodWrapper(private val mMethod: Method?, private val mDefaultValue: Float) {
operator fun invoke(receiver: Any?, vararg args: Any?): Float {
return CompatUtils.invoke(receiver, mDefaultValue, mMethod, *args) as Float
}
}
class ToBooleanMethodWrapper(private val mMethod: Method?, private val mDefaultValue: Boolean) {
operator fun invoke(receiver: Any?, vararg args: Any?): Boolean {
return CompatUtils.invoke(receiver, mDefaultValue, mMethod, *args) as Boolean
}
}
}

View file

@ -1,185 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.annotation.TargetApi;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Build;
import android.view.inputmethod.CursorAnchorInfo;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A wrapper for {@link CursorAnchorInfo}, which has been introduced in API Level 21. You can use
* this wrapper to avoid direct dependency on newly introduced types.
*/
public class CursorAnchorInfoCompatWrapper {
/**
* The insertion marker or character bounds have at least one visible region.
*/
public static final int FLAG_HAS_VISIBLE_REGION = 0x01;
/**
* The insertion marker or character bounds have at least one invisible (clipped) region.
*/
public static final int FLAG_HAS_INVISIBLE_REGION = 0x02;
/**
* The insertion marker or character bounds is placed at right-to-left (RTL) character.
*/
public static final int FLAG_IS_RTL = 0x04;
CursorAnchorInfoCompatWrapper() {
// This class is not publicly instantiable.
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Nullable
public static CursorAnchorInfoCompatWrapper wrap(@Nullable final CursorAnchorInfo instance) {
if (BuildCompatUtils.EFFECTIVE_SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return null;
}
if (instance == null) {
return null;
}
return new RealWrapper(instance);
}
public int getSelectionStart() {
throw new UnsupportedOperationException("not supported.");
}
public int getSelectionEnd() {
throw new UnsupportedOperationException("not supported.");
}
public CharSequence getComposingText() {
throw new UnsupportedOperationException("not supported.");
}
public int getComposingTextStart() {
throw new UnsupportedOperationException("not supported.");
}
public Matrix getMatrix() {
throw new UnsupportedOperationException("not supported.");
}
@SuppressWarnings("unused")
public RectF getCharacterBounds(final int index) {
throw new UnsupportedOperationException("not supported.");
}
@SuppressWarnings("unused")
public int getCharacterBoundsFlags(final int index) {
throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerBaseline() {
throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerBottom() {
throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerHorizontal() {
throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerTop() {
throw new UnsupportedOperationException("not supported.");
}
public int getInsertionMarkerFlags() {
throw new UnsupportedOperationException("not supported.");
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static final class RealWrapper extends CursorAnchorInfoCompatWrapper {
@Nonnull
private final CursorAnchorInfo mInstance;
public RealWrapper(@Nonnull final CursorAnchorInfo info) {
mInstance = info;
}
@Override
public int getSelectionStart() {
return mInstance.getSelectionStart();
}
@Override
public int getSelectionEnd() {
return mInstance.getSelectionEnd();
}
@Override
public CharSequence getComposingText() {
return mInstance.getComposingText();
}
@Override
public int getComposingTextStart() {
return mInstance.getComposingTextStart();
}
@Override
public Matrix getMatrix() {
return mInstance.getMatrix();
}
@Override
public RectF getCharacterBounds(final int index) {
return mInstance.getCharacterBounds(index);
}
@Override
public int getCharacterBoundsFlags(final int index) {
return mInstance.getCharacterBoundsFlags(index);
}
@Override
public float getInsertionMarkerBaseline() {
return mInstance.getInsertionMarkerBaseline();
}
@Override
public float getInsertionMarkerBottom() {
return mInstance.getInsertionMarkerBottom();
}
@Override
public float getInsertionMarkerHorizontal() {
return mInstance.getInsertionMarkerHorizontal();
}
@Override
public float getInsertionMarkerTop() {
return mInstance.getInsertionMarkerTop();
}
@Override
public int getInsertionMarkerFlags() {
return mInstance.getInsertionMarkerFlags();
}
}
}

View file

@ -0,0 +1,158 @@
package org.dslul.openboard.inputmethod.compat
import android.annotation.TargetApi
import android.graphics.Matrix
import android.graphics.RectF
import android.os.Build
import android.os.Build.VERSION_CODES
import android.view.inputmethod.CursorAnchorInfo
/**
* A wrapper for [CursorAnchorInfo], which has been introduced in API Level 21. You can use
* this wrapper to avoid direct dependency on newly introduced types.
*/
open class CursorAnchorInfoCompatWrapper internal constructor() {
open val selectionStart: Int
get() {
throw UnsupportedOperationException("not supported.")
}
open val selectionEnd: Int
get() {
throw UnsupportedOperationException("not supported.")
}
open val composingText: CharSequence?
get() {
throw UnsupportedOperationException("not supported.")
}
open val composingTextStart: Int
get() {
throw UnsupportedOperationException("not supported.")
}
open val matrix: Matrix?
get() {
throw UnsupportedOperationException("not supported.")
}
open fun getCharacterBounds(index: Int): RectF? {
throw UnsupportedOperationException("not supported.")
}
open fun getCharacterBoundsFlags(index: Int): Int {
throw UnsupportedOperationException("not supported.")
}
open val insertionMarkerBaseline: Float
get() {
throw UnsupportedOperationException("not supported.")
}
open val insertionMarkerBottom: Float
get() {
throw UnsupportedOperationException("not supported.")
}
open val insertionMarkerHorizontal: Float
get() {
throw UnsupportedOperationException("not supported.")
}
open val insertionMarkerTop: Float
get() {
throw UnsupportedOperationException("not supported.")
}
open val insertionMarkerFlags: Int
get() {
throw UnsupportedOperationException("not supported.")
}
@TargetApi(VERSION_CODES.LOLLIPOP)
private class RealWrapper(private val mInstance: CursorAnchorInfo) : CursorAnchorInfoCompatWrapper() {
override val selectionStart: Int
get() {
return mInstance.selectionStart
}
override val selectionEnd: Int
get() {
return mInstance.selectionEnd
}
override val composingText: CharSequence?
get() {
return mInstance.composingText
}
override val composingTextStart: Int
get() {
return mInstance.composingTextStart
}
override val matrix: Matrix?
get() {
return mInstance.matrix
}
override fun getCharacterBounds(index: Int): RectF? {
return mInstance.getCharacterBounds(index)
}
override fun getCharacterBoundsFlags(index: Int): Int {
return mInstance.getCharacterBoundsFlags(index)
}
override val insertionMarkerBaseline: Float
get() {
return mInstance.insertionMarkerBaseline
}
override val insertionMarkerBottom: Float
get() {
return mInstance.insertionMarkerBottom
}
override val insertionMarkerHorizontal: Float
get() {
return mInstance.insertionMarkerHorizontal
}
override val insertionMarkerTop: Float
get() {
return mInstance.insertionMarkerTop
}
override val insertionMarkerFlags: Int
get() {
return mInstance.insertionMarkerFlags
}
}
companion object {
/**
* The insertion marker or character bounds have at least one visible region.
*/
const val FLAG_HAS_VISIBLE_REGION = 0x01
/**
* The insertion marker or character bounds have at least one invisible (clipped) region.
*/
const val FLAG_HAS_INVISIBLE_REGION = 0x02
/**
* The insertion marker or character bounds is placed at right-to-left (RTL) character.
*/
const val FLAG_IS_RTL = 0x04
@kotlin.jvm.JvmStatic
@TargetApi(VERSION_CODES.LOLLIPOP)
fun wrap(instance: CursorAnchorInfo?): CursorAnchorInfoCompatWrapper? {
return if (Build.VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
null
} else instance?.let { RealWrapper(it) }
}
}
}

View file

@ -1,98 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.view.inputmethod.EditorInfo;
import java.lang.reflect.Field;
import java.util.Locale;
public final class EditorInfoCompatUtils {
// Note that EditorInfo.IME_FLAG_FORCE_ASCII has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Field FIELD_IME_FLAG_FORCE_ASCII = CompatUtils.getField(
EditorInfo.class, "IME_FLAG_FORCE_ASCII");
private static final Integer OBJ_IME_FLAG_FORCE_ASCII = (Integer) CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_IME_FLAG_FORCE_ASCII);
private static final Field FIELD_HINT_LOCALES = CompatUtils.getField(
EditorInfo.class, "hintLocales");
private EditorInfoCompatUtils() {
// This utility class is not publicly instantiable.
}
public static boolean hasFlagForceAscii(final int imeOptions) {
if (OBJ_IME_FLAG_FORCE_ASCII == null) return false;
return (imeOptions & OBJ_IME_FLAG_FORCE_ASCII) != 0;
}
public static String imeActionName(final int imeOptions) {
final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION;
switch (actionId) {
case EditorInfo.IME_ACTION_UNSPECIFIED:
return "actionUnspecified";
case EditorInfo.IME_ACTION_NONE:
return "actionNone";
case EditorInfo.IME_ACTION_GO:
return "actionGo";
case EditorInfo.IME_ACTION_SEARCH:
return "actionSearch";
case EditorInfo.IME_ACTION_SEND:
return "actionSend";
case EditorInfo.IME_ACTION_NEXT:
return "actionNext";
case EditorInfo.IME_ACTION_DONE:
return "actionDone";
case EditorInfo.IME_ACTION_PREVIOUS:
return "actionPrevious";
default:
return "actionUnknown(" + actionId + ")";
}
}
public static String imeOptionsName(final int imeOptions) {
final String action = imeActionName(imeOptions);
final StringBuilder flags = new StringBuilder();
if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
flags.append("flagNoEnterAction|");
}
if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0) {
flags.append("flagNavigateNext|");
}
if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0) {
flags.append("flagNavigatePrevious|");
}
if (hasFlagForceAscii(imeOptions)) {
flags.append("flagForceAscii|");
}
return (action != null) ? flags + action : flags.toString();
}
public static Locale getPrimaryHintLocale(final EditorInfo editorInfo) {
if (editorInfo == null) {
return null;
}
final Object localeList = CompatUtils.getFieldValue(editorInfo, null, FIELD_HINT_LOCALES);
if (localeList == null) {
return null;
}
if (LocaleListCompatUtils.isEmpty(localeList)) {
return null;
}
return LocaleListCompatUtils.get(localeList, 0);
}
}

View file

@ -0,0 +1,66 @@
package org.dslul.openboard.inputmethod.compat
import android.view.inputmethod.EditorInfo
import java.util.*
object EditorInfoCompatUtils {
// Note that EditorInfo.IME_FLAG_FORCE_ASCII has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private val FIELD_IME_FLAG_FORCE_ASCII = CompatUtils.getField(
EditorInfo::class.java, "IME_FLAG_FORCE_ASCII")
private val OBJ_IME_FLAG_FORCE_ASCII: Int? = CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_IME_FLAG_FORCE_ASCII) as Int
private val FIELD_HINT_LOCALES = CompatUtils.getField(
EditorInfo::class.java, "hintLocales")
@kotlin.jvm.JvmStatic
fun hasFlagForceAscii(imeOptions: Int): Boolean {
return if (OBJ_IME_FLAG_FORCE_ASCII == null) false else imeOptions and OBJ_IME_FLAG_FORCE_ASCII != 0
}
@kotlin.jvm.JvmStatic
fun imeActionName(imeOptions: Int): String {
val actionId = imeOptions and EditorInfo.IME_MASK_ACTION
return when (actionId) {
EditorInfo.IME_ACTION_UNSPECIFIED -> "actionUnspecified"
EditorInfo.IME_ACTION_NONE -> "actionNone"
EditorInfo.IME_ACTION_GO -> "actionGo"
EditorInfo.IME_ACTION_SEARCH -> "actionSearch"
EditorInfo.IME_ACTION_SEND -> "actionSend"
EditorInfo.IME_ACTION_NEXT -> "actionNext"
EditorInfo.IME_ACTION_DONE -> "actionDone"
EditorInfo.IME_ACTION_PREVIOUS -> "actionPrevious"
else -> "actionUnknown($actionId)"
}
}
fun imeOptionsName(imeOptions: Int): String {
val action = imeActionName(imeOptions)
val flags = StringBuilder()
if (imeOptions and EditorInfo.IME_FLAG_NO_ENTER_ACTION != 0) {
flags.append("flagNoEnterAction|")
}
if (imeOptions and EditorInfo.IME_FLAG_NAVIGATE_NEXT != 0) {
flags.append("flagNavigateNext|")
}
if (imeOptions and EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS != 0) {
flags.append("flagNavigatePrevious|")
}
if (hasFlagForceAscii(imeOptions)) {
flags.append("flagForceAscii|")
}
return if (action != null) flags.toString() + action else flags.toString()
}
@kotlin.jvm.JvmStatic
fun getPrimaryHintLocale(editorInfo: EditorInfo?): Locale? {
if (editorInfo == null) {
return null
}
val localeList = CompatUtils.getFieldValue(editorInfo, null, FIELD_HINT_LOCALES)
?: return null
return if (LocaleListCompatUtils.isEmpty(localeList)) {
null
} else LocaleListCompatUtils.get(localeList, 0)
}
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
public final class InputConnectionCompatUtils {
private static final CompatUtils.ClassWrapper sInputConnectionType;
private static final CompatUtils.ToBooleanMethodWrapper sRequestCursorUpdatesMethod;
static {
sInputConnectionType = new CompatUtils.ClassWrapper(InputConnection.class);
sRequestCursorUpdatesMethod = sInputConnectionType.getPrimitiveMethod(
"requestCursorUpdates", false, int.class);
}
public static boolean isRequestCursorUpdatesAvailable() {
return sRequestCursorUpdatesMethod != null;
}
/**
* Local copies of some constants in InputConnection until the SDK becomes publicly available.
*/
private static int CURSOR_UPDATE_IMMEDIATE = 1 << 0;
private static int CURSOR_UPDATE_MONITOR = 1 << 1;
private static boolean requestCursorUpdatesImpl(final InputConnection inputConnection,
final int cursorUpdateMode) {
if (!isRequestCursorUpdatesAvailable()) {
return false;
}
return sRequestCursorUpdatesMethod.invoke(inputConnection, cursorUpdateMode);
}
/**
* Requests the editor to call back {@link InputMethodManager#updateCursorAnchorInfo}.
* @param inputConnection the input connection to which the request is to be sent.
* @param enableMonitor {@code true} to request the editor to call back the method whenever the
* cursor/anchor position is changed.
* @param requestImmediateCallback {@code true} to request the editor to call back the method
* as soon as possible to notify the current cursor/anchor position to the input method.
* @return {@code false} if the request is not handled. Otherwise returns {@code true}.
*/
public static boolean requestCursorUpdates(final InputConnection inputConnection,
final boolean enableMonitor, final boolean requestImmediateCallback) {
final int cursorUpdateMode = (enableMonitor ? CURSOR_UPDATE_MONITOR : 0)
| (requestImmediateCallback ? CURSOR_UPDATE_IMMEDIATE : 0);
return requestCursorUpdatesImpl(inputConnection, cursorUpdateMode);
}
}

View file

@ -0,0 +1,47 @@
package org.dslul.openboard.inputmethod.compat
import android.view.inputmethod.InputConnection
import org.dslul.openboard.inputmethod.compat.CompatUtils.ClassWrapper
import org.dslul.openboard.inputmethod.compat.CompatUtils.ToBooleanMethodWrapper
object InputConnectionCompatUtils {
private var sInputConnectionType: ClassWrapper? = null
private var sRequestCursorUpdatesMethod: ToBooleanMethodWrapper? = null
val isRequestCursorUpdatesAvailable: Boolean
get() = sRequestCursorUpdatesMethod != null
/**
* Local copies of some constants in InputConnection until the SDK becomes publicly available.
*/
private const val CURSOR_UPDATE_IMMEDIATE = 1 shl 0
private const val CURSOR_UPDATE_MONITOR = 1 shl 1
private fun requestCursorUpdatesImpl(inputConnection: InputConnection,
cursorUpdateMode: Int): Boolean {
return if (!isRequestCursorUpdatesAvailable) {
false
} else sRequestCursorUpdatesMethod!!.invoke(inputConnection, cursorUpdateMode)
}
/**
* Requests the editor to call back [InputMethodManager.updateCursorAnchorInfo].
* @param inputConnection the input connection to which the request is to be sent.
* @param enableMonitor `true` to request the editor to call back the method whenever the
* cursor/anchor position is changed.
* @param requestImmediateCallback `true` to request the editor to call back the method
* as soon as possible to notify the current cursor/anchor position to the input method.
* @return `false` if the request is not handled. Otherwise returns `true`.
*/
@kotlin.jvm.JvmStatic
fun requestCursorUpdates(inputConnection: InputConnection,
enableMonitor: Boolean, requestImmediateCallback: Boolean): Boolean {
val cursorUpdateMode = ((if (enableMonitor) CURSOR_UPDATE_MONITOR else 0)
or if (requestImmediateCallback) CURSOR_UPDATE_IMMEDIATE else 0)
return requestCursorUpdatesImpl(inputConnection, cursorUpdateMode)
}
init {
sInputConnectionType = ClassWrapper(InputConnection::class.java)
sRequestCursorUpdatesMethod = sInputConnectionType!!.getPrimitiveMethod(
"requestCursorUpdates", false, Int::class.javaPrimitiveType)
}
}

View file

@ -1,52 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.Context;
import android.os.IBinder;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Method;
public final class InputMethodManagerCompatWrapper {
// Note that InputMethodManager.switchToNextInputMethod() has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod(
InputMethodManager.class, "switchToNextInputMethod", IBinder.class, boolean.class);
// Note that InputMethodManager.shouldOfferSwitchingToNextInputMethod() has been introduced
// in API level 19 (Build.VERSION_CODES.KITKAT).
private static final Method METHOD_shouldOfferSwitchingToNextInputMethod =
CompatUtils.getMethod(InputMethodManager.class,
"shouldOfferSwitchingToNextInputMethod", IBinder.class);
public final InputMethodManager mImm;
public InputMethodManagerCompatWrapper(final Context context) {
mImm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
}
public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */,
METHOD_switchToNextInputMethod, token, onlyCurrentIme);
}
public boolean shouldOfferSwitchingToNextInputMethod(final IBinder token) {
return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */,
METHOD_shouldOfferSwitchingToNextInputMethod, token);
}
}

View file

@ -0,0 +1,34 @@
package org.dslul.openboard.inputmethod.compat
import android.content.Context
import android.os.IBinder
import android.view.inputmethod.InputMethodManager
class InputMethodManagerCompatWrapper(context: Context) {
@kotlin.jvm.JvmField
val mImm: InputMethodManager
fun switchToNextInputMethod(token: IBinder?, onlyCurrentIme: Boolean): Boolean {
return CompatUtils.invoke(mImm, false /* defaultValue */,
METHOD_switchToNextInputMethod, token, onlyCurrentIme) as Boolean
}
fun shouldOfferSwitchingToNextInputMethod(token: IBinder?): Boolean {
return CompatUtils.invoke(mImm, false /* defaultValue */,
METHOD_shouldOfferSwitchingToNextInputMethod, token) as Boolean
}
companion object {
// Note that InputMethodManager.switchToNextInputMethod() has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private val METHOD_switchToNextInputMethod = CompatUtils.getMethod(
InputMethodManager::class.java, "switchToNextInputMethod", IBinder::class.java, Boolean::class.javaPrimitiveType)
// Note that InputMethodManager.shouldOfferSwitchingToNextInputMethod() has been introduced
// in API level 19 (Build.VERSION_CODES.KITKAT).
private val METHOD_shouldOfferSwitchingToNextInputMethod = CompatUtils.getMethod(InputMethodManager::class.java,
"shouldOfferSwitchingToNextInputMethod", IBinder::class.java)
}
init {
mImm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
}
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.inputmethodservice.InputMethodService;
import java.lang.reflect.Method;
public final class InputMethodServiceCompatUtils {
// Note that {@link InputMethodService#enableHardwareAcceleration} has been introduced
// in API level 17 (Build.VERSION_CODES.JELLY_BEAN_MR1).
private static final Method METHOD_enableHardwareAcceleration =
CompatUtils.getMethod(InputMethodService.class, "enableHardwareAcceleration");
private InputMethodServiceCompatUtils() {
// This utility class is not publicly instantiable.
}
public static boolean enableHardwareAcceleration(final InputMethodService ims) {
return (Boolean)CompatUtils.invoke(ims, false /* defaultValue */,
METHOD_enableHardwareAcceleration);
}
}

View file

@ -1,100 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.os.Build;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodSubtype;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Locale;
import javax.annotation.Nonnull;
public final class InputMethodSubtypeCompatUtils {
private static final String TAG = InputMethodSubtypeCompatUtils.class.getSimpleName();
// Note that InputMethodSubtype(int nameId, int iconId, String locale, String mode,
// String extraValue, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id)
// has been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static final Constructor<?> CONSTRUCTOR_INPUT_METHOD_SUBTYPE =
CompatUtils.getConstructor(InputMethodSubtype.class,
int.class, int.class, String.class, String.class, String.class, boolean.class,
boolean.class, int.class);
static {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
android.util.Log.w(TAG, "Warning!!! Constructor is not defined.");
}
}
// Note that {@link InputMethodSubtype#isAsciiCapable()} has been introduced in API level 19
// (Build.VERSION_CODE.KITKAT).
private static final Method METHOD_isAsciiCapable = CompatUtils.getMethod(
InputMethodSubtype.class, "isAsciiCapable");
private InputMethodSubtypeCompatUtils() {
// This utility class is not publicly instantiable.
}
@SuppressWarnings("deprecation")
@Nonnull
public static InputMethodSubtype newInputMethodSubtype(int nameId, int iconId, String locale,
String mode, String extraValue, boolean isAuxiliary,
boolean overridesImplicitlyEnabledSubtype, int id) {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
return new InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype);
}
return (InputMethodSubtype) CompatUtils.newInstance(CONSTRUCTOR_INPUT_METHOD_SUBTYPE,
nameId, iconId, locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype, id);
}
public static boolean isAsciiCapable(final RichInputMethodSubtype subtype) {
return isAsciiCapable(subtype.getRawSubtype());
}
public static boolean isAsciiCapable(final InputMethodSubtype subtype) {
return isAsciiCapableWithAPI(subtype)
|| subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE);
}
// Note that InputMethodSubtype.getLanguageTag() is expected to be available in Android N+.
private static final Method GET_LANGUAGE_TAG =
CompatUtils.getMethod(InputMethodSubtype.class, "getLanguageTag");
public static Locale getLocaleObject(final InputMethodSubtype subtype) {
// Locale.forLanguageTag() is available only in Android L and later.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final String languageTag = (String) CompatUtils.invoke(subtype, null, GET_LANGUAGE_TAG);
if (!TextUtils.isEmpty(languageTag)) {
return Locale.forLanguageTag(languageTag);
}
}
return LocaleUtils.constructLocaleFromString(subtype.getLocale());
}
@UsedForTesting
public static boolean isAsciiCapableWithAPI(final InputMethodSubtype subtype) {
return (Boolean)CompatUtils.invoke(subtype, false, METHOD_isAsciiCapable);
}
}

View file

@ -0,0 +1,54 @@
package org.dslul.openboard.inputmethod.compat
import android.os.Build
import android.os.Build.VERSION_CODES
import android.text.TextUtils
import android.util.Log
import android.view.inputmethod.InputMethodSubtype
import org.dslul.openboard.inputmethod.annotations.UsedForTesting
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype
import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
import java.util.*
object InputMethodSubtypeCompatUtils {
private val TAG = InputMethodSubtypeCompatUtils::class.java.simpleName
// Note that InputMethodSubtype(int nameId, int iconId, String locale, String mode,
// String extraValue, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id)
// has been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
private val CONSTRUCTOR_INPUT_METHOD_SUBTYPE = CompatUtils.getConstructor(InputMethodSubtype::class.java,
Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java, String::class.java, String::class.java, Boolean::class.javaPrimitiveType,
Boolean::class.javaPrimitiveType, Int::class.javaPrimitiveType)
@kotlin.jvm.JvmStatic
fun newInputMethodSubtype(nameId: Int, iconId: Int, locale: String?,
mode: String?, extraValue: String?, isAuxiliary: Boolean,
overridesImplicitlyEnabledSubtype: Boolean, id: Int): InputMethodSubtype? {
return if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype)
} else CompatUtils.newInstance(CONSTRUCTOR_INPUT_METHOD_SUBTYPE,
nameId, iconId, locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype, id) as InputMethodSubtype
}
// Note that InputMethodSubtype.getLanguageTag() is expected to be available in Android N+.
private val GET_LANGUAGE_TAG = CompatUtils.getMethod(InputMethodSubtype::class.java, "getLanguageTag")
@kotlin.jvm.JvmStatic
fun getLocaleObject(subtype: InputMethodSubtype): Locale { // Locale.forLanguageTag() is available only in Android L and later.
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val languageTag = CompatUtils.invoke(subtype, null, GET_LANGUAGE_TAG) as String
if (!TextUtils.isEmpty(languageTag)) {
return Locale.forLanguageTag(languageTag)
}
}
return LocaleUtils.constructLocaleFromString(subtype.locale)
}
init {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
Log.w(TAG, "Warning!!! Constructor is not defined.")
}
}
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.Intent;
public final class IntentCompatUtils {
// Note that Intent.ACTION_USER_INITIALIZE have been introduced in API level 17
// (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static final String ACTION_USER_INITIALIZE =
(String)CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
CompatUtils.getField(Intent.class, "ACTION_USER_INITIALIZE"));
private IntentCompatUtils() {
// This utility class is not publicly instantiable.
}
public static boolean is_ACTION_USER_INITIALIZE(final String action) {
return ACTION_USER_INITIALIZE != null && ACTION_USER_INITIALIZE.equals(action);
}
}

View file

@ -1,40 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import java.lang.reflect.Method;
import java.util.Locale;
public final class LocaleListCompatUtils {
private static final Class CLASS_LocaleList = CompatUtils.getClass("android.os.LocaleList");
private static final Method METHOD_get =
CompatUtils.getMethod(CLASS_LocaleList, "get", int.class);
private static final Method METHOD_isEmpty =
CompatUtils.getMethod(CLASS_LocaleList, "isEmpty");
private LocaleListCompatUtils() {
// This utility class is not publicly instantiable.
}
public static boolean isEmpty(final Object localeList) {
return (Boolean) CompatUtils.invoke(localeList, Boolean.FALSE, METHOD_isEmpty);
}
public static Locale get(final Object localeList, final int index) {
return (Locale) CompatUtils.invoke(localeList, null, METHOD_get, index);
}
}

View file

@ -0,0 +1,16 @@
package org.dslul.openboard.inputmethod.compat
import java.util.*
object LocaleListCompatUtils {
private val CLASS_LocaleList = CompatUtils.getClass("android.os.LocaleList")
private val METHOD_get = CompatUtils.getMethod(CLASS_LocaleList, "get", Int::class.javaPrimitiveType)
private val METHOD_isEmpty = CompatUtils.getMethod(CLASS_LocaleList, "isEmpty")
fun isEmpty(localeList: Any?): Boolean {
return CompatUtils.invoke(localeList, java.lang.Boolean.FALSE, METHOD_isEmpty) as Boolean
}
operator fun get(localeList: Any?, index: Int): Locale? {
return CompatUtils.invoke(localeList, null, METHOD_get, index) as Locale
}
}

View file

@ -1,218 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.LocaleSpan;
import android.util.Log;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Locale;
@UsedForTesting
public final class LocaleSpanCompatUtils {
private static final String TAG = LocaleSpanCompatUtils.class.getSimpleName();
// Note that LocaleSpan(Locale locale) has been introduced in API level 17
// (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static Class<?> getLocaleSpanClass() {
try {
return Class.forName("android.text.style.LocaleSpan");
} catch (ClassNotFoundException e) {
return null;
}
}
private static final Class<?> LOCALE_SPAN_TYPE;
private static final Constructor<?> LOCALE_SPAN_CONSTRUCTOR;
private static final Method LOCALE_SPAN_GET_LOCALE;
static {
LOCALE_SPAN_TYPE = getLocaleSpanClass();
LOCALE_SPAN_CONSTRUCTOR = CompatUtils.getConstructor(LOCALE_SPAN_TYPE, Locale.class);
LOCALE_SPAN_GET_LOCALE = CompatUtils.getMethod(LOCALE_SPAN_TYPE, "getLocale");
}
@UsedForTesting
public static boolean isLocaleSpanAvailable() {
return (LOCALE_SPAN_CONSTRUCTOR != null && LOCALE_SPAN_GET_LOCALE != null);
}
@UsedForTesting
public static Object newLocaleSpan(final Locale locale) {
return CompatUtils.newInstance(LOCALE_SPAN_CONSTRUCTOR, locale);
}
@UsedForTesting
public static Locale getLocaleFromLocaleSpan(final Object localeSpan) {
return (Locale) CompatUtils.invoke(localeSpan, null, LOCALE_SPAN_GET_LOCALE);
}
/**
* Ensures that the specified range is covered with only one {@link LocaleSpan} with the given
* locale. If the region is already covered by one or more {@link LocaleSpan}, their ranges are
* updated so that each character has only one locale.
* @param spannable the spannable object to be updated.
* @param start the start index from which {@link LocaleSpan} is attached (inclusive).
* @param end the end index to which {@link LocaleSpan} is attached (exclusive).
* @param locale the locale to be attached to the specified range.
*/
@UsedForTesting
public static void updateLocaleSpan(final Spannable spannable, final int start,
final int end, final Locale locale) {
if (end < start) {
Log.e(TAG, "Invalid range: start=" + start + " end=" + end);
return;
}
if (!isLocaleSpanAvailable()) {
return;
}
// A brief summary of our strategy;
// 1. Enumerate all LocaleSpans between [start - 1, end + 1].
// 2. For each LocaleSpan S:
// - Update the range of S so as not to cover [start, end] if S doesn't have the
// expected locale.
// - Mark S as "to be merged" if S has the expected locale.
// 3. Merge all the LocaleSpans that are marked as "to be merged" into one LocaleSpan.
// If no appropriate span is found, create a new one with newLocaleSpan method.
final int searchStart = Math.max(start - 1, 0);
final int searchEnd = Math.min(end + 1, spannable.length());
// LocaleSpans found in the target range. See the step 1 in the above comment.
final Object[] existingLocaleSpans = spannable.getSpans(searchStart, searchEnd,
LOCALE_SPAN_TYPE);
// LocaleSpans that are marked as "to be merged". See the step 2 in the above comment.
final ArrayList<Object> existingLocaleSpansToBeMerged = new ArrayList<>();
boolean isStartExclusive = true;
boolean isEndExclusive = true;
int newStart = start;
int newEnd = end;
for (final Object existingLocaleSpan : existingLocaleSpans) {
final Locale attachedLocale = getLocaleFromLocaleSpan(existingLocaleSpan);
if (!locale.equals(attachedLocale)) {
// This LocaleSpan does not have the expected locale. Update its range if it has
// an intersection with the range [start, end] (the first case of the step 2 in the
// above comment).
removeLocaleSpanFromRange(existingLocaleSpan, spannable, start, end);
continue;
}
final int spanStart = spannable.getSpanStart(existingLocaleSpan);
final int spanEnd = spannable.getSpanEnd(existingLocaleSpan);
if (spanEnd < spanStart) {
Log.e(TAG, "Invalid span: spanStart=" + spanStart + " spanEnd=" + spanEnd);
continue;
}
if (spanEnd < start || end < spanStart) {
// No intersection found.
continue;
}
// Here existingLocaleSpan has the expected locale and an intersection with the
// range [start, end] (the second case of the the step 2 in the above comment).
final int spanFlag = spannable.getSpanFlags(existingLocaleSpan);
if (spanStart < newStart) {
newStart = spanStart;
isStartExclusive = ((spanFlag & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (newEnd < spanEnd) {
newEnd = spanEnd;
isEndExclusive = ((spanFlag & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
existingLocaleSpansToBeMerged.add(existingLocaleSpan);
}
int originalLocaleSpanFlag = 0;
Object localeSpan = null;
if (existingLocaleSpansToBeMerged.isEmpty()) {
// If there is no LocaleSpan that is marked as to be merged, create a new one.
localeSpan = newLocaleSpan(locale);
} else {
// Reuse the first LocaleSpan to avoid unnecessary object instantiation.
localeSpan = existingLocaleSpansToBeMerged.get(0);
originalLocaleSpanFlag = spannable.getSpanFlags(localeSpan);
// No need to keep other instances.
for (int i = 1; i < existingLocaleSpansToBeMerged.size(); ++i) {
spannable.removeSpan(existingLocaleSpansToBeMerged.get(i));
}
}
final int localeSpanFlag = getSpanFlag(originalLocaleSpanFlag, isStartExclusive,
isEndExclusive);
spannable.setSpan(localeSpan, newStart, newEnd, localeSpanFlag);
}
private static void removeLocaleSpanFromRange(final Object localeSpan,
final Spannable spannable, final int removeStart, final int removeEnd) {
if (!isLocaleSpanAvailable()) {
return;
}
final int spanStart = spannable.getSpanStart(localeSpan);
final int spanEnd = spannable.getSpanEnd(localeSpan);
if (spanStart > spanEnd) {
Log.e(TAG, "Invalid span: spanStart=" + spanStart + " spanEnd=" + spanEnd);
return;
}
if (spanEnd < removeStart) {
// spanStart < spanEnd < removeStart < removeEnd
return;
}
if (removeEnd < spanStart) {
// spanStart < removeEnd < spanStart < spanEnd
return;
}
final int spanFlags = spannable.getSpanFlags(localeSpan);
if (spanStart < removeStart) {
if (removeEnd < spanEnd) {
// spanStart < removeStart < removeEnd < spanEnd
final Locale locale = getLocaleFromLocaleSpan(localeSpan);
spannable.setSpan(localeSpan, spanStart, removeStart, spanFlags);
final Object attionalLocaleSpan = newLocaleSpan(locale);
spannable.setSpan(attionalLocaleSpan, removeEnd, spanEnd, spanFlags);
return;
}
// spanStart < removeStart < spanEnd <= removeEnd
spannable.setSpan(localeSpan, spanStart, removeStart, spanFlags);
return;
}
if (removeEnd < spanEnd) {
// removeStart <= spanStart < removeEnd < spanEnd
spannable.setSpan(localeSpan, removeEnd, spanEnd, spanFlags);
return;
}
// removeStart <= spanStart < spanEnd < removeEnd
spannable.removeSpan(localeSpan);
}
private static int getSpanFlag(final int originalFlag,
final boolean isStartExclusive, final boolean isEndExclusive) {
return (originalFlag & ~Spanned.SPAN_POINT_MARK_MASK) |
getSpanPointMarkFlag(isStartExclusive, isEndExclusive);
}
private static int getSpanPointMarkFlag(final boolean isStartExclusive,
final boolean isEndExclusive) {
if (isStartExclusive) {
return isEndExclusive ? Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
: Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
}
return isEndExclusive ? Spanned.SPAN_INCLUSIVE_EXCLUSIVE
: Spanned.SPAN_INCLUSIVE_INCLUSIVE;
}
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.os.Looper;
import java.lang.reflect.Method;
/**
* Helper to call Looper#quitSafely, which was introduced in API
* level 18 (Build.VERSION_CODES.JELLY_BEAN_MR2).
*
* In unit tests, we create lots of instances of LatinIME, which means we need to clean up
* some Loopers lest we leak file descriptors. In normal use on a device though, this is never
* necessary (although it does not hurt).
*/
public final class LooperCompatUtils {
private static final Method METHOD_quitSafely = CompatUtils.getMethod(
Looper.class, "quitSafely");
public static void quitSafely(final Looper looper) {
if (null != METHOD_quitSafely) {
CompatUtils.invoke(looper, null /* default return value */, METHOD_quitSafely);
} else {
looper.quit();
}
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.app.Notification;
import android.os.Build;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class NotificationCompatUtils {
// Note that TextInfo.getCharSequence() is supposed to be available in API level 21 and later.
private static final Method METHOD_setColor =
CompatUtils.getMethod(Notification.Builder.class, "setColor", int.class);
private static final Method METHOD_setVisibility =
CompatUtils.getMethod(Notification.Builder.class, "setVisibility", int.class);
private static final Method METHOD_setCategory =
CompatUtils.getMethod(Notification.Builder.class, "setCategory", String.class);
private static final Method METHOD_setPriority =
CompatUtils.getMethod(Notification.Builder.class, "setPriority", int.class);
private static final Method METHOD_build =
CompatUtils.getMethod(Notification.Builder.class, "build");
private static final Field FIELD_VISIBILITY_SECRET =
CompatUtils.getField(Notification.class, "VISIBILITY_SECRET");
private static final int VISIBILITY_SECRET = null == FIELD_VISIBILITY_SECRET ? 0
: (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
FIELD_VISIBILITY_SECRET);
private static final Field FIELD_CATEGORY_RECOMMENDATION =
CompatUtils.getField(Notification.class, "CATEGORY_RECOMMENDATION");
private static final String CATEGORY_RECOMMENDATION = null == FIELD_CATEGORY_RECOMMENDATION ? ""
: (String) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
FIELD_CATEGORY_RECOMMENDATION);
private static final Field FIELD_PRIORITY_LOW =
CompatUtils.getField(Notification.class, "PRIORITY_LOW");
private static final int PRIORITY_LOW = null == FIELD_PRIORITY_LOW ? 0
: (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
FIELD_PRIORITY_LOW);
private NotificationCompatUtils() {
// This class is non-instantiable.
}
// Sets the accent color
public static void setColor(final Notification.Builder builder, final int color) {
CompatUtils.invoke(builder, null, METHOD_setColor, color);
}
public static void setVisibilityToSecret(final Notification.Builder builder) {
CompatUtils.invoke(builder, null, METHOD_setVisibility, VISIBILITY_SECRET);
}
public static void setCategoryToRecommendation(final Notification.Builder builder) {
CompatUtils.invoke(builder, null, METHOD_setCategory, CATEGORY_RECOMMENDATION);
}
public static void setPriorityToLow(final Notification.Builder builder) {
CompatUtils.invoke(builder, null, METHOD_setPriority, PRIORITY_LOW);
}
@SuppressWarnings("deprecation")
public static Notification build(final Notification.Builder builder) {
// #build was added in API level 16, JELLY_BEAN
return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
// #getNotification was deprecated in API level 16, JELLY_BEAN
}
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import java.lang.reflect.Field;
public final class SettingsSecureCompatUtils {
// Note that Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD has been introduced
// in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1).
private static final Field FIELD_ACCESSIBILITY_SPEAK_PASSWORD = CompatUtils.getField(
android.provider.Settings.Secure.class, "ACCESSIBILITY_SPEAK_PASSWORD");
private SettingsSecureCompatUtils() {
// This class is non-instantiable.
}
/**
* Whether to speak passwords while in accessibility mode.
*/
public static final String ACCESSIBILITY_SPEAK_PASSWORD = (String) CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_ACCESSIBILITY_SPEAK_PASSWORD);
}

View file

@ -1,121 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.latin.SuggestedWords;
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
import org.dslul.openboard.inputmethod.latin.define.DebugFlags;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class SuggestionSpanUtils {
// Note that SuggestionSpan.FLAG_AUTO_CORRECTION has been introduced
// in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1).
private static final Field FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField(
SuggestionSpan.class, "FLAG_AUTO_CORRECTION");
private static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_FLAG_AUTO_CORRECTION);
static {
if (DebugFlags.DEBUG_ENABLED) {
if (OBJ_FLAG_AUTO_CORRECTION == null) {
throw new RuntimeException("Field is accidentially null.");
}
}
}
private SuggestionSpanUtils() {
// This utility class is not publicly instantiable.
}
@UsedForTesting
public static CharSequence getTextWithAutoCorrectionIndicatorUnderline(
final Context context, final String text, @Nonnull final Locale locale) {
if (TextUtils.isEmpty(text) || OBJ_FLAG_AUTO_CORRECTION == null) {
return text;
}
final Spannable spannable = new SpannableString(text);
final SuggestionSpan suggestionSpan = new SuggestionSpan(context, locale,
new String[] {} /* suggestions */, OBJ_FLAG_AUTO_CORRECTION, null);
spannable.setSpan(suggestionSpan, 0, text.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
return spannable;
}
@UsedForTesting
public static CharSequence getTextWithSuggestionSpan(final Context context,
final String pickedWord, final SuggestedWords suggestedWords, final Locale locale) {
if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
|| suggestedWords.isPrediction() || suggestedWords.isPunctuationSuggestions()) {
return pickedWord;
}
final ArrayList<String> suggestionsList = new ArrayList<>();
for (int i = 0; i < suggestedWords.size(); ++i) {
if (suggestionsList.size() >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) {
break;
}
final SuggestedWordInfo info = suggestedWords.getInfo(i);
if (info.isKindOf(SuggestedWordInfo.KIND_PREDICTION)) {
continue;
}
final String word = suggestedWords.getWord(i);
if (!TextUtils.equals(pickedWord, word)) {
suggestionsList.add(word.toString());
}
}
final SuggestionSpan suggestionSpan = new SuggestionSpan(context, locale,
suggestionsList.toArray(new String[suggestionsList.size()]), 0 /* flags */, null);
final Spannable spannable = new SpannableString(pickedWord);
spannable.setSpan(suggestionSpan, 0, pickedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
/**
* Returns first {@link Locale} found in the given array of {@link SuggestionSpan}.
* @param suggestionSpans the array of {@link SuggestionSpan} to be examined.
* @return the first {@link Locale} found in {@code suggestionSpans}. {@code null} when not
* found.
*/
@UsedForTesting
@Nullable
public static Locale findFirstLocaleFromSuggestionSpans(
final SuggestionSpan[] suggestionSpans) {
for (final SuggestionSpan suggestionSpan : suggestionSpans) {
final String localeString = suggestionSpan.getLocale();
if (TextUtils.isEmpty(localeString)) {
continue;
}
return LocaleUtils.constructLocaleFromString(localeString);
}
return null;
}
}

View file

@ -0,0 +1,92 @@
package org.dslul.openboard.inputmethod.compat
import android.content.Context
import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
import android.text.TextUtils
import android.text.style.SuggestionSpan
import org.dslul.openboard.inputmethod.annotations.UsedForTesting
import org.dslul.openboard.inputmethod.latin.SuggestedWords
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
import org.dslul.openboard.inputmethod.latin.define.DebugFlags
import java.util.*
object SuggestionSpanUtils {
// Note that SuggestionSpan.FLAG_AUTO_CORRECTION has been introduced
// in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1).
private val FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField(
SuggestionSpan::class.java, "FLAG_AUTO_CORRECTION")
private val OBJ_FLAG_AUTO_CORRECTION: Int? = CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_FLAG_AUTO_CORRECTION) as Int
@kotlin.jvm.JvmStatic
@UsedForTesting
fun getTextWithAutoCorrectionIndicatorUnderline(
context: Context?, text: String,locale: Locale?): CharSequence {
if (TextUtils.isEmpty(text) || OBJ_FLAG_AUTO_CORRECTION == null) {
return text
}
val spannable: Spannable = SpannableString(text)
val suggestionSpan = SuggestionSpan(context, locale, arrayOf(), OBJ_FLAG_AUTO_CORRECTION, null)
spannable.setSpan(suggestionSpan, 0, text.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE or Spanned.SPAN_COMPOSING)
return spannable
}
@UsedForTesting
fun getTextWithSuggestionSpan(context: Context?,
pickedWord: String, suggestedWords: SuggestedWords, locale: Locale?): CharSequence {
if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty
|| suggestedWords.isPrediction || suggestedWords.isPunctuationSuggestions) {
return pickedWord
}
val suggestionsList = ArrayList<String>()
for (i in 0 until suggestedWords.size()) {
if (suggestionsList.size >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) {
break
}
val info = suggestedWords.getInfo(i)
if (info.isKindOf(SuggestedWordInfo.KIND_PREDICTION)) {
continue
}
val word = suggestedWords.getWord(i)
if (!TextUtils.equals(pickedWord, word)) {
suggestionsList.add(word.toString())
}
}
val suggestionSpan = SuggestionSpan(context, locale,
suggestionsList.toTypedArray(), 0 /* flags */, null)
val spannable: Spannable = SpannableString(pickedWord)
spannable.setSpan(suggestionSpan, 0, pickedWord.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* Returns first [Locale] found in the given array of [SuggestionSpan].
* @param suggestionSpans the array of [SuggestionSpan] to be examined.
* @return the first [Locale] found in `suggestionSpans`. `null` when not
* found.
*/
@UsedForTesting
fun findFirstLocaleFromSuggestionSpans(
suggestionSpans: Array<SuggestionSpan>): Locale? {
for (suggestionSpan in suggestionSpans) {
val localeString = suggestionSpan.locale
if (TextUtils.isEmpty(localeString)) {
continue
}
return LocaleUtils.constructLocaleFromString(localeString)
}
return null
}
init {
if (DebugFlags.DEBUG_ENABLED) {
if (OBJ_FLAG_AUTO_CORRECTION == null) {
throw RuntimeException("Field is accidentially null.")
}
}
}
}

View file

@ -1,47 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.view.textservice.SuggestionsInfo;
import java.lang.reflect.Field;
public final class SuggestionsInfoCompatUtils {
// Note that SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS has been introduced
// in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1).
private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS =
CompatUtils.getField(SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS");
private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS =
(Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);
private static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS =
OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS != null
? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0;
private SuggestionsInfoCompatUtils() {
// This utility class is not publicly instantiable.
}
/**
* Returns the flag value of the attributes of the suggestions that can be obtained by
* {@link SuggestionsInfo#getSuggestionsAttributes()}: this tells that the text service thinks
* the result suggestions include highly recommended ones.
*/
public static int getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() {
return RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS;
}
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.view.textservice.TextInfo;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@UsedForTesting
public final class TextInfoCompatUtils {
// Note that TextInfo.getCharSequence() is supposed to be available in API level 21 and later.
private static final Method TEXT_INFO_GET_CHAR_SEQUENCE =
CompatUtils.getMethod(TextInfo.class, "getCharSequence");
private static final Constructor<?> TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE =
CompatUtils.getConstructor(TextInfo.class, CharSequence.class, int.class, int.class,
int.class, int.class);
@UsedForTesting
public static boolean isCharSequenceSupported() {
return TEXT_INFO_GET_CHAR_SEQUENCE != null &&
TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE != null;
}
@UsedForTesting
public static TextInfo newInstance(CharSequence charSequence, int start, int end, int cookie,
int sequenceNumber) {
if (TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE != null) {
return (TextInfo) CompatUtils.newInstance(TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE,
charSequence, start, end, cookie, sequenceNumber);
}
return new TextInfo(charSequence.subSequence(start, end).toString(), cookie,
sequenceNumber);
}
/**
* Returns the result of {@link TextInfo#getCharSequence()} when available. Otherwise returns
* the result of {@link TextInfo#getText()} as fall back.
* @param textInfo the instance for which {@link TextInfo#getCharSequence()} or
* {@link TextInfo#getText()} is called.
* @return the result of {@link TextInfo#getCharSequence()} when available. Otherwise returns
* the result of {@link TextInfo#getText()} as fall back. If {@code textInfo} is {@code null},
* returns {@code null}.
*/
@UsedForTesting
public static CharSequence getCharSequenceOrString(final TextInfo textInfo) {
final CharSequence defaultValue = (textInfo == null ? null : textInfo.getText());
return (CharSequence) CompatUtils.invoke(textInfo, defaultValue,
TEXT_INFO_GET_CHAR_SEQUENCE);
}
}

View file

@ -0,0 +1,44 @@
package org.dslul.openboard.inputmethod.compat
import android.view.textservice.TextInfo
import org.dslul.openboard.inputmethod.annotations.UsedForTesting
object TextInfoCompatUtils {
// Note that TextInfo.getCharSequence() is supposed to be available in API level 21 and later.
private val TEXT_INFO_GET_CHAR_SEQUENCE = CompatUtils.getMethod(TextInfo::class.java, "getCharSequence")
private val TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE = CompatUtils.getConstructor(TextInfo::class.java, CharSequence::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType,
Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
@get:UsedForTesting
val isCharSequenceSupported: Boolean
get() = TEXT_INFO_GET_CHAR_SEQUENCE != null &&
TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE != null
@kotlin.jvm.JvmStatic
@UsedForTesting
fun newInstance(charSequence: CharSequence, start: Int, end: Int, cookie: Int,
sequenceNumber: Int): TextInfo? {
return if (TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE != null) {
CompatUtils.newInstance(TEXT_INFO_CONSTRUCTOR_FOR_CHAR_SEQUENCE,
charSequence, start, end, cookie, sequenceNumber) as TextInfo
} else TextInfo(charSequence.subSequence(start, end).toString(), cookie,
sequenceNumber)
}
/**
* Returns the result of [TextInfo.getCharSequence] when available. Otherwise returns
* the result of [TextInfo.getText] as fall back.
* @param textInfo the instance for which [TextInfo.getCharSequence] or
* [TextInfo.getText] is called.
* @return the result of [TextInfo.getCharSequence] when available. Otherwise returns
* the result of [TextInfo.getText] as fall back. If `textInfo` is `null`,
* returns `null`.
*/
@kotlin.jvm.JvmStatic
@UsedForTesting
fun getCharSequenceOrString(textInfo: TextInfo?): CharSequence? {
val defaultValue: CharSequence? = textInfo?.text
return CompatUtils.invoke(textInfo, defaultValue!!,
TEXT_INFO_GET_CHAR_SEQUENCE) as CharSequence
}
}

View file

@ -1,44 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.graphics.drawable.Drawable;
import android.widget.TextView;
import java.lang.reflect.Method;
public final class TextViewCompatUtils {
// Note that TextView.setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable,Drawable,
// Drawable,Drawable) has been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static final Method METHOD_setCompoundDrawablesRelativeWithIntrinsicBounds =
CompatUtils.getMethod(TextView.class, "setCompoundDrawablesRelativeWithIntrinsicBounds",
Drawable.class, Drawable.class, Drawable.class, Drawable.class);
private TextViewCompatUtils() {
// This utility class is not publicly instantiable.
}
public static void setCompoundDrawablesRelativeWithIntrinsicBounds(final TextView textView,
final Drawable start, final Drawable top, final Drawable end, final Drawable bottom) {
if (METHOD_setCompoundDrawablesRelativeWithIntrinsicBounds == null) {
textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
return;
}
CompatUtils.invoke(textView, null, METHOD_setCompoundDrawablesRelativeWithIntrinsicBounds,
start, top, end, bottom);
}
}

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.provider.UserDictionary;
import java.util.Locale;
public final class UserDictionaryCompatUtils {
@SuppressWarnings("deprecation")
public static void addWord(final Context context, final String word,
final int freq, final String shortcut, final Locale locale) {
if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
addWordWithShortcut(context, word, freq, shortcut, locale);
return;
}
// Fall back to the pre-JellyBean method.
final Locale currentLocale = context.getResources().getConfiguration().locale;
final int localeType = currentLocale.equals(locale)
? UserDictionary.Words.LOCALE_TYPE_CURRENT : UserDictionary.Words.LOCALE_TYPE_ALL;
UserDictionary.Words.addWord(context, word, freq, localeType);
}
// {@link UserDictionary.Words#addWord(Context,String,int,String,Locale)} was introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void addWordWithShortcut(final Context context, final String word,
final int freq, final String shortcut, final Locale locale) {
UserDictionary.Words.addWord(context, word, freq, shortcut, locale);
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.content.Context;
import android.os.Build;
import android.os.UserManager;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.reflect.Method;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* A temporary solution until {@code UserManagerCompat.isUserUnlocked()} in the support-v4 library
* becomes publicly available.
*/
public final class UserManagerCompatUtils {
private static final Method METHOD_isUserUnlocked;
static {
// We do not try to search the method in Android M and prior.
if (BuildCompatUtils.EFFECTIVE_SDK_INT <= Build.VERSION_CODES.M) {
METHOD_isUserUnlocked = null;
} else {
METHOD_isUserUnlocked = CompatUtils.getMethod(UserManager.class, "isUserUnlocked");
}
}
private UserManagerCompatUtils() {
// This utility class is not publicly instantiable.
}
public static final int LOCK_STATE_UNKNOWN = 0;
public static final int LOCK_STATE_UNLOCKED = 1;
public static final int LOCK_STATE_LOCKED = 2;
@Retention(SOURCE)
@IntDef({LOCK_STATE_UNKNOWN, LOCK_STATE_UNLOCKED, LOCK_STATE_LOCKED})
public @interface LockState {}
/**
* Check if the calling user is running in an "unlocked" state. A user is unlocked only after
* they've entered their credentials (such as a lock pattern or PIN), and credential-encrypted
* private app data storage is available.
* @param context context from which {@link UserManager} should be obtained.
* @return One of {@link LockState}.
*/
@LockState
public static int getUserLockState(final Context context) {
if (METHOD_isUserUnlocked == null) {
return LOCK_STATE_UNKNOWN;
}
final UserManager userManager = context.getSystemService(UserManager.class);
if (userManager == null) {
return LOCK_STATE_UNKNOWN;
}
final Boolean result =
(Boolean) CompatUtils.invoke(userManager, null, METHOD_isUserUnlocked);
if (result == null) {
return LOCK_STATE_UNKNOWN;
}
return result ? LOCK_STATE_UNLOCKED : LOCK_STATE_LOCKED;
}
}

View file

@ -0,0 +1,52 @@
package org.dslul.openboard.inputmethod.compat
import android.content.Context
import android.os.Build
import android.os.Build.VERSION_CODES
import android.os.UserManager
import androidx.annotation.IntDef
import androidx.annotation.RequiresApi
import java.lang.reflect.Method
/**
* A temporary solution until `UserManagerCompat.isUserUnlocked()` in the support-v4 library
* becomes publicly available.
*/
object UserManagerCompatUtils {
private var METHOD_isUserUnlocked: Method? = null
const val LOCK_STATE_UNKNOWN = 0
const val LOCK_STATE_UNLOCKED = 1
const val LOCK_STATE_LOCKED = 2
/**
* Check if the calling user is running in an "unlocked" state. A user is unlocked only after
* they've entered their credentials (such as a lock pattern or PIN), and credential-encrypted
* private app data storage is available.
* @param context context from which [UserManager] should be obtained.
* @return One of [LockState].
*/
@RequiresApi(VERSION_CODES.M)
@kotlin.jvm.JvmStatic
@LockState
fun getUserLockState(context: Context): Int {
if (METHOD_isUserUnlocked == null) {
return LOCK_STATE_UNKNOWN
}
val userManager = context.getSystemService(UserManager::class.java)
?: return LOCK_STATE_UNKNOWN
val result = CompatUtils.invoke(userManager, null, METHOD_isUserUnlocked) as Boolean
?: return LOCK_STATE_UNKNOWN
return if (result) LOCK_STATE_UNLOCKED else LOCK_STATE_LOCKED
}
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
@IntDef(LOCK_STATE_UNKNOWN, LOCK_STATE_UNLOCKED, LOCK_STATE_LOCKED)
annotation class LockState
init { // We do not try to search the method in Android M and prior.
METHOD_isUserUnlocked = if (Build.VERSION.SDK_INT <= VERSION_CODES.M) {
null
} else {
CompatUtils.getMethod(UserManager::class.java, "isUserUnlocked")
}
}
}

View file

@ -1,70 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.view.View;
import java.lang.reflect.Method;
// TODO: Use {@link androidx.core.view.ViewCompat} instead of this utility class.
// Currently {@link #getPaddingEnd(View)} and {@link #setPaddingRelative(View,int,int,int,int)}
// are missing from android-support-v4 static library in KitKat SDK.
public final class ViewCompatUtils {
// Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int) have been
// introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod(
View.class, "getPaddingEnd");
private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
View.class, "setPaddingRelative",
int.class, int.class, int.class, int.class);
// Note that View.setTextAlignment(int) has been introduced in API level 17.
private static final Method METHOD_setTextAlignment = CompatUtils.getMethod(
View.class, "setTextAlignment", int.class);
private ViewCompatUtils() {
// This utility class is not publicly instantiable.
}
public static int getPaddingEnd(final View view) {
if (METHOD_getPaddingEnd == null) {
return view.getPaddingRight();
}
return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd);
}
public static void setPaddingRelative(final View view, final int start, final int top,
final int end, final int bottom) {
if (METHOD_setPaddingRelative == null) {
view.setPadding(start, top, end, bottom);
return;
}
CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
}
// These TEXT_ALIGNMENT_* constants have been introduced in API 17.
public static final int TEXT_ALIGNMENT_INHERIT = 0;
public static final int TEXT_ALIGNMENT_GRAVITY = 1;
public static final int TEXT_ALIGNMENT_TEXT_START = 2;
public static final int TEXT_ALIGNMENT_TEXT_END = 3;
public static final int TEXT_ALIGNMENT_CENTER = 4;
public static final int TEXT_ALIGNMENT_VIEW_START = 5;
public static final int TEXT_ALIGNMENT_VIEW_END = 6;
public static void setTextAlignment(final View view, final int textAlignment) {
CompatUtils.invoke(view, null, METHOD_setTextAlignment, textAlignment);
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.view.View;
public class ViewOutlineProviderCompatUtils {
private ViewOutlineProviderCompatUtils() {
// This utility class is not publicly instantiable.
}
public interface InsetsUpdater {
public void setInsets(final InputMethodService.Insets insets);
}
private static final InsetsUpdater EMPTY_INSETS_UPDATER = new InsetsUpdater() {
@Override
public void setInsets(final InputMethodService.Insets insets) {}
};
public static InsetsUpdater setInsetsOutlineProvider(final View view) {
if (BuildCompatUtils.EFFECTIVE_SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return EMPTY_INSETS_UPDATER;
}
return ViewOutlineProviderCompatUtilsLXX.setInsetsOutlineProvider(view);
}
}

View file

@ -0,0 +1,23 @@
package org.dslul.openboard.inputmethod.compat
import android.inputmethodservice.InputMethodService
import android.os.Build
import android.os.Build.VERSION_CODES
import android.view.View
object ViewOutlineProviderCompatUtils {
private val EMPTY_INSETS_UPDATER: InsetsUpdater = object : InsetsUpdater {
override fun setInsets(insets: InputMethodService.Insets) {}
}
@kotlin.jvm.JvmStatic
fun setInsetsOutlineProvider(view: View): InsetsUpdater? {
return if (Build.VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
EMPTY_INSETS_UPDATER
} else ViewOutlineProviderCompatUtilsLXX.setInsetsOutlineProvider(view)
}
interface InsetsUpdater {
fun setInsets(insets: InputMethodService.Insets)
}
}

View file

@ -1,72 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source 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.dslul.openboard.inputmethod.compat;
import android.annotation.TargetApi;
import android.graphics.Outline;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.view.View;
import android.view.ViewOutlineProvider;
import org.dslul.openboard.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class ViewOutlineProviderCompatUtilsLXX {
private ViewOutlineProviderCompatUtilsLXX() {
// This utility class is not publicly instantiable.
}
static InsetsUpdater setInsetsOutlineProvider(final View view) {
final InsetsOutlineProvider provider = new InsetsOutlineProvider(view);
view.setOutlineProvider(provider);
return provider;
}
private static class InsetsOutlineProvider extends ViewOutlineProvider
implements InsetsUpdater {
private final View mView;
private static final int NO_DATA = -1;
private int mLastVisibleTopInsets = NO_DATA;
public InsetsOutlineProvider(final View view) {
mView = view;
view.setOutlineProvider(this);
}
@Override
public void setInsets(final InputMethodService.Insets insets) {
final int visibleTopInsets = insets.visibleTopInsets;
if (mLastVisibleTopInsets != visibleTopInsets) {
mLastVisibleTopInsets = visibleTopInsets;
mView.invalidateOutline();
}
}
@Override
public void getOutline(final View view, final Outline outline) {
if (mLastVisibleTopInsets == NO_DATA) {
// Call default implementation.
ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
return;
}
// TODO: Revisit this when floating/resize keyboard is supported.
outline.setRect(
view.getLeft(), mLastVisibleTopInsets, view.getRight(), view.getBottom());
}
}
}

View file

@ -0,0 +1,44 @@
package org.dslul.openboard.inputmethod.compat
import android.graphics.Outline
import android.inputmethodservice.InputMethodService
import android.view.View
import android.view.ViewOutlineProvider
import org.dslul.openboard.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater
internal object ViewOutlineProviderCompatUtilsLXX {
fun setInsetsOutlineProvider(view: View): InsetsUpdater {
val provider = InsetsOutlineProvider(view)
view.outlineProvider = provider
return provider
}
private class InsetsOutlineProvider(private val mView: View) : ViewOutlineProvider(), InsetsUpdater {
private var mLastVisibleTopInsets = NO_DATA
override fun setInsets(insets: InputMethodService.Insets) {
val visibleTopInsets = insets.visibleTopInsets
if (mLastVisibleTopInsets != visibleTopInsets) {
mLastVisibleTopInsets = visibleTopInsets
mView.invalidateOutline()
}
}
override fun getOutline(view: View, outline: Outline) {
if (mLastVisibleTopInsets == NO_DATA) { // Call default implementation.
BACKGROUND.getOutline(view, outline)
return
}
// TODO: Revisit this when floating/resize keyboard is supported.
outline.setRect(
view.left, mLastVisibleTopInsets, view.right, view.bottom)
}
companion object {
private const val NO_DATA = -1
}
init {
mView.outlineProvider = this
}
}
}

View file

@ -16,12 +16,6 @@
package org.dslul.openboard.inputmethod.keyboard;
import static org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_SHIFT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_SWITCH_ALPHA_SYMBOL;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.Typeface;
@ -46,6 +40,12 @@ import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_SHIFT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_SWITCH_ALPHA_SYMBOL;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
/**
* Class for describing the position and characteristics of a single key in the keyboard.
*/

View file

@ -16,8 +16,6 @@
package org.dslul.openboard.inputmethod.keyboard;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
import android.text.InputType;
import android.text.TextUtils;
import android.view.inputmethod.EditorInfo;
@ -29,6 +27,8 @@ import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils;
import java.util.Arrays;
import java.util.Locale;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
/**
* Unique identifier for each keyboard type.
*/

View file

@ -16,9 +16,6 @@
package org.dslul.openboard.inputmethod.keyboard;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_SETTINGS_KEY;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@ -39,12 +36,10 @@ import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache;
import org.dslul.openboard.inputmethod.latin.InputAttributes;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.define.DebugFlags;
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils;
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils;
import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils;
import org.dslul.openboard.inputmethod.latin.utils.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -55,6 +50,9 @@ import java.util.HashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_SETTINGS_KEY;
/**
* This class represents a set of keyboard layouts. Each of them represents a different keyboard
* specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same
@ -295,7 +293,7 @@ public final class KeyboardLayoutSet {
}
public Builder setSubtype(@Nonnull final RichInputMethodSubtype subtype) {
final boolean asciiCapable = InputMethodSubtypeCompatUtils.isAsciiCapable(subtype);
final boolean asciiCapable = subtype.getmSubtype().isAsciiCapable();
// TODO: Consolidate with {@link InputAttributes}.
@SuppressWarnings("deprecation")
final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions(

View file

@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import org.dslul.openboard.inputmethod.compat.InputMethodServiceCompatUtils;
import org.dslul.openboard.inputmethod.event.Event;
import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPalettesView;
@ -84,8 +83,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mLatinIME = latinIme;
mRichImm = RichInputMethodManager.getInstance();
mState = new KeyboardState(this);
mIsHardwareAcceleratedDrawingEnabled =
InputMethodServiceCompatUtils.enableHardwareAcceleration(mLatinIME);
mIsHardwareAcceleratedDrawingEnabled = mLatinIME.enableHardwareAcceleration();
}
public void updateKeyboardTheme() {

View file

@ -23,7 +23,6 @@ import android.os.Build.VERSION_CODES;
import android.preference.PreferenceManager;
import android.util.Log;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.latin.R;
import java.util.ArrayList;
@ -156,7 +155,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
public static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs) {
saveKeyboardThemeId(themeId, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
saveKeyboardThemeId(themeId, prefs, Build.VERSION.SDK_INT);
}
/* package private for testing */
@ -177,7 +176,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public static KeyboardTheme getKeyboardTheme(final Context context) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final KeyboardTheme[] availableThemeArray = getAvailableThemeArray(context);
return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray);
return getKeyboardTheme(prefs, Build.VERSION.SDK_INT, availableThemeArray);
}
/* package private for testing */

View file

@ -28,7 +28,6 @@ import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@ -60,7 +59,6 @@ import org.dslul.openboard.inputmethod.latin.settings.DebugSettings;
import org.dslul.openboard.inputmethod.latin.utils.LanguageOnSpacebarUtils;
import org.dslul.openboard.inputmethod.latin.utils.TypefaceUtils;
import java.util.Locale;
import java.util.WeakHashMap;
import javax.annotation.Nonnull;

View file

@ -25,7 +25,6 @@ import android.os.Build;
import android.util.Log;
import android.util.Pair;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.keyboard.Key;
import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.keyboard.KeyboardId;
@ -174,7 +173,7 @@ final class EmojiCategory {
int defaultCategoryId = EmojiCategory.ID_SYMBOLS;
addShownCategoryId(EmojiCategory.ID_RECENTS);
if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (canShowUnicodeEightEmoji()) {
defaultCategoryId = EmojiCategory.ID_EIGHT_SMILEY_PEOPLE;
addShownCategoryId(EmojiCategory.ID_EIGHT_SMILEY_PEOPLE);

View file

@ -17,13 +17,14 @@
package org.dslul.openboard.inputmethod.keyboard.emoji;
import android.content.res.Resources;
import androidx.viewpager.widget.ViewPager;
import android.view.View;
import android.widget.LinearLayout;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
import androidx.viewpager.widget.ViewPager;
final class EmojiLayoutParams {
private static final int DEFAULT_KEYBOARD_ROWS = 4;

View file

@ -16,7 +16,6 @@
package org.dslul.openboard.inputmethod.keyboard.emoji;
import androidx.viewpager.widget.PagerAdapter;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
@ -28,6 +27,8 @@ import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.keyboard.KeyboardView;
import org.dslul.openboard.inputmethod.latin.R;
import androidx.viewpager.widget.PagerAdapter;
final class EmojiPalettesAdapter extends PagerAdapter {
private static final String TAG = EmojiPalettesAdapter.class.getSimpleName();
private static final boolean DEBUG_PAGER = false;

View file

@ -16,14 +16,11 @@
package org.dslul.openboard.inputmethod.keyboard.emoji;
import static org.dslul.openboard.inputmethod.latin.common.Constants.NOT_A_COORDINATE;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager;
import android.util.AttributeSet;
import android.util.Pair;
import android.util.TypedValue;
@ -51,6 +48,10 @@ import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
import androidx.viewpager.widget.ViewPager;
import static org.dslul.openboard.inputmethod.latin.common.Constants.NOT_A_COORDINATE;
/**
* View class to implement Emoji palettes.
* The Emoji keyboard consists of group of views layout/emoji_palettes_view.

View file

@ -16,11 +16,11 @@
package org.dslul.openboard.inputmethod.keyboard.internal;
import android.text.TextUtils;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import android.text.TextUtils;
/**
* The string parser of codesArray specification for <GridRows />. The attribute codesArray is an
* array of string.

View file

@ -16,15 +16,15 @@
package org.dslul.openboard.inputmethod.keyboard.internal;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT;
import static org.dslul.openboard.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
/**
* The string parser of the key specification.
*

View file

@ -22,7 +22,6 @@ import android.util.SparseArray;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.utils.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

View file

@ -38,7 +38,6 @@ import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
import org.dslul.openboard.inputmethod.latin.utils.XmlParseUtils;
import org.dslul.openboard.inputmethod.latin.utils.XmlParseUtils.ParseException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

View file

@ -24,7 +24,6 @@ import org.dslul.openboard.inputmethod.keyboard.Key;
import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
import org.xmlpull.v1.XmlPullParser;
import java.util.ArrayDeque;

View file

@ -16,10 +16,10 @@
package org.dslul.openboard.inputmethod.keyboard.internal;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import android.util.Log;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import java.util.Arrays;
/**

View file

@ -19,7 +19,6 @@ package org.dslul.openboard.inputmethod.keyboard.internal;
import android.text.TextUtils;
import android.util.SparseIntArray;
import org.dslul.openboard.inputmethod.compat.CharacterCompat;
import org.dslul.openboard.inputmethod.keyboard.Key;
import org.dslul.openboard.inputmethod.latin.common.CollectionUtils;
import org.dslul.openboard.inputmethod.latin.common.Constants;
@ -129,7 +128,7 @@ public final class MoreKeySpec {
public void addLetter(@Nonnull final Key key) {
final int code = key.getCode();
if (CharacterCompat.isAlphabetic(code)) {
if (Character.isAlphabetic(code)) {
mCodes.put(code, 0);
} else if (code == Constants.CODE_OUTPUT_TEXT) {
mTexts.add(key.getOutputText());
@ -138,7 +137,7 @@ public final class MoreKeySpec {
public boolean contains(@Nonnull final MoreKeySpec moreKey) {
final int code = moreKey.mCode;
if (CharacterCompat.isAlphabetic(code) && mCodes.indexOfKey(code) >= 0) {
if (Character.isAlphabetic(code) && mCodes.indexOfKey(code) >= 0) {
return true;
} else if (code == Constants.CODE_OUTPUT_TEXT && mTexts.contains(moreKey.mOutputText)) {
return true;

View file

@ -16,11 +16,11 @@
package org.dslul.openboard.inputmethod.keyboard.internal;
import android.util.Log;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.keyboard.internal.MatrixUtils.MatrixOperationFailedException;
import android.util.Log;
import java.util.Arrays;
/**

View file

@ -28,21 +28,15 @@ import android.text.TextUtils;
import android.util.Log;
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants;
import org.dslul.openboard.inputmethod.dictionarypack.MD5Calculator;
import org.dslul.openboard.inputmethod.latin.common.FileUtils;
import org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants;
import org.dslul.openboard.inputmethod.latin.utils.DictionaryInfoUtils;
import org.dslul.openboard.inputmethod.latin.utils.DictionaryInfoUtils.DictionaryInfo;
import org.dslul.openboard.inputmethod.latin.utils.FileTransforms;
import org.dslul.openboard.inputmethod.latin.utils.MetadataFileUriGetter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

View file

@ -25,7 +25,6 @@ import android.text.TextUtils;
import android.util.Log;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import java.util.ArrayList;
import java.util.Collections;

View file

@ -22,9 +22,9 @@ import org.dslul.openboard.inputmethod.latin.common.ComposedData;
import org.dslul.openboard.inputmethod.latin.settings.SettingsValuesForSuggestion;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
/**
* Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key

View file

@ -16,12 +16,12 @@
package org.dslul.openboard.inputmethod.latin;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.util.Log;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/**
* Cache for dictionary facilitators of multiple locales.
* This class automatically creates and releases up to 3 facilitator instances using LRU policy.

View file

@ -16,9 +16,6 @@
package org.dslul.openboard.inputmethod.latin;
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants;
import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -28,6 +25,9 @@ import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.util.Log;
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants;
import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask;
/**
* Receives broadcasts pertaining to dictionary management and takes the appropriate action.
*

View file

@ -27,7 +27,6 @@ import org.dslul.openboard.inputmethod.latin.settings.Settings;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;

View file

@ -16,10 +16,6 @@
package org.dslul.openboard.inputmethod.latin;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
import android.text.InputType;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
@ -30,6 +26,10 @@ import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils;
import java.util.ArrayList;
import java.util.Arrays;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
/**
* Class to hold attributes of the input field.
*/

View file

@ -16,10 +16,6 @@
package org.dslul.openboard.inputmethod.latin;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
import android.Manifest.permission;
import android.app.ActivityOptions;
import android.app.AlertDialog;
@ -40,7 +36,6 @@ import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.text.InputType;
import android.text.TextUtils;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@ -57,10 +52,7 @@ import android.view.inputmethod.InputMethodSubtype;
import org.dslul.openboard.inputmethod.accessibility.AccessibilityUtils;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.compat.EditorInfoCompatUtils;
import org.dslul.openboard.inputmethod.compat.InputMethodServiceCompatUtils;
import org.dslul.openboard.inputmethod.compat.InputMethodSubtypeCompatUtils;
import org.dslul.openboard.inputmethod.compat.ViewOutlineProviderCompatUtils;
import org.dslul.openboard.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants;
@ -109,6 +101,10 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
/**
* Input method implementation for Qwerty'ish keyboard.
*/
@ -583,8 +579,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSettings = Settings.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
mStatsUtilsManager = StatsUtilsManager.getInstance();
mIsHardwareAcceleratedDrawingEnabled =
InputMethodServiceCompatUtils.enableHardwareAcceleration(this);
mIsHardwareAcceleratedDrawingEnabled = this.enableHardwareAcceleration();
Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled);
}
@ -1992,7 +1987,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void setNavigationBarVisibility(final boolean visible) {
if (BuildCompatUtils.EFFECTIVE_SDK_INT > Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
// For N and later, IMEs can specify Color.TRANSPARENT to make the navigation bar
// transparent. For other colors the system uses the default color.
getWindow().getWindow().setNavigationBarColor(

View file

@ -17,7 +17,6 @@
package org.dslul.openboard.inputmethod.latin;
import android.inputmethodservice.InputMethodService;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.SpannableStringBuilder;
@ -34,8 +33,8 @@ import android.view.inputmethod.InputMethodManager;
import org.dslul.openboard.inputmethod.compat.InputConnectionCompatUtils;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.UnicodeSurrogate;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import org.dslul.openboard.inputmethod.latin.common.UnicodeSurrogate;
import org.dslul.openboard.inputmethod.latin.inputlogic.PrivateCommandPerformer;
import org.dslul.openboard.inputmethod.latin.settings.SpacingAndPunctuations;
import org.dslul.openboard.inputmethod.latin.utils.CapsModeUtils;

View file

@ -16,8 +16,6 @@
package org.dslul.openboard.inputmethod.latin;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
import android.content.Context;
import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService;
@ -49,6 +47,8 @@ import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
/**
* Enrichment class for InputMethodManager to simplify interaction and add functionality.
*/

View file

@ -16,13 +16,10 @@
package org.dslul.openboard.inputmethod.latin;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
import android.os.Build;
import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.compat.InputMethodSubtypeCompatUtils;
import org.dslul.openboard.inputmethod.latin.common.Constants;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
@ -34,6 +31,8 @@ import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
/**
* Enrichment class for InputMethodSubtype to enable concurrent multi-lingual input.
*
@ -46,7 +45,7 @@ public class RichInputMethodSubtype {
private static final HashMap<Locale, Locale> sLocaleMap = initializeLocaleMap();
private static final HashMap<Locale, Locale> initializeLocaleMap() {
final HashMap<Locale, Locale> map = new HashMap<>();
if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Locale#forLanguageTag is available on API Level 21+.
// TODO: Remove this workaround once when we become able to deal with "sr-Latn".
map.put(Locale.forLanguageTag("sr-Latn"), new Locale("sr_ZZ"));
@ -54,6 +53,11 @@ public class RichInputMethodSubtype {
return map;
}
@Nonnull
public InputMethodSubtype getmSubtype() {
return mSubtype;
}
@Nonnull
private final InputMethodSubtype mSubtype;
@Nonnull

View file

@ -18,9 +18,6 @@ package org.dslul.openboard.inputmethod.latin;
import android.text.TextUtils;
import static org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants.SHOULD_AUTO_CORRECT_USING_NON_WHITE_LISTED_SUGGESTION;
import static org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants.SHOULD_REMOVE_PREVIOUSLY_REJECTED_SUGGESTION;
import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import org.dslul.openboard.inputmethod.latin.common.Constants;
@ -37,6 +34,9 @@ import java.util.Locale;
import javax.annotation.Nonnull;
import static org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants.SHOULD_AUTO_CORRECT_USING_NON_WHITE_LISTED_SUGGESTION;
import static org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants.SHOULD_REMOVE_PREVIOUSLY_REJECTED_SUGGESTION;
/**
* This class loads a dictionary and provides a list of suggestions for a given sequence of
* characters. This includes corrections and completions.

View file

@ -16,7 +16,6 @@
package org.dslul.openboard.inputmethod.latin;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@ -24,14 +23,12 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Process;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants;
import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet;
import org.dslul.openboard.inputmethod.latin.settings.Settings;
import org.dslul.openboard.inputmethod.latin.setup.SetupActivity;

View file

@ -22,7 +22,6 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.provider.UserDictionary.Words;
import android.text.TextUtils;
import android.util.Log;

View file

@ -1109,8 +1109,7 @@ public final class InputLogic {
StatsUtils.onBackspaceSelectedText(numCharsDeleted);
} else {
// There is no selection, just delete one character.
if (inputTransaction.getMSettingsValues().isBeforeJellyBean()
|| inputTransaction.getMSettingsValues().mInputAttributes.isTypeNull()
if (inputTransaction.getMSettingsValues().mInputAttributes.isTypeNull()
|| Constants.NOT_A_CURSOR_POSITION
== mConnection.getExpectedSelectionEnd()) {
// There are three possible reasons to send a key event: either the field has
@ -1518,10 +1517,7 @@ public final class InputLogic {
// HACK: We may want to special-case some apps that exhibit bad behavior in case of
// recorrection. This is a temporary, stopgap measure that will be removed later.
// TODO: remove this.
if (settingsValues.isBrokenByRecorrection()
// Recorrection is not supported in languages without spaces because we don't know
// how to segment them yet.
|| !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
if (!settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
// If no suggestions are requested, don't try restarting suggestions.
|| !settingsValues.needsToLookupSuggestions()
// If we are currently in a batch input, we must not resume suggestions, or the result
@ -1997,16 +1993,7 @@ public final class InputLogic {
return;
}
// TODO: we should do this also when the editor has TYPE_NULL
if (Constants.CODE_ENTER == codePoint && settingsValues.isBeforeJellyBean()) {
// Backward compatibility mode. Before Jelly bean, the keyboard would simulate
// a hardware keyboard event on pressing enter or delete. This is bad for many
// reasons (there are race conditions with commits) but some applications are
// relying on this behavior so we continue to support it for older apps.
sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER);
} else {
mConnection.commitText(StringUtils.newSingleCodePointString(codePoint), 1);
}
mConnection.commitText(StringUtils.newSingleCodePointString(codePoint), 1);
}
/**

View file

@ -20,10 +20,9 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import org.dslul.openboard.inputmethod.compat.LooperCompatUtils;
import org.dslul.openboard.inputmethod.latin.LatinIME;
import org.dslul.openboard.inputmethod.latin.SuggestedWords;
import org.dslul.openboard.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
import org.dslul.openboard.inputmethod.latin.SuggestedWords;
import org.dslul.openboard.inputmethod.latin.common.InputPointers;
/**
@ -83,7 +82,7 @@ class InputLogicHandler implements Handler.Callback {
// In unit tests, we create several instances of LatinIME, which results in several instances
// of InputLogicHandler. To avoid these handlers lingering, we call this.
public void destroy() {
LooperCompatUtils.quitSafely(mNonUIThreadHandler.getLooper());
mNonUIThreadHandler.getLooper().quitSafely();
}
/**

View file

@ -21,6 +21,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

View file

@ -20,13 +20,14 @@ import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
/**
* Utility class for permissions.
*/

View file

@ -24,8 +24,6 @@ import org.dslul.openboard.inputmethod.latin.BinaryDictionary;
import org.dslul.openboard.inputmethod.latin.Dictionary;
import org.dslul.openboard.inputmethod.latin.ExpandableBinaryDictionary;
import org.dslul.openboard.inputmethod.latin.NgramContext;
import org.dslul.openboard.inputmethod.latin.define.DecoderSpecificConstants;
import org.dslul.openboard.inputmethod.latin.define.ProductionFlags;
import org.dslul.openboard.inputmethod.latin.makedict.DictionaryHeader;
import java.io.File;

View file

@ -21,8 +21,8 @@ import android.content.SharedPreferences;
import android.preference.PreferenceFragment;
import android.view.inputmethod.InputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import javax.annotation.Nonnull;

View file

@ -22,12 +22,10 @@ import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.SystemBroadcastReceiver;
import org.dslul.openboard.inputmethod.latin.define.ProductionFlags;
/**
* "Advanced" settings sub screen.

View file

@ -23,7 +23,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.SwitchPreference;

View file

@ -32,8 +32,6 @@ import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import org.dslul.openboard.inputmethod.compat.InputMethodSubtypeCompatUtils;
import org.dslul.openboard.inputmethod.compat.ViewCompatUtils;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
import org.dslul.openboard.inputmethod.latin.utils.AdditionalSubtypeUtils;
@ -125,8 +123,7 @@ final class CustomInputStylePreference extends DialogPreference
// the view would align them to the left even if the system locale is RTL, but that
// would look strange. To fix this, we align them to the view's start, which will be
// natural for any direction.
ViewCompatUtils.setTextAlignment(
mKeyboardLayoutSetSpinner, ViewCompatUtils.TEXT_ALIGNMENT_VIEW_START);
mKeyboardLayoutSetSpinner.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
return v;
}
@ -295,7 +292,7 @@ final class CustomInputStylePreference extends DialogPreference
subtype.getLocale(), subtype.hashCode(), subtype.hashCode(),
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype)));
}
if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) {
if (subtype.isAsciiCapable()) {
items.add(new SubtypeLocaleItem(subtype));
}
}

View file

@ -26,7 +26,6 @@ import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import androidx.core.view.ViewCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@ -47,6 +46,8 @@ import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.ArrayList;
import androidx.core.view.ViewCompat;
public final class CustomInputStyleSettingsFragment extends PreferenceFragment
implements CustomInputStylePreference.Listener {
private static final String TAG = CustomInputStyleSettingsFragment.class.getSimpleName();

View file

@ -19,7 +19,6 @@ package org.dslul.openboard.inputmethod.latin.settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.preference.Preference;

View file

@ -25,7 +25,6 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager;
import org.dslul.openboard.inputmethod.latin.InputAttributes;
import org.dslul.openboard.inputmethod.latin.R;
@ -73,9 +72,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE =
"pref_key_block_potentially_offensive";
public static final boolean ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS =
BuildCompatUtils.EFFECTIVE_SDK_INT <= Build.VERSION_CODES.KITKAT;
Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT;
public static final boolean SHOULD_SHOW_LXX_SUGGESTION_UI =
BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY =
"pref_show_language_switch_key";
public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =

View file

@ -16,17 +16,15 @@
package org.dslul.openboard.inputmethod.latin.settings;
import org.dslul.openboard.inputmethod.latin.permissions.PermissionsManager;
import org.dslul.openboard.inputmethod.latin.utils.FragmentUtils;
import org.dslul.openboard.inputmethod.latin.utils.StatsUtils;
import org.dslul.openboard.inputmethod.latin.utils.StatsUtilsManager;
import android.app.ActionBar;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import org.dslul.openboard.inputmethod.latin.permissions.PermissionsManager;
import org.dslul.openboard.inputmethod.latin.utils.FragmentUtils;
import androidx.core.app.ActivityCompat;
import android.view.MenuItem;
public final class SettingsActivity extends PreferenceActivity
implements ActivityCompat.OnRequestPermissionsResultCallback {

View file

@ -28,7 +28,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.define.ProductionFlags;
import org.dslul.openboard.inputmethod.latin.utils.ApplicationUtils;
import org.dslul.openboard.inputmethod.latin.utils.FeedbackUtils;
import org.dslul.openboard.inputmethod.latin.utils.JniUtils;

View file

@ -21,7 +21,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
@ -292,18 +291,6 @@ public class SettingsValues {
return mDisplayOrientation == configuration.orientation;
}
public boolean isBeforeJellyBean() {
final AppWorkaroundsUtils appWorkaroundUtils
= mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE);
return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBeforeJellyBean();
}
public boolean isBrokenByRecorrection() {
final AppWorkaroundsUtils appWorkaroundUtils
= mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE);
return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection();
}
private static final String SUGGESTIONS_VISIBILITY_HIDE_VALUE_OBSOLETE = "2";
private static boolean readSuggestionsEnabled(final SharedPreferences prefs) {

View file

@ -21,7 +21,6 @@ import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@ -30,6 +29,8 @@ import android.widget.TextView;
import org.dslul.openboard.inputmethod.latin.R;
import androidx.core.view.ViewCompat;
public final class SetupStartIndicatorView extends LinearLayout {
public SetupStartIndicatorView(final Context context, final AttributeSet attrs) {
super(context, attrs);

View file

@ -20,12 +20,13 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import org.dslul.openboard.inputmethod.latin.R;
import androidx.core.view.ViewCompat;
public final class SetupStepIndicatorView extends View {
private final Path mIndicatorPath = new Path();
private final Paint mIndicatorPaint = new Paint();

View file

@ -33,8 +33,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.VideoView;
import org.dslul.openboard.inputmethod.compat.TextViewCompatUtils;
import org.dslul.openboard.inputmethod.compat.ViewCompatUtils;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.settings.SettingsActivity;
import org.dslul.openboard.inputmethod.latin.utils.LeakGuardHandlerWrapper;
@ -222,8 +220,8 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL
mActionNext = findViewById(R.id.setup_next);
mActionNext.setOnClickListener(this);
mActionFinish = (TextView)findViewById(R.id.setup_finish);
TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(mActionFinish,
getResources().getDrawable(R.drawable.ic_setup_finish), null, null, null);
mActionFinish.setCompoundDrawablesRelativeWithIntrinsicBounds(getResources().getDrawable(R.drawable.ic_setup_finish),
null, null, null);
mActionFinish.setOnClickListener(this);
}
@ -460,11 +458,11 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL
mActionLabel = (TextView)mStepView.findViewById(R.id.setup_step_action_label);
mActionLabel.setText(res.getString(actionLabel));
if (actionIcon == 0) {
final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
final int paddingEnd = mActionLabel.getPaddingEnd();
mActionLabel.setPaddingRelative(paddingEnd, 0, paddingEnd, 0);
} else {
TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
mActionLabel, res.getDrawable(actionIcon), null, null, null);
mActionLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(
res.getDrawable(actionIcon), null, null, null);
}
}

View file

@ -27,7 +27,6 @@ import android.util.LruCache;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import org.dslul.openboard.inputmethod.compat.SuggestionsInfoCompatUtils;
import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.latin.NgramContext;
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@ -312,8 +311,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final int flags =
SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
| (result.mHasRecommendedSuggestions
? SuggestionsInfoCompatUtils
.getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS()
? SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS
: 0);
final SuggestionsInfo retval = new SuggestionsInfo(flags, result.mSuggestions);
mSuggestionsCache.putSuggestionsToCache(text, result.mSuggestions, flags);

View file

@ -16,14 +16,15 @@
package org.dslul.openboard.inputmethod.latin.spellcheck;
import org.dslul.openboard.inputmethod.latin.permissions.PermissionsManager;
import org.dslul.openboard.inputmethod.latin.utils.FragmentUtils;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import org.dslul.openboard.inputmethod.latin.permissions.PermissionsManager;
import org.dslul.openboard.inputmethod.latin.utils.FragmentUtils;
import androidx.core.app.ActivityCompat;
/**

View file

@ -21,7 +21,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import androidx.core.view.ViewCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
@ -55,6 +54,8 @@ import org.dslul.openboard.inputmethod.latin.utils.ImportantNoticeUtils;
import java.util.ArrayList;
import androidx.core.view.ViewCompat;
public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
OnLongClickListener {
public interface Listener {

View file

@ -26,7 +26,6 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import org.dslul.openboard.inputmethod.compat.UserDictionaryCompatUtils;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
@ -184,7 +183,7 @@ public class UserDictionaryAddWordContents {
// In this class we use the empty string to represent 'all locales' and mLocale cannot
// be null. However the addWord method takes null to mean 'all locales'.
UserDictionaryCompatUtils.addWord(context, newWord.toString(),
UserDictionary.Words.addWord(context, newWord.toString(),
FREQUENCY_FOR_USER_DICTIONARY_ADDS, newShortcut, TextUtils.isEmpty(mLocale) ?
null : LocaleUtils.constructLocaleFromString(mLocale));

View file

@ -16,10 +16,6 @@
package org.dslul.openboard.inputmethod.latin.userdictionary;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.userdictionary.UserDictionaryAddWordContents.LocaleRenderer;
import org.dslul.openboard.inputmethod.latin.userdictionary.UserDictionaryLocalePicker.LocationChangedListener;
import android.app.Fragment;
import android.os.Bundle;
import android.preference.PreferenceActivity;
@ -33,6 +29,10 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.userdictionary.UserDictionaryAddWordContents.LocaleRenderer;
import org.dslul.openboard.inputmethod.latin.userdictionary.UserDictionaryLocalePicker.LocationChangedListener;
import java.util.ArrayList;
import java.util.Locale;

View file

@ -16,14 +16,11 @@
package org.dslul.openboard.inputmethod.latin.userdictionary;
import org.dslul.openboard.inputmethod.latin.R;
import android.app.ListFragment;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.provider.UserDictionary;
import android.text.TextUtils;
@ -40,6 +37,8 @@ import android.widget.SectionIndexer;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import org.dslul.openboard.inputmethod.latin.R;
import java.util.Locale;
// Caveat: This class is basically taken from

View file

@ -16,12 +16,12 @@
package org.dslul.openboard.inputmethod.latin.userdictionary;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
import android.content.Context;
import android.text.TextUtils;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils;
import java.util.Locale;
/**

View file

@ -16,13 +16,6 @@
package org.dslul.openboard.inputmethod.latin.utils;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
@ -36,6 +29,13 @@ import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
import static org.dslul.openboard.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
public final class AdditionalSubtypeUtils {
private static final String TAG = AdditionalSubtypeUtils.class.getSimpleName();

View file

@ -30,7 +30,6 @@ import android.view.ViewParent;
import android.view.inputmethod.CursorAnchorInfo;
import android.widget.TextView;
import org.dslul.openboard.inputmethod.compat.BuildCompatUtils;
import org.dslul.openboard.inputmethod.compat.CursorAnchorInfoCompatWrapper;
import javax.annotation.Nonnull;
@ -96,7 +95,7 @@ public final class CursorAnchorInfoUtils {
@Nullable
public static CursorAnchorInfoCompatWrapper extractFromTextView(
@Nonnull final TextView textView) {
if (BuildCompatUtils.EFFECTIVE_SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return null;
}
return CursorAnchorInfoCompatWrapper.wrap(extractFromTextViewInternal(textView));

Some files were not shown because too many files have changed in this diff Show more