address some more warnings

This commit is contained in:
Helium314 2023-09-09 12:51:49 +02:00
parent af1eb551cf
commit e543788920
10 changed files with 77 additions and 52 deletions

View file

@ -2,6 +2,7 @@ package org.dslul.openboard.inputmethod.accessibility
import android.content.Context
import android.media.AudioManager
import android.os.Build
import android.os.SystemClock
import android.provider.Settings
import android.text.TextUtils
@ -12,7 +13,6 @@ import android.view.ViewGroup
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.latin.R
import org.dslul.openboard.inputmethod.latin.SuggestedWords
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils
@ -127,17 +127,17 @@ class AccessibilityUtils private constructor() {
return
}
// The following is a hack to avoid using the heavy-weight TextToSpeech
// class. Instead, we're just forcing a fake AccessibilityEvent into
// the screen reader to make it speak.
val event = AccessibilityEvent.obtain()
// class. Instead, we're just forcing a fake AccessibilityEvent into
// the screen reader to make it speak.
val event = obtainEvent()
event.packageName = PACKAGE
event.className = CLASS
event.eventTime = SystemClock.uptimeMillis()
event.isEnabled = true
event.text.add(text)
// Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use
// announce events.
event.eventType = AccessibilityEventCompat.TYPE_ANNOUNCEMENT
// announce events.
event.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT
val viewParent = view.parent
if (viewParent == null || viewParent !is ViewGroup) {
Log.e(TAG, "Failed to obtain ViewParent in announceForAccessibility")
@ -205,5 +205,21 @@ class AccessibilityUtils private constructor() {
val action = event.action
return action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_EXIT || action == MotionEvent.ACTION_HOVER_MOVE
}
fun obtainEvent(eventType: Int): AccessibilityEvent =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AccessibilityEvent(eventType)
} else {
@Suppress("deprecation")
AccessibilityEvent.obtain(eventType)
}
fun obtainEvent(): AccessibilityEvent =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AccessibilityEvent()
} else {
@Suppress("deprecation")
AccessibilityEvent.obtain()
}
}
}

View file

@ -73,8 +73,7 @@ open class KeyboardAccessibilityDelegate<KV : KeyboardView?>(protected val mKeyb
* @param text The text to send with the event.
*/
protected fun sendWindowStateChanged(text: String?) {
val stateChange = AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
val stateChange = AccessibilityUtils.obtainEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
mKeyboardView!!.onInitializeAccessibilityEvent(stateChange)
stateChange.text.add(text)
stateChange.contentDescription = null

View file

@ -1,10 +1,12 @@
package org.dslul.openboard.inputmethod.accessibility
import android.graphics.Rect
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityRecord
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityEventCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
@ -91,12 +93,12 @@ class KeyboardAccessibilityNodeProvider<KV : KeyboardView?>(keyboardView: KV,
fun createAccessibilityEvent(key: Key, eventType: Int): AccessibilityEvent {
val virtualViewId = getVirtualViewIdOf(key)
val keyDescription = getKeyDescription(key)
val event = AccessibilityEvent.obtain(eventType)
val event = AccessibilityUtils.obtainEvent(eventType)
event.packageName = mKeyboardView!!.context.packageName
event.className = key.javaClass.name
event.contentDescription = keyDescription
event.isEnabled = true
val record = AccessibilityEventCompat.asRecord(event)
val record: AccessibilityRecord = event
record.setSource(mKeyboardView, virtualViewId)
return event
}
@ -111,16 +113,16 @@ class KeyboardAccessibilityNodeProvider<KV : KeyboardView?>(keyboardView: KV,
// announcements.
mHoveringNodeId = id
// Invalidate the node info of the key.
sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED)
sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER)
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)
}
fun onHoverExitFrom(key: Key) {
mHoveringNodeId = UNDEFINED
// Invalidate the node info of the key to be able to revert the change we have done
// in {@link #onHoverEnterTo(Key)}.
sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED)
sendAccessibilityEventForKey(key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT)
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT)
}
/**
@ -292,8 +294,8 @@ class KeyboardAccessibilityNodeProvider<KV : KeyboardView?>(keyboardView: KV,
}
init {
mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.Companion.instance
mAccessibilityUtils = AccessibilityUtils.Companion.instance
mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.instance
mAccessibilityUtils = AccessibilityUtils.instance
mKeyboardView = keyboardView
mDelegate = delegate
// Since this class is constructed lazily, we might not get a subsequent

View file

@ -24,8 +24,8 @@ object CompatUtils {
}
try {
return targetClass.getMethod(name!!, *parameterTypes)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchMethodException) {
} catch (_: SecurityException) { // ignore
} catch (_: NoSuchMethodException) {
}
return null
}
@ -36,8 +36,8 @@ object CompatUtils {
}
try {
return targetClass.getField(name!!)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchFieldException) {
} catch (_: SecurityException) { // ignore
} catch (_: NoSuchFieldException) {
}
return null
}
@ -49,8 +49,8 @@ object CompatUtils {
}
try {
return targetClass.getConstructor(*types)
} catch (e: SecurityException) { // ignore
} catch (e: NoSuchMethodException) {
} catch (_: SecurityException) { // ignore
} catch (_: NoSuchMethodException) {
}
return null
}
@ -153,9 +153,10 @@ object CompatUtils {
}
@Suppress("unchecked_cast")
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
return CompatUtils.invoke(receiver, mDefaultValue, mMethod, *args) as T
}
}

View file

@ -2,28 +2,24 @@ 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 org.dslul.openboard.inputmethod.latin.settings.locale
import java.util.*
object InputMethodSubtypeCompatUtils {
// 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
@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)) {
if (!languageTag.isNullOrEmpty()) {
return Locale.forLanguageTag(languageTag)
}
}
return LocaleUtils.constructLocaleFromString(subtype.locale)
return LocaleUtils.constructLocaleFromString(subtype.locale())
}
}

View file

@ -87,6 +87,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
layoutManager = StaggeredGridLayoutManager(colCount, StaggeredGridLayoutManager.VERTICAL)
val dividerHeight = resources.getDimensionPixelSize(R.dimen.config_clipboard_divider_height)
addItemDecoration(ClipboardHistoryRecyclerView.BottomDividerItemDecoration(dividerHeight, dividerColor))
@Suppress("deprecation") // no cache should be fine according to warning in https://developer.android.com/reference/android/view/ViewGroup#setPersistentDrawingCache(int)
persistentDrawingCache = PERSISTENT_NO_CACHE
clipboardLayoutParams.setListProperties(this)
placeholderView = this@ClipboardHistoryView.placeholderView
@ -222,8 +223,8 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardRecyclerView.smoothScrollToPosition(at)
}
override fun onClipboardHistoryEntriesRemoved(position: Int, count: Int) {
clipboardAdapter.notifyItemRangeRemoved(position, count)
override fun onClipboardHistoryEntriesRemoved(pos: Int, count: Int) {
clipboardAdapter.notifyItemRangeRemoved(pos, count)
}
override fun onClipboardHistoryEntryMoved(from: Int, to: Int) {

View file

@ -3,7 +3,6 @@ package org.dslul.openboard.inputmethod.latin.settings
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
@ -179,7 +178,7 @@ class LanguageSettingsDialog(
private fun fillDictionariesView(dictionariesView: LinearLayout) {
dictionariesView.findViewById<ImageView>(R.id.add_dictionary).setOnClickListener {
val link = "<a href='$DICTIONARY_URL'>" + context.getString(R.string.dictionary_link_text) + "</a>"
val message = Html.fromHtml(context.getString(R.string.add_dictionary, link))
val message = SpannableStringUtils.fromHtml(context.getString(R.string.add_dictionary, link))
val dialog = Builder(context)
.setTitle(R.string.add_new_dictionary_title)
.setMessage(message)

View file

@ -259,4 +259,8 @@ private val systemSubtypes = mutableListOf<InputMethodSubtype>()
private const val SUBTYPE_SEPARATOR = ";"
private const val LOCALE_LAYOUT_SEPARATOR = ":"
@Suppress("deprecation") // it's deprecated, but no replacement for API < 24
// todo: add language tags in method.xml, and adjust this method to use locale only if necessary
// but then language tag should be converted to locale, or other way!
// see also InputMethodSubtypeCompatUtils
fun InputMethodSubtype.locale() = locale

View file

@ -1,7 +1,6 @@
package org.dslul.openboard.inputmethod.latin.utils
import android.content.Context
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.View
import android.widget.TextView
@ -49,7 +48,7 @@ fun showMissingDictionaryDialog(context: Context, locale: Locale) {
val dictionaryLink = "<a href='$DICTIONARY_URL/src/branch/main/dictionaries/main_$locale.dict'>" + context.getString(
R.string.dictionary_link_text) + "</a>"
val message = Html.fromHtml(context.getString(
val message = SpannableStringUtils.fromHtml(context.getString(
R.string.no_dictionary_message,
repositoryLink,
locale.toString(),

View file

@ -16,6 +16,8 @@
package org.dslul.openboard.inputmethod.latin.utils;
import android.os.Build;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
@ -50,8 +52,8 @@ public final class SpannableStringUtils {
Spannable dest, int destoff) {
Object[] spans = source.getSpans(start, end, SuggestionSpan.class);
for (int i = 0; i < spans.length; i++) {
int fl = source.getSpanFlags(spans[i]);
for (Object span : spans) {
int fl = source.getSpanFlags(span);
// We don't care about the PARAGRAPH flag in LatinIME code. However, if this flag
// is set, Spannable#setSpan will throw an exception unless the span is on the edge
// of a word. But the spans have been split into two by the getText{Before,After}Cursor
@ -59,16 +61,15 @@ public final class SpannableStringUtils {
// Since we don't use them, we can just remove them and avoid crashing.
fl &= ~Spanned.SPAN_PARAGRAPH;
int st = source.getSpanStart(spans[i]);
int en = source.getSpanEnd(spans[i]);
int st = source.getSpanStart(span);
int en = source.getSpanEnd(span);
if (st < start)
st = start;
if (en > end)
en = end;
dest.setSpan(spans[i], st - start + destoff, en - start + destoff,
fl);
dest.setSpan(span, st - start + destoff, en - start + destoff, fl);
}
}
@ -89,16 +90,16 @@ public final class SpannableStringUtils {
}
boolean spanned = false;
for (int i = 0; i < text.length; i++) {
if (text[i] instanceof Spanned) {
for (CharSequence value : text) {
if (value instanceof Spanned) {
spanned = true;
break;
}
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length; i++) {
sb.append(text[i]);
for (CharSequence sequence : text) {
sb.append(sequence);
}
if (!spanned) {
@ -107,11 +108,11 @@ public final class SpannableStringUtils {
SpannableString ss = new SpannableString(sb);
int off = 0;
for (int i = 0; i < text.length; i++) {
int len = text[i].length();
for (CharSequence charSequence : text) {
int len = charSequence.length();
if (text[i] instanceof Spanned) {
copyNonParagraphSuggestionSpansFrom((Spanned) text[i], 0, len, ss, off);
if (charSequence instanceof Spanned) {
copyNonParagraphSuggestionSpansFrom((Spanned) charSequence, 0, len, ss, off);
}
off += len;
@ -120,6 +121,13 @@ public final class SpannableStringUtils {
return new SpannedString(ss);
}
@SuppressWarnings("deprecation")
public static Spanned fromHtml(final String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
return Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
return Html.fromHtml(text);
}
public static boolean hasUrlSpans(final CharSequence text,
final int startIndex, final int endIndex) {
if (!(text instanceof Spanned)) {
@ -178,6 +186,6 @@ public final class SpannableStringUtils {
sequences.remove(i);
}
}
return sequences.toArray(new CharSequence[sequences.size()]);
return sequences.toArray(new CharSequence[0]);
}
}