diff --git a/AGENTS.md b/AGENTS.md index 79f9715c3bdf..63b73f2af614 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,6 +39,12 @@ Project-specific skills live in `./.claude/skills//`. Load a skill w - **`android-java-to-kotlin`** (`./.claude/skills/android-java-to-kotlin/SKILL.md`) — Completes a Java-to-Kotlin conversion in this Android app. Use it when finishing a conversion, when the user mentions "java to kotlin", "j2k", "convert java", or "make it idiomatic", or when a freshly IDE-converted `.kt` file needs cleanup. The workflow is two-person: the developer first runs the Android Studio converter (`Code > Convert Java File to Kotlin File`), then the agent drives the idiomatic second pass — fail-fast control flow, function decomposition, `lifecycleScope`/coroutines instead of Java threads, modern Android APIs, and project conventions (SPDX headers, no magic numbers, `@JvmStatic`). The conversion must preserve behaviour, and the agent must write a behaviour-locking test before declaring it done. - **`android-activity-to-navigator-fragment`** (`./.claude/skills/android-activity-to-navigator-fragment/SKILL.md`) — Converts a standalone Activity (typically a drawer destination) into a Fragment hosted by `NavigatorActivity`. Use it when the user mentions "navigator", `NavigatorActivity`, `NavigatorScreen`, or "convert activity to fragment". It covers registering the `NavigatorScreen`, the fragment and its layout, decoupling collaborators from `FileActivity`, rewiring every entry point with `NavigatorActivity.intent(...)`, DI and manifest cleanup, and migrating the screenshot test. +### Android Skills + +Agent skills for Android development at https://github.com/android/skills (overview: https://developer.android.com/tools/agents/android-skills). Use them when a task matches their trigger and no project-specific skill above covers it. Install one with the Android CLI (`android skills add `) or read its `SKILL.md` directly from the repository. Project-specific skills and the rules in this file take precedence over the official skills. + +- **`r8-analyzer`** (https://github.com/android/skills/tree/main/performance/r8-analyzer) — Analyzes the R8 configuration and keep rules for redundant, overly broad, or library-subsumed rules. Use it when changing the keep rules in `app/src/main/keepRules/` or the `optimization {}` blocks in `app/build.gradle.kts`. + ## General Guidance Every new file needs to get a SPDX header in the first rows according to this template. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c4e8f4e1aba2..f544da971f56 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -142,9 +142,11 @@ android { buildTypes { release { + optimization { + enable = true + } buildConfigField("String", "NC_TEST_SERVER_DATA_STRING", "\"\"") } - debug { enableUnitTestCoverage = project.hasProperty("coverage") enableAndroidTestCoverage = project.hasProperty("coverage") diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java index 709f368080d8..4901488e5611 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -15,8 +15,8 @@ import android.content.SharedPreferences; import android.content.res.Configuration; -import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.nextcloud.appReview.AppReviewShownModel; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt index d4d79fbd1c37..45ec63cbe09b 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt @@ -17,6 +17,7 @@ import android.view.ViewOutlineProvider import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.doOnLayout import androidx.core.view.updatePadding import com.google.android.material.behavior.HideViewOnScrollBehavior @@ -81,7 +82,7 @@ fun View?.slideHideBottomBehavior(visible: Boolean) { if (params?.behavior !is HideViewOnScrollBehavior<*>) return val behavior = HideViewOnScrollBehavior.from(view) - view.post { + view.doOnLayout { if (visible) behavior.slideIn(view) else behavior.slideOut(view) } } diff --git a/app/src/main/keepRules/ezvcard.keep b/app/src/main/keepRules/ezvcard.keep new file mode 100644 index 000000000000..8cb9e415917b --- /dev/null +++ b/app/src/main/keepRules/ezvcard.keep @@ -0,0 +1,11 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keepclassmembers class * extends ezvcard.parameter.VCardParameter { + public static ; + (java.lang.String); + (java.lang.String, ezvcard.VCardVersion[]); + (java.lang.String, java.lang.String, java.lang.String); +} diff --git a/app/src/main/keepRules/gson-models.keep b/app/src/main/keepRules/gson-models.keep new file mode 100644 index 000000000000..4f53fdc15ac3 --- /dev/null +++ b/app/src/main/keepRules/gson-models.keep @@ -0,0 +1,25 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keepclassmembers class com.owncloud.android.authentication.AuthObject, + com.owncloud.android.authentication.Poll, + com.owncloud.android.authentication.LoginUrlInfo, + com.owncloud.android.authentication.EnforcedServer, + com.owncloud.android.datamodel.PushConfigurationState, + com.owncloud.android.datamodel.MediaFoldersModel, + com.owncloud.android.datamodel.DecryptedPushMessage, + com.nextcloud.client.jobs.LogEntry, + com.nextcloud.appReview.AppReviewShownModel, + com.nextcloud.client.NominatimClient$Companion$ReverseGeocodingResult, + com.nextcloud.model.OfflineOperationType$* { + !static !transient ; + (...); +} + +-keepclassmembers class com.owncloud.android.datamodel.e2e.**, + com.owncloud.android.datamodel.EncryptedFiledrop { + ; + (...); +} diff --git a/app/src/main/keepRules/ical4j.keep b/app/src/main/keepRules/ical4j.keep new file mode 100644 index 000000000000..a21977a36871 --- /dev/null +++ b/app/src/main/keepRules/ical4j.keep @@ -0,0 +1,14 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keep class com.nextcloud.utils.ical.AndroidCompatTimeZoneRegistryFactory, + net.fortuna.ical4j.util.MapTimeZoneCache { + (); +} + +-keeppackagenames net.fortuna.ical4j.transform.compliance + +-dontwarn java.time.zone.ZoneRulesProvider +-dontwarn org.joda.convert.ToString diff --git a/app/src/main/keepRules/legacy-http.keep b/app/src/main/keepRules/legacy-http.keep new file mode 100644 index 000000000000..905cdc3a9026 --- /dev/null +++ b/app/src/main/keepRules/legacy-http.keep @@ -0,0 +1,15 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keep class org.apache.commons.httpclient.auth.AuthPolicy +-keep class org.apache.commons.httpclient.cookie.CookiePolicy +-keep class * implements org.apache.commons.httpclient.auth.AuthScheme { + public (); +} +-keep class * implements org.apache.commons.httpclient.cookie.CookieSpec { + public (); +} + +-keeppackagenames org.apache.jackrabbit.webdav diff --git a/app/src/main/keepRules/nextcloud-library.keep b/app/src/main/keepRules/nextcloud-library.keep new file mode 100644 index 000000000000..ac61798c6e7d --- /dev/null +++ b/app/src/main/keepRules/nextcloud-library.keep @@ -0,0 +1,12 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keepclassmembers class com.owncloud.android.lib.**, com.nextcloud.android.lib.** { + !static !transient ; + (...); +} + +-keep,allowobfuscation,allowshrinking class com.owncloud.android.lib.ocs.ServerResponse, + com.owncloud.android.lib.ocs.OCSResponse diff --git a/app/src/main/keepRules/sso.keep b/app/src/main/keepRules/sso.keep new file mode 100644 index 000000000000..e9e04379d0aa --- /dev/null +++ b/app/src/main/keepRules/sso.keep @@ -0,0 +1,14 @@ +# Nextcloud - Android Client +# +# SPDX-FileCopyrightText: 2026 Alper Ozturk +# SPDX-License-Identifier: AGPL-3.0-or-later + +-keep class com.nextcloud.android.sso.aidl.NextcloudRequest, + com.nextcloud.android.sso.QueryParam, + com.nextcloud.android.sso.PlainHeader { + static final long serialVersionUID; + !static !transient ; + (...); + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); +}