From adba4542b286b8fb9e388c264b7378f018b9be91 Mon Sep 17 00:00:00 2001 From: Brayan Oliveira <69634269+brayandso@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:27:27 -0300 Subject: [PATCH] refactor: add MenuItemImpl utils will be used in the next commit refactor: move getJavaFieldAsAccessible to main I also changed the method to not throw by default if the field name could not be found --- .../java/com/ichi2/anki/utils/Reflection.kt | 38 +++++++++++++++++++ .../com/ichi2/anki/utils/ext/MenuItemImpl.kt | 30 +++++++++++++++ .../anki/preferences/SettingsSearchBarTest.kt | 10 ++--- .../com/ichi2/testutils/ReflectionUtils.kt | 13 ------- 4 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/utils/Reflection.kt create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/MenuItemImpl.kt diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/utils/Reflection.kt b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Reflection.kt new file mode 100644 index 000000000000..9304779d0da9 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Reflection.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Brayan Oliveira + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +package com.ichi2.anki.utils + +import timber.log.Timber +import java.lang.reflect.Field + +/** + * @param clazz Java class to get the field + * @param fieldName name of the field + * @return a [Field] with `isAccessible` set to true, or null if the field could not be found + */ +fun getJavaFieldAsAccessible( + clazz: Class<*>, + fieldName: String, +): Field? { + val field = + clazz.declaredFields.firstOrNull { it.name == fieldName }?.apply { + isAccessible = true + } + if (field == null) { + Timber.d("Could not find field $fieldName in class $clazz") + } + return field +} diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/MenuItemImpl.kt b/AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/MenuItemImpl.kt new file mode 100644 index 000000000000..7ee8bdf8a4a8 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/MenuItemImpl.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Brayan Oliveira + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +package com.ichi2.anki.utils.ext + +import androidx.appcompat.view.menu.MenuBuilder +import androidx.appcompat.view.menu.MenuItemImpl +import com.ichi2.anki.utils.getJavaFieldAsAccessible + +fun MenuItemImpl.removeSubMenu() { + val subMenuField = getJavaFieldAsAccessible(MenuItemImpl::class.java, "mSubMenu") + subMenuField?.set(this, null) +} + +val MenuItemImpl.menu: MenuBuilder get() { + val menuField = getJavaFieldAsAccessible(MenuItemImpl::class.java, "mMenu") + return menuField?.get(this) as MenuBuilder +} diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt index 9933b1c0dc9d..ff4f03c0bc8b 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt @@ -19,7 +19,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bytehamster.lib.preferencesearch.PreferenceItem import com.bytehamster.lib.preferencesearch.SearchConfiguration import com.ichi2.anki.RobolectricTest -import com.ichi2.testutils.getJavaFieldAsAccessible +import com.ichi2.anki.utils.getJavaFieldAsAccessible import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.junit.Test @@ -44,17 +44,17 @@ class SettingsSearchBarTest : RobolectricTest() { val prefItemResIdField = getJavaFieldAsAccessible(PreferenceItem::class.java, "resId") // Get the resIds of the files indexed with `SearchConfiguration.index` - val filesToIndex = filesToIndexField.get(searchConfig) as ArrayList + val filesToIndex = filesToIndexField?.get(searchConfig) as ArrayList val filesResIds = filesToIndex.map { - searchItemResIdField.get(it) + searchItemResIdField?.get(it) } // Get the resIds of preferences indexed with `SearchConfiguration.indexItem` - val preferencesToIndex = preferencesToIndexField.get(searchConfig) as ArrayList + val preferencesToIndex = preferencesToIndexField?.get(searchConfig) as ArrayList val prefItemsResIds = preferencesToIndex.map { - prefItemResIdField.get(it) + prefItemResIdField?.get(it) } // Join both lists diff --git a/AnkiDroid/src/test/java/com/ichi2/testutils/ReflectionUtils.kt b/AnkiDroid/src/test/java/com/ichi2/testutils/ReflectionUtils.kt index fed562251aad..c4b2c7adc210 100644 --- a/AnkiDroid/src/test/java/com/ichi2/testutils/ReflectionUtils.kt +++ b/AnkiDroid/src/test/java/com/ichi2/testutils/ReflectionUtils.kt @@ -24,19 +24,6 @@ import kotlin.reflect.full.createType /** For use when checking to see if a KType is equal to another type */ inline fun KCallable<*>.isType() = returnType == T::class.createType() -/** - * @param clazz Java class to get the field - * @param fieldName name of the field - * @return a [Field] object with `isAccessible` set to true - */ -fun getJavaFieldAsAccessible( - clazz: Class<*>, - fieldName: String, -): Field = - clazz.getDeclaredField(fieldName).apply { - isAccessible = true - } - /** * @param clazz Java class to get the field * @param methodName name of the method