From 6749cce33cfa568e46c417b57f4fd9c19b00cdfe Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 25 Nov 2025 10:10:48 +0100 Subject: [PATCH 01/11] add new analysis workflow Signed-off-by: Marcel Hibbe --- .github/workflows/analysis.yml | 112 +- app/analysis/baselines/lint-baseline.sarif | 4822 +++++++++++++++++ .../baselines/spotbugs-baseline.sarif | 1 + app/build.gradle | 5 + 4 files changed, 4884 insertions(+), 56 deletions(-) create mode 100644 app/analysis/baselines/lint-baseline.sarif create mode 100644 app/analysis/baselines/spotbugs-baseline.sarif diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 98d35c0a048..5cb75339ea5 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -1,14 +1,7 @@ -# synced from @nextcloud/android-config - -# SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors -# SPDX-FileCopyrightText: 2025 Alper Ozturk -# SPDX-FileCopyrightText: 2023 Tobias Kaminsky -# SPDX-FileCopyrightText: 2023 Andy Scherzinger -# SPDX-FileCopyrightText: 2023 Josh Richards # SPDX-FileCopyrightText: 2025 Marcel Hibbe # SPDX-License-Identifier: GPL-3.0-or-later -name: "Analysis" +name: "PR Analysis with SARIF" on: pull_request: @@ -28,53 +21,60 @@ jobs: analysis: runs-on: ubuntu-latest steps: - - name: Disabled on forks - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Setup JDK 17 + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + + - name: Install dependencies + run: sudo apt install -y python3-defusedxml + + - name: Run Lint + run: | + mkdir -p build/reports/lint/sarif + ./gradlew lintGplayDebug \ + -Pandroid.lintOptions.sarifOutput=build/reports/lint/sarif/lint-results.sarif + + - name: Run SpotBugs + run: | + mkdir -p build/reports/spotbugs/sarif + ./gradlew spotbugsGplayDebug \ + -Pspotbugs.reportFormat=sarif \ + -Pspotbugs.sarifOutput=build/reports/spotbugs/sarif/spotbugs-results.sarif + + - name: Filter new Lint issues run: | - echo 'Can not analyze PRs from forks' - exit 1 - - name: Setup variables # zizmor: ignore[template-injection] - id: get-vars - run: | - if [ -z "$GITHUB_HEAD_REF" ]; then - # push - { - echo "branch=$GITHUB_REF_NAME" - echo "pr=$GITHUB_RUN_ID" - echo "repo=${{ github.repository }}" - } >> "$GITHUB_OUTPUT" - else - # pull request - { - echo "branch=$GITHUB_HEAD_REF" - echo "pr=${{ github.event.pull_request.number }}" - echo "repo=${{ github.event.pull_request.head.repo.full_name }}" - } >> "$GITHUB_OUTPUT" - fi - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - with: - persist-credentials: false - repository: ${{ steps.get-vars.outputs.repo }} - ref: ${{ steps.get-vars.outputs.branch }} - - name: Set up JDK 17 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 - with: - distribution: "temurin" - java-version: 17 - - name: Install dependencies - run: | - sudo apt install python3-defusedxml - - name: Run analysis wrapper - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if [ -f analysis/baselines/lint-baseline.sarif ]; then + npx sarif-diff analysis/baselines/lint-baseline.sarif build/reports/lint/sarif/lint-results.sarif > build/reports/lint/sarif/lint-new.sarif + else + cp build/reports/lint/sarif/lint-results.sarif build/reports/lint/sarif/lint-new.sarif + fi + + - name: Filter new SpotBugs issues + run: | + if [ -f analysis/baselines/spotbugs-baseline.sarif ]; then + npx sarif-diff analysis/baselines/spotbugs-baseline.sarif build/reports/spotbugs/sarif/spotbugs-results.sarif > build/reports/spotbugs/sarif/spotbugs-new.sarif + else + cp build/reports/spotbugs/sarif/spotbugs-results.sarif build/reports/spotbugs/sarif/spotbugs-new.sarif + fi + + - name: Upload new Lint issues + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: build/reports/lint/sarif/lint-new.sarif - # Memory that is set in jvmargs must be wisely chosen. - # E.g. with -Xmx5g and -Xmx1g android talk builds always failed with "The operation was canceled". -Xmx3g seems to work so far. - run: | - mkdir -p "$HOME/.gradle" - { - echo "org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" - echo "org.gradle.configureondemand=true" - echo "kapt.incremental.apt=true" - } > "$HOME/.gradle/gradle.properties" - scripts/analysis/analysis-wrapper.sh "${{ steps.get-vars.outputs.branch }}" "${{ secrets.LOG_USERNAME }}" "${{ secrets.LOG_PASSWORD }}" "$GITHUB_RUN_NUMBER" "${{ steps.get-vars.outputs.pr }}" + - name: Upload new SpotBugs issues + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: build/reports/spotbugs/sarif/spotbugs-new.sarif diff --git a/app/analysis/baselines/lint-baseline.sarif b/app/analysis/baselines/lint-baseline.sarif new file mode 100644 index 00000000000..7afb9ee8db3 --- /dev/null +++ b/app/analysis/baselines/lint-baseline.sarif @@ -0,0 +1,4822 @@ +{ + "$schema" : "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version" : "2.1.0", + "runs" : [ + { + "tool": { + "driver": { + "name": "Android Lint", + "fullName": "Android Lint (in gradle)", + "version": "8.13.1", + "semanticVersion": "8.13.1", + "organization": "Google", + "informationUri": "https://developer.android.com/studio/write/lint", + "fullDescription": { + "text": "Static analysis originally for Android source code but now performing general analysis" + }, + "language": "en-US", + "rules": [ + { + "id": "AcceptsUserCertificates", + "shortDescription": { + "text": "Allowing User Certificates" + }, + "fullDescription": { + "text": "Allowing user certificates could allow eavesdroppers to intercept data sent by your app, which could impact the privacy of your users. Consider nesting your app's trust-anchors inside a element to make sure they are only available when android:debuggable is set to true.", + "markdown": "Allowing user certificates could allow eavesdroppers to intercept data sent by your app, which could impact the privacy of your users. Consider nesting your app's `trust-anchors` inside a `` element to make sure they are only available when `android:debuggable` is set to `true`." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Security" + ] + } + }, + { + "id": "CustomX509TrustManager", + "shortDescription": { + "text": "Implements custom TLS trust manager" + }, + "fullDescription": { + "text": "This check looks for custom X509TrustManager implementations.", + "markdown": "This check looks for custom `X509TrustManager` implementations." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Security" + ] + } + }, + { + "id": "DataExtractionRules", + "shortDescription": { + "text": "Missing data extraction rules" + }, + "fullDescription": { + "text": "Before Android 12, the attributes android:allowBackup and android:fullBackupContent were used to configure all forms of backup, including cloud backups, device-to-device transfers and adb backup.\n\nIn Android 12 and higher, these attributes have been deprecated and will only apply to cloud backups. You should instead use the attribute android:dataExtractionRules, specifying an @xml resource that configures which files to back up, for cloud backups and for device-to-device transfers, separately. If your minSdkVersion supports older versions, you'll still want to specify an android:fullBackupContent resource if the default behavior is not right for your app.", + "markdown": "Before Android 12, the attributes `android:allowBackup` and `android:fullBackupContent` were used to configure all forms of backup, including cloud backups, device-to-device transfers and adb backup.\n\nIn Android 12 and higher, these attributes have been deprecated and will only apply to cloud backups. You should instead use the attribute `android:dataExtractionRules`, specifying an `@xml` resource that configures which files to back up, for cloud backups and for device-to-device transfers, separately. If your `minSdkVersion` supports older versions, you'll still want to specify an `android:fullBackupContent` resource if the default behavior is not right for your app." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 80 + }, + "properties": { + "tags": [ + "Security" + ] + } + }, + { + "id": "ExportedService", + "shortDescription": { + "text": "Exported service does not require permission" + }, + "fullDescription": { + "text": "Exported services (services which either set exported=true or contain an intent-filter and do not specify exported=false) should define a permission that an entity must have in order to launch the service or bind to it. Without this, any application can use this service.", + "markdown": "Exported services (services which either set `exported=true` or contain an intent-filter and do not specify `exported=false`) should define a permission that an entity must have in order to launch the service or bind to it. Without this, any application can use this service." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Security" + ] + } + }, + { + "id": "FrequentlyChangingValue", + "shortDescription": { + "text": "Reading a value annotated with @FrequentlyChangingValue inside composition" + }, + "fullDescription": { + "text": "Reading a value annotated with @FrequentlyChangingValue inside composition can cause performance issues due to frequent recompositions. To avoid frequent recompositions, instead consider:\n\n- Using derivedStateOf to filter state changes based on a provided calculation. For example, rather than recomposing on every scroll position change, only recomposing if the scroll position changes from 0 (at the top of the list) to greater than 0 (not at the top of the list), and vice versa.\n- Using snapshotFlow to create a flow of changes from a provided state. This can then be collected inside a LaunchedEffect, and used to make changes without needing to recompose.\n- If using Compose UI, read this value inside measure / layout / draw, depending on where it is needed. This will cause invalidation of the corresponding phase, instead of a recomposition. See developer.android.com for more information on Jetpack Compose phases." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "InsecureBaseConfiguration", + "shortDescription": { + "text": "Insecure Base Configuration" + }, + "fullDescription": { + "text": "Permitting cleartext traffic could allow eavesdroppers to intercept data sent by your app, which impacts the privacy of your users. Consider only allowing encrypted traffic by setting the cleartextTrafficPermitted tag to false.", + "markdown": "Permitting cleartext traffic could allow eavesdroppers to intercept data sent by your app, which impacts the privacy of your users. Consider only allowing encrypted traffic by setting the `cleartextTrafficPermitted` tag to `false`." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Security" + ] + } + }, + { + "id": "LocalContextResourcesRead", + "shortDescription": { + "text": "Reading Resources using LocalContext.current.resources" + }, + "fullDescription": { + "text": "Changes to the Configuration object will not cause LocalContext.current.resources reads to be invalidated, so calls to APIs suchas Resources.getString() will not be updated when the Configuration changes. Instead, use LocalResources.current to retrieve the Resources - this will invalidate callers when the Configuration changes, to ensure that these calls reflect the latest values." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 80 + }, + "properties": { + "tags": [ + "Correctness" + ] + } + }, + { + "id": "NotifyDataSetChanged", + "shortDescription": { + "text": "Invalidating All RecyclerView Data" + }, + "fullDescription": { + "text": "The RecyclerView adapter's onNotifyDataSetChanged method does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. `LayoutManager`s will be forced to fully rebind and relayout all visible views.", + "markdown": "The `RecyclerView` adapter's `onNotifyDataSetChanged` method does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. `LayoutManager`s will be forced to fully rebind and relayout all visible views." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 30 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "ObsoleteSdkInt", + "shortDescription": { + "text": "Obsolete SDK_INT Version Check" + }, + "fullDescription": { + "text": "This check flags version checks that are not necessary, because the minSdkVersion (or surrounding known API level) is already at least as high as the version checked for.\n\nSimilarly, it also looks for resources in -vNN folders, such as values-v14 where the version qualifier is less than or equal to the minSdkVersion, where the contents should be merged into the best folder.", + "markdown": "This check flags version checks that are not necessary, because the `minSdkVersion` (or surrounding known API level) is already at least as high as the version checked for.\n\nSimilarly, it also looks for resources in `-vNN` folders, such as `values-v14` where the version qualifier is less than or equal to the `minSdkVersion`, where the contents should be merged into the best folder." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 50 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "Overdraw", + "shortDescription": { + "text": "Overdraw: Painting regions more than once" + }, + "fullDescription": { + "text": "If you set a background drawable on a root view, then you should use a custom theme where the theme background is null. Otherwise, the theme background will be painted first, only to have your custom background completely cover it; this is called \"overdraw\".\n\nNOTE: This detector relies on figuring out which layouts are associated with which activities based on scanning the Java code, and it's currently doing that using an inexact pattern matching algorithm. Therefore, it can incorrectly conclude which activity the layout is associated with and then wrongly complain that a background-theme is hidden.\n\nIf you want your custom background on multiple pages, then you should consider making a custom theme with your custom background and just using that theme instead of a root element background.\n\nOf course it's possible that your custom drawable is translucent and you want it to be mixed with the background. However, you will get better performance if you pre-mix the background with your drawable and use that resulting image or color as a custom theme background instead." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 80 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "PictureInPictureIssue", + "shortDescription": { + "text": "Picture In Picture best practices not followed" + }, + "fullDescription": { + "text": "Starting in Android 12, the recommended approach for enabling picture-in-picture (PiP) has changed. If your app does not use the new approach, your app's transition animations will be of poor quality compared to other apps. The new approach requires calling setAutoEnterEnabled(true) and setSourceRectHint(...).", + "markdown": "Starting in Android 12, the recommended approach for enabling picture-in-picture (PiP) has changed. If your app does not use the new approach, your app's transition animations will be of poor quality compared to other apps. The new approach requires calling `setAutoEnterEnabled(true)` and `setSourceRectHint(...)`." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Correctness" + ] + } + }, + { + "id": "RtlHardcoded", + "shortDescription": { + "text": "Using left/right instead of start/end attributes" + }, + "fullDescription": { + "text": "Using Gravity#LEFT and Gravity#RIGHT can lead to problems when a layout is rendered in locales where text flows from right to left. Use Gravity#START and Gravity#END instead. Similarly, in XML gravity and layout_gravity attributes, use start rather than left.\n\nFor XML attributes such as paddingLeft and layout_marginLeft, use paddingStart and layout_marginStart. NOTE: If your minSdkVersion is less than 17, you should add both the older left/right attributes as well as the new start/end attributes. On older platforms, where RTL is not supported and the start/end attributes are unknown and therefore ignored, you need the older left/right attributes. There is a separate lint check which catches that type of error.\n\n(Note: For Gravity#LEFT and Gravity#START, you can use these constants even when targeting older platforms, because the start bitmask is a superset of the left bitmask. Therefore, you can use gravity=\"start\" rather than gravity=\"left|start\".)", + "markdown": "Using `Gravity#LEFT` and `Gravity#RIGHT` can lead to problems when a layout is rendered in locales where text flows from right to left. Use `Gravity#START` and `Gravity#END` instead. Similarly, in XML `gravity` and `layout_gravity` attributes, use `start` rather than `left`.\n\nFor XML attributes such as paddingLeft and `layout_marginLeft`, use `paddingStart` and `layout_marginStart`. **NOTE**: If your `minSdkVersion` is less than 17, you should add **both** the older left/right attributes **as well as** the new start/end attributes. On older platforms, where RTL is not supported and the start/end attributes are unknown and therefore ignored, you need the older left/right attributes. There is a separate lint check which catches that type of error.\n\n(Note: For `Gravity#LEFT` and `Gravity#START`, you can use these constants even when targeting older platforms, because the `start` bitmask is a superset of the `left` bitmask. Therefore, you can use `gravity=\"start\"` rather than `gravity=\"left|start\"`.)" + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Bidirectional Text", + "Internationalization" + ] + } + }, + { + "id": "SelectedPhotoAccess", + "shortDescription": { + "text": "Behavior change when requesting photo library access" + }, + "fullDescription": { + "text": "Selected Photo Access is a new ability for users to share partial access to their photo library when apps request access to their device storage on Android 14+.\n\nInstead of letting the system manage the selection lifecycle, we recommend you adapt your app to handle partial access to the photo library." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Correctness" + ] + } + }, + { + "id": "SetTextI18n", + "shortDescription": { + "text": "TextView Internationalization" + }, + "fullDescription": { + "text": "When calling TextView#setText\n* Never call Number#toString() to format numbers; it will not handle fraction separators and locale-specific digits properly. Consider using String#format with proper format specifications (%d or %f) instead.\n* Do not pass a string literal (e.g. \"Hello\") to display text. Hardcoded text can not be properly translated to other languages. Consider using Android resource strings instead.\n* Do not build messages by concatenating text chunks. Such messages can not be properly translated.", + "markdown": "When calling `TextView#setText`\n* Never call `Number#toString()` to format numbers; it will not handle fraction separators and locale-specific digits properly. Consider using `String#format` with proper format specifications (`%d` or `%f`) instead.\n* Do not pass a string literal (e.g. \"Hello\") to display text. Hardcoded text can not be properly translated to other languages. Consider using Android resource strings instead.\n* Do not build messages by concatenating text chunks. Such messages can not be properly translated." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 50 + }, + "properties": { + "tags": [ + "Internationalization" + ] + } + }, + { + "id": "StringFormatCount", + "shortDescription": { + "text": "Formatting argument types incomplete or inconsistent" + }, + "fullDescription": { + "text": "When a formatted string takes arguments, it usually needs to reference the same arguments in all translations (or all arguments if there are no translations.\n\nThere are cases where this is not the case, so this issue is a warning rather than an error by default. However, this usually happens when a language is not translated or updated correctly." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Messages", + "Correctness" + ] + } + }, + { + "id": "TooManyViews", + "shortDescription": { + "text": "Layout has too many views" + }, + "fullDescription": { + "text": "Using too many views in a single layout is bad for performance. Consider using compound drawables or other tricks for reducing the number of views in this layout.\n\nThe maximum view count defaults to 80 but can be configured with the environment variable ANDROID_LINT_MAX_VIEW_COUNT.", + "markdown": "Using too many views in a single layout is bad for performance. Consider using compound drawables or other tricks for reducing the number of views in this layout.\n\nThe maximum view count defaults to 80 but can be configured with the environment variable `ANDROID_LINT_MAX_VIEW_COUNT`." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 100 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "UnusedResources", + "shortDescription": { + "text": "Unused resources" + }, + "fullDescription": { + "text": "Unused resources make applications larger and slow down builds.\n\n\nThe unused resource check can ignore tests. If you want to include resources that are only referenced from tests, consider packaging them in a test source set instead.\n\nYou can include test sources in the unused resource check by setting the system property lint.unused-resources.include-tests =true, and to exclude them (usually for performance reasons), use lint.unused-resources.exclude-tests =true.\n," + }, + "defaultConfiguration": { + "level": "warning", + "rank": 80 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "UseKtx", + "shortDescription": { + "text": "Use KTX extension function" + }, + "fullDescription": { + "text": "The Android KTX libraries decorates the Android platform SDK as well as various libraries with more convenient extension functions available from Kotlin, allowing you to use default parameters, named parameters, and more." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 50 + }, + "properties": { + "tags": [ + "Productivity" + ] + } + }, + { + "id": "UselessParent", + "shortDescription": { + "text": "Unnecessary parent layout" + }, + "fullDescription": { + "text": "A layout with children that has no siblings, is not a scrollview or a root layout, and does not have a background, can be removed and have its children moved directly into the parent for a flatter and more efficient layout hierarchy." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 90 + }, + "properties": { + "tags": [ + "Performance" + ] + } + }, + { + "id": "ViewHolder", + "shortDescription": { + "text": "View Holder Candidates" + }, + "fullDescription": { + "text": "When implementing a view Adapter, you should avoid unconditionally inflating a new layout; if an available item is passed in for reuse, you should try to use that one instead. This helps make for example ListView scrolling much smoother.", + "markdown": "When implementing a view Adapter, you should avoid unconditionally inflating a new layout; if an available item is passed in for reuse, you should try to use that one instead. This helps make for example `ListView` scrolling much smoother." + }, + "defaultConfiguration": { + "level": "warning", + "rank": 60 + }, + "properties": { + "tags": [ + "Performance" + ] + } + } + ] + } + }, + "originalUriBaseIds": { + "%SRCROOT%": { + "uri": "file:///home/marcel/Source/NC/AndroidStudioProjects/talk-android/" + } + }, + "results": [ + { + "ruleId": "PictureInPictureIssue", + "ruleIndex": 10, + "message": { + "text": "An activity in this app supports picture-in-picture and the targetSdkVersion is 31 or above; it is therefore strongly recommended to call both setAutoEnterEnabled(true) and setSourceRectHint(...)", + "markdown": "An activity in this app supports picture-in-picture and the targetSdkVersion is 31 or above; it is therefore strongly recommended to call both `setAutoEnterEnabled(true)` and `setSourceRectHint(...)`" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/AndroidManifest.xml" + }, + "region": { + "startLine": 85, + "startColumn": 6, + "endLine": 85, + "endColumn": 17, + "charOffset": 4040, + "charLength": 11, + "snippet": { + "text": "application" + } + }, + "contextRegion": { + "startLine": 83, + "endLine": 88, + "snippet": { + "text": " \n\n \n \n " + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "01236b51bdbc7e07" + } + }, + { + "ruleId": "SelectedPhotoAccess", + "ruleIndex": 12, + "message": { + "text": "Your app is currently not handling Selected Photos Access introduced in Android 14+" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/AndroidManifest.xml" + }, + "region": { + "startLine": 66, + "startColumn": 36, + "endLine": 66, + "endColumn": 71, + "charOffset": 3201, + "charLength": 35, + "snippet": { + "text": "android.permission.READ_MEDIA_VIDEO" + } + }, + "contextRegion": { + "startLine": 64, + "endLine": 69, + "snippet": { + "text": " android:maxSdkVersion=\"32\" />\n \n \n " + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "26725b8e2f246143" + } + }, + { + "ruleId": "LocalContextResourcesRead", + "ruleIndex": 6, + "message": { + "text": "Reading Resources using LocalContext.current.resources" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt" + }, + "region": { + "startLine": 267, + "startColumn": 25, + "endLine": 267, + "endColumn": 55, + "charOffset": 10631, + "charLength": 30, + "snippet": { + "text": "LocalContext.current.resources" + } + }, + "contextRegion": { + "startLine": 265, + "endLine": 270, + "snippet": { + "text": " val color = Color(highEmphasisColorInt)\n val backgroundColor =\n LocalContext.current.resources.getColor(R.color.bg_message_list_incoming_bubble, null)\n Row(" + } + } + } + } + ], + "fixes": [ + { + "description": { + "text": "Replace with LocalResources.current" + }, + "artifactChanges": [ + { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt" + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 267, + "startColumn": 25, + "charOffset": 10631, + "endLine": 267, + "endColumn": 55, + "charLength": 30 + }, + "insertedContent": { + "text": "LocalResources.current\n" + } + } + ] + } + ] + } + ], + "partialFingerprints": { + "sourceContext/v1": "8738f693b7c52bb6" + } + }, + { + "ruleId": "LocalContextResourcesRead", + "ruleIndex": 6, + "message": { + "text": "Reading Resources using LocalContext.current.resources" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt" + }, + "region": { + "startLine": 1035, + "startColumn": 37, + "endLine": 1035, + "endColumn": 67, + "charOffset": 40800, + "charLength": 30, + "snippet": { + "text": "LocalContext.current.resources" + } + }, + "contextRegion": { + "startLine": 1033, + "endLine": 1038, + "snippet": { + "text": " if (cardName?.isNotEmpty() == true) {\n val cardDescription = String.format(\n LocalContext.current.resources.getString(R.string.deck_card_description),\n stackName," + } + } + } + } + ], + "fixes": [ + { + "description": { + "text": "Replace with LocalResources.current" + }, + "artifactChanges": [ + { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt" + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 1035, + "startColumn": 37, + "charOffset": 40800, + "endLine": 1035, + "endColumn": 67, + "charLength": 30 + }, + "insertedContent": { + "text": "LocalResources.current\n" + } + } + ] + } + ] + } + ], + "partialFingerprints": { + "sourceContext/v1": "49519503c0f5653d" + } + }, + { + "ruleId": "StringFormatCount", + "ruleIndex": 14, + "message": { + "text": "Inconsistent number of arguments in formatting string nc_upload_notification_text; found both 3 here and 0 in values/strings.xml", + "markdown": "Inconsistent number of arguments in formatting string `nc_upload_notification_text`; found both 3 here and 0 in values/strings.xml" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values-ug/strings.xml" + }, + "region": { + "startLine": 495, + "startColumn": 5, + "endLine": 495, + "endColumn": 83, + "charOffset": 38439, + "charLength": 78, + "snippet": { + "text": "%1$s دىن%2$s - %3$s \\ %%" + } + }, + "contextRegion": { + "startLine": 493, + "endLine": 498, + "snippet": { + "text": " ئۈسكۈنىدىن يۈكلەش\n يۈكلەش\n %1$s دىن%2$s - %3$s \\ %%\n رەسىمگە تارتىڭ" + } + } + } + } + ], + "relatedLocations": [ + { + "id": 1, + "message": { + "text": "Conflicting number of arguments (0) here" + }, + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 592, + "startColumn": 5, + "endLine": 592, + "endColumn": 79, + "charOffset": 39640, + "charLength": 74, + "snippet": { + "text": "%1$s to %2$s - %3$s\\%%" + } + }, + "contextRegion": { + "startLine": 590, + "endLine": 595, + "snippet": { + "text": " Gallery\n\n %1$s to %2$s - %3$s\\%%\n Failure" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "a224a9c96d4fccfb" + } + }, + { + "ruleId": "StringFormatCount", + "ruleIndex": 14, + "message": { + "text": "Inconsistent number of arguments in formatting string nc_upload_notification_text; found both 3 here and 0 in values/strings.xml", + "markdown": "Inconsistent number of arguments in formatting string `nc_upload_notification_text`; found both 3 here and 0 in values/strings.xml" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values-sw/strings.xml" + }, + "region": { + "startLine": 544, + "startColumn": 5, + "endLine": 544, + "endColumn": 80, + "charOffset": 43249, + "charLength": 75, + "snippet": { + "text": "%1$skwenda %2$s-%3$s/%%" + } + }, + "contextRegion": { + "startLine": 542, + "endLine": 547, + "snippet": { + "text": " Pakia kutoka katika kifaa\n Inapakia\n %1$skwenda %2$s-%3$s/%%\n Chukua picha" + } + } + } + } + ], + "relatedLocations": [ + { + "id": 1, + "message": { + "text": "Conflicting number of arguments (0) here" + }, + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 592, + "startColumn": 5, + "endLine": 592, + "endColumn": 79, + "charOffset": 39640, + "charLength": 74, + "snippet": { + "text": "%1$s to %2$s - %3$s\\%%" + } + }, + "contextRegion": { + "startLine": 590, + "endLine": 595, + "snippet": { + "text": " Gallery\n\n %1$s to %2$s - %3$s\\%%\n Failure" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "a06b176dd3787127" + } + }, + { + "ruleId": "AcceptsUserCertificates", + "ruleIndex": 0, + "message": { + "text": "The Network Security Configuration allows the use of user certificates in the release version of your app" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/xml/network_security_config.xml" + }, + "region": { + "startLine": 12, + "startColumn": 13, + "endLine": 12, + "endColumn": 39, + "charOffset": 354, + "charLength": 26, + "snippet": { + "text": "" + } + }, + "contextRegion": { + "startLine": 10, + "endLine": 15, + "snippet": { + "text": " \n \n \n " + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "fb63c8660abbc02a" + } + }, + { + "ruleId": "CustomX509TrustManager", + "ruleIndex": 1, + "message": { + "text": "Implementing a custom X509TrustManager is error-prone and likely to be insecure. It is likely to disable certificate validation altogether, and is non-trivial to implement correctly without calling Android's default implementation.", + "markdown": "Implementing a custom `X509TrustManager` is error-prone and likely to be insecure. It is likely to disable certificate validation altogether, and is non-trivial to implement correctly without calling Android's default implementation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/utils/ssl/TrustManager.java" + }, + "region": { + "startLine": 35, + "startColumn": 14, + "endLine": 35, + "endColumn": 26, + "charOffset": 1016, + "charLength": 12, + "snippet": { + "text": "TrustManager" + } + }, + "contextRegion": { + "startLine": 33, + "endLine": 38, + "snippet": { + "text": "\n\npublic class TrustManager implements X509TrustManager {\n private static final String TAG = \"TrustManager\";" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "5458c4934670d382" + } + }, + { + "ruleId": "ExportedService", + "ruleIndex": 3, + "message": { + "text": "Exported service does not require permission" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/AndroidManifest.xml" + }, + "region": { + "startLine": 284, + "startColumn": 10, + "endLine": 284, + "endColumn": 17, + "charOffset": 11527, + "charLength": 7, + "snippet": { + "text": "service" + } + }, + "contextRegion": { + "startLine": 282, + "endLine": 287, + "snippet": { + "text": " \n\n \n\n \n " + } + } + } + } + ], + "fixes": [ + { + "description": { + "text": "Replace with false" + }, + "artifactChanges": [ + { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/xml/network_security_config.xml" + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 9, + "startColumn": 45, + "charOffset": 270, + "endLine": 9, + "endColumn": 49, + "charLength": 4 + }, + "insertedContent": { + "text": "false\n" + } + } + ] + } + ] + } + ], + "partialFingerprints": { + "sourceContext/v1": "258d87161883f476" + } + }, + { + "ruleId": "DataExtractionRules", + "ruleIndex": 2, + "message": { + "text": "The attribute android:fullBackupContent is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute android:dataExtractionRules specifying an @xml resource which configures cloud backups and device transfers on Android 12 and higher.", + "markdown": "The attribute `android:fullBackupContent` is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml` resource which configures cloud backups and device transfers on Android 12 and higher." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/AndroidManifest.xml" + }, + "region": { + "startLine": 88, + "startColumn": 36, + "endLine": 88, + "endColumn": 54, + "charOffset": 4183, + "charLength": 18, + "snippet": { + "text": "@xml/backup_config" + } + }, + "contextRegion": { + "startLine": 86, + "endLine": 91, + "snippet": { + "text": " android:name=\".application.NextcloudTalkApplication\"\n android:allowBackup=\"true\"\n android:fullBackupContent=\"@xml/backup_config\"\n android:icon=\"@mipmap/ic_launcher\"" + } + } + } + } + ], + "fixes": [ + { + "description": { + "text": "Create data_extraction_rules.xml" + }, + "artifactChanges": [ + { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/xml/data_extraction_rules.xml" + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 1, + "startColumn": 1, + "charOffset": 0 + }, + "insertedContent": { + "text": "\n\n\n \n \n \n\n" + } + } + ] + }, + { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/AndroidManifest.xml" + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 88, + "startColumn": 9, + "charOffset": 4156 + }, + "insertedContent": { + "text": "android:dataExtractionRules=\"@xml/data_extraction_rules\" \n" + } + } + ] + } + ] + } + ], + "partialFingerprints": { + "sourceContext/v1": "d756dbd928ae1eda" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt" + }, + "region": { + "startLine": 3000, + "startColumn": 13, + "endLine": 3000, + "endColumn": 45, + "charOffset": 123576, + "charLength": 32, + "snippet": { + "text": "adapter!!.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 2998, + "endLine": 3003, + "snippet": { + "text": " }\n }\n adapter!!.notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "b8cde936af9b48d4" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt" + }, + "region": { + "startLine": 110, + "startColumn": 9, + "endLine": 110, + "endColumn": 36, + "charOffset": 4284, + "charLength": 27, + "snippet": { + "text": "this.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 108, + "endLine": 113, + "snippet": { + "text": " this.selection = listener\n }\n this.notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "c3cdf561752376e8" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/bottomsheet/items/ListIconDialogAdapter.kt" + }, + "region": { + "startLine": 115, + "startColumn": 9, + "endLine": 115, + "endColumn": 31, + "charOffset": 4417, + "charLength": 22, + "snippet": { + "text": "notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 113, + "endLine": 118, + "snippet": { + "text": " override fun disableItems(indices: IntArray) {\n this.disabledIndices = indices\n notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "8d21dc6522e6f649" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/polls/adapters/PollCreateOptionsAdapter.kt" + }, + "region": { + "startLine": 43, + "startColumn": 9, + "endLine": 43, + "endColumn": 31, + "charOffset": 1488, + "charLength": 22, + "snippet": { + "text": "notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 41, + "endLine": 46, + "snippet": { + "text": " fun updateOptionsList(optionsList: ArrayList) {\n list = optionsList\n notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "9c11296cac5786a0" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 267, + "startColumn": 29, + "endLine": 267, + "endColumn": 61, + "charOffset": 11034, + "charLength": 32, + "snippet": { + "text": "adapter!!.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 265, + "endLine": 270, + "snippet": { + "text": " override fun onNext(userProfileFieldsOverall: UserProfileFieldsOverall) {\n editableFields = userProfileFieldsOverall.ocs!!.data!!\n adapter!!.notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "4248d4d2b0b11b3a" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 289, + "startColumn": 13, + "endLine": 289, + "endColumn": 45, + "charOffset": 11912, + "charLength": 32, + "snippet": { + "text": "adapter!!.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 287, + "endLine": 292, + "snippet": { + "text": " }\n }\n adapter!!.notifyDataSetChanged()\n return true" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "855fe19b562872b5" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 366, + "startColumn": 25, + "endLine": 366, + "endColumn": 57, + "charOffset": 14849, + "charLength": 32, + "snippet": { + "text": "adapter!!.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 364, + "endLine": 369, + "snippet": { + "text": " editableFields = userProfileFieldsOverall.ocs!!.data!!\n invalidateOptionsMenu()\n adapter!!.notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "555564c043048366" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 492, + "startColumn": 29, + "endLine": 492, + "endColumn": 61, + "charOffset": 19996, + "charLength": 32, + "snippet": { + "text": "adapter!!.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 490, + "endLine": 495, + "snippet": { + "text": " ).show()\n adapter!!.updateFilteredList()\n adapter!!.notifyDataSetChanged()\n Log.e(TAG, \"Failed to saved: \" + item.text + \" as \" + item.field, e)" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "ba9273e95a852156" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 641, + "startColumn": 13, + "endLine": 641, + "endColumn": 35, + "charOffset": 25464, + "charLength": 22, + "snippet": { + "text": "notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 639, + "endLine": 644, + "snippet": { + "text": " this.displayList = displayList\n updateFilteredList()\n notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "484063c8690f714b" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt" + }, + "region": { + "startLine": 760, + "startColumn": 13, + "endLine": 760, + "endColumn": 35, + "charOffset": 30898, + "charLength": 22, + "snippet": { + "text": "notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 758, + "endLine": 763, + "snippet": { + "text": " fun updateScope(position: Int, scope: Scope?) {\n displayList!![position].scope = scope\n notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "de83d0108ed0eafb" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt" + }, + "region": { + "startLine": 134, + "startColumn": 9, + "endLine": 134, + "endColumn": 40, + "charOffset": 5564, + "charLength": 31, + "snippet": { + "text": "adapter?.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 132, + "endLine": 137, + "snippet": { + "text": " updateParticipantsForEmoji(chatMessage, tagAll)\n }\n adapter?.notifyDataSetChanged()\n }" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "2747dcb801ecf674" + } + }, + { + "ruleId": "NotifyDataSetChanged", + "ruleIndex": 7, + "message": { + "text": "It will always be more efficient to use more specific change events if you can. Rely on notifyDataSetChanged as a last resort.", + "markdown": "It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/dialog/ShowReactionsDialog.kt" + }, + "region": { + "startLine": 171, + "startColumn": 25, + "endLine": 171, + "endColumn": 56, + "charOffset": 7041, + "charLength": 31, + "snippet": { + "text": "adapter?.notifyDataSetChanged()" + } + }, + "contextRegion": { + "startLine": 169, + "endLine": 174, + "snippet": { + "text": "\n adapter?.list?.addAll(reactionVoters)\n adapter?.notifyDataSetChanged()\n } else {" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "3587c514e5ac0e7e" + } + }, + { + "ruleId": "ObsoleteSdkInt", + "ruleIndex": 8, + "message": { + "text": "Unnecessary; SDK_INT is always >= 26", + "markdown": "Unnecessary; `SDK_INT` is always >= 26" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/activities/CallBaseActivity.java" + }, + "region": { + "startLine": 155, + "startColumn": 13, + "endLine": 155, + "endColumn": 70, + "charOffset": 5610, + "charLength": 57, + "snippet": { + "text": "Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH" + } + }, + "contextRegion": { + "startLine": 153, + "endLine": 158, + "snippet": { + "text": " }\n\n if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {\n return powerManager.isInteractive();" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "ff9384b48518720d" + } + }, + { + "ruleId": "ObsoleteSdkInt", + "ruleIndex": 8, + "message": { + "text": "This folder configuration (v26) is unnecessary; minSdkVersion is 26. Merge all the resources in this folder into mipmap-anydpi.", + "markdown": "This folder configuration (`v26`) is unnecessary; `minSdkVersion` is 26. Merge all the resources in this folder into `mipmap-anydpi`." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/mipmap-anydpi-v26" + }, + "region": { + "startLine": 1 + } } + } + ], + "fixes": [ + ], + "partialFingerprints": { + } + }, + { + "ruleId": "FrequentlyChangingValue", + "ruleIndex": 4, + "message": { + "text": "Reading a value annotated with @FrequentlyChangingValue inside composition" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/ComposeChatAdapter.kt" + }, + "region": { + "startLine": 263, + "startColumn": 53, + "endLine": 263, + "endColumn": 74, + "charOffset": 10401, + "charLength": 21, + "snippet": { + "text": "firstVisibleItemIndex" + } + }, + "contextRegion": { + "startLine": 261, + "endLine": 266, + "snippet": { + "text": " }\n } else {\n val timestamp = items[listState.firstVisibleItemIndex].timestamp\n val dateString = formatTime(timestamp * LONG_1000)" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "0ae903562c61e694" + } + }, + { + "ruleId": "ViewHolder", + "ruleIndex": 19, + "message": { + "text": "Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/java/com/nextcloud/talk/ui/dialog/DialogBanListFragment.kt" + }, + "region": { + "startLine": 61, + "startColumn": 27, + "endLine": 61, + "endColumn": 83, + "charOffset": 2109, + "charLength": 56, + "snippet": { + "text": "BanItemListBinding.inflate(LayoutInflater.from(context))" + } + }, + "contextRegion": { + "startLine": 59, + "endLine": 64, + "snippet": { + "text": "\n override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {\n val binding = BanItemListBinding.inflate(LayoutInflater.from(context))\n binding.banActorName.text = bans[position].bannedDisplayName" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "2ce54271fb224b7f" + } + }, + { + "ruleId": "Overdraw", + "ruleIndex": 9, + "message": { + "text": "Possible overdraw: Root element paints background @color/bg_default with a theme that also paints a background (inferred theme is @style/AppTheme.Launcher)", + "markdown": "Possible overdraw: Root element paints background `@color/bg_default` with a theme that also paints a background (inferred theme is `@style/AppTheme.Launcher`)" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/layout/activity_account_verification.xml" + }, + "region": { + "startLine": 12, + "startColumn": 5, + "endLine": 12, + "endColumn": 43, + "charOffset": 411, + "charLength": 38, + "snippet": { + "text": "android:background=\"@color/bg_default\"" + } + }, + "contextRegion": { + "startLine": 10, + "endLine": 15, + "snippet": { + "text": " android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\"\n android:background=\"@color/bg_default\"\n android:keepScreenOn=\"true\">" + } + } + } + } + ], + "partialFingerprints": { + "sourceContext/v1": "3b39646fc91b1eab" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.baseline_calendar_month_24 appears to be unused", + "markdown": "The resource `R.drawable.baseline_calendar_month_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/baseline_calendar_month_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 1578, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "0905b61d38506ebb" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.baseline_report_problem_24 appears to be unused", + "markdown": "The resource `R.drawable.baseline_report_problem_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/baseline_report_problem_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 592, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "e141bd2e1e5668b8" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.baseline_tag_faces_24 appears to be unused", + "markdown": "The resource `R.drawable.baseline_tag_faces_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/baseline_tag_faces_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 17, + "endColumn": 10, + "charOffset": 138, + "charLength": 691, + "snippet": { + "text": "\n \n \n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 18, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n \n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "57d5dcd9b220f1f5" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.bool.value_false appears to be unused", + "markdown": "The resource `R.bool.value_false` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/bool.xml" + }, + "region": { + "startLine": 10, + "startColumn": 11, + "endLine": 10, + "endColumn": 29, + "charOffset": 267, + "charLength": 18, + "snippet": { + "text": "name=\"value_false\"" + } + }, + "contextRegion": { + "startLine": 8, + "endLine": 13, + "snippet": { + "text": "\n true\n false\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "d61476f0e06df2b1" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.color.list_divider_background appears to be unused", + "markdown": "The resource `R.color.list_divider_background` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/colors.xml" + }, + "region": { + "startLine": 88, + "startColumn": 12, + "endLine": 88, + "endColumn": 42, + "charOffset": 3691, + "charLength": 30, + "snippet": { + "text": "name=\"list_divider_background\"" + } + }, + "contextRegion": { + "startLine": 86, + "endLine": 91, + "snippet": { + "text": " #99121212\n\n #1F121212\n #EEEEEE" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "361d0a655faa950f" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.layout.dialog_create_conversation appears to be unused", + "markdown": "The resource `R.layout.dialog_create_conversation` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/layout/dialog_create_conversation.xml" + }, + "region": { + "startLine": 8, + "startColumn": 1, + "endLine": 55, + "endColumn": 18, + "charOffset": 200, + "charLength": 2093, + "snippet": { + "text": "\n\n \n\n \n\n \n\n \n\n" + } + }, + "contextRegion": { + "startLine": 6, + "endLine": 56, + "snippet": { + "text": " ~ SPDX-License-Identifier: GPL-3.0-or-later\n-->\n\n\n \n\n \n\n \n\n \n\n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "f5a3bb701eb7870a" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.dimen.call_participant_progress_bar_size appears to be unused", + "markdown": "The resource `R.dimen.call_participant_progress_bar_size` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/dimens.xml" + }, + "region": { + "startLine": 65, + "startColumn": 12, + "endLine": 65, + "endColumn": 53, + "charOffset": 2864, + "charLength": 41, + "snippet": { + "text": "name=\"call_participant_progress_bar_size\"" + } + }, + "contextRegion": { + "startLine": 63, + "endLine": 68, + "snippet": { + "text": "\n 110dp\n 48dp\n 48dp" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "f4713e2ea2e19519" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_baseline_mic_24 appears to be unused", + "markdown": "The resource `R.drawable.ic_baseline_mic_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_baseline_mic_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 981, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "9675376b0f090514" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_baseline_mic_red_24 appears to be unused", + "markdown": "The resource `R.drawable.ic_baseline_mic_red_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_baseline_mic_red_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 974, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "b4b2493a64ec557a" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_check_24 appears to be unused", + "markdown": "The resource `R.drawable.ic_check_24` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_check_24.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 372, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "133b18896afdedb6" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_circular_document appears to be unused", + "markdown": "The resource `R.drawable.ic_circular_document` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_circular_document.xml" + }, + "region": { + "startLine": 8, + "startColumn": 1, + "endLine": 24, + "endColumn": 10, + "charOffset": 220, + "charLength": 924, + "snippet": { + "text": "\n\n\n\n\n" + } + }, + "contextRegion": { + "startLine": 6, + "endLine": 25, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n\n\n\n\n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "8d5ee0bc865df686" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_circular_mail appears to be unused", + "markdown": "The resource `R.drawable.ic_circular_mail` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_circular_mail.xml" + }, + "region": { + "startLine": 8, + "startColumn": 1, + "endLine": 21, + "endColumn": 10, + "charOffset": 220, + "charLength": 876, + "snippet": { + "text": "\n \n \n" + } + }, + "contextRegion": { + "startLine": 6, + "endLine": 22, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "6eb23ec362695880" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_link_grey600_24px appears to be unused", + "markdown": "The resource `R.drawable.ic_link_grey600_24px` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_link_grey600_24px.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 15, + "endColumn": 10, + "charOffset": 166, + "charLength": 694, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 16, + "snippet": { + "text": " ~ SPDX-License-Identifier: GPL-3.0-or-later\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "782017e4e64f0644" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_lock_plus_grey600_24dp appears to be unused", + "markdown": "The resource `R.drawable.ic_lock_plus_grey600_24dp` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_lock_plus_grey600_24dp.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 1118, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "9c65949d18736caa" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_mimetype_folder_shared appears to be unused", + "markdown": "The resource `R.drawable.ic_mimetype_folder_shared` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_mimetype_folder_shared.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 15, + "endColumn": 10, + "charOffset": 138, + "charLength": 1532, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 16, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "e1c5507e82ded6bc" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_mimetype_text_calendar appears to be unused", + "markdown": "The resource `R.drawable.ic_mimetype_text_calendar` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_mimetype_text_calendar.xml" + }, + "region": { + "startLine": 8, + "startColumn": 1, + "endLine": 17, + "endColumn": 10, + "charOffset": 177, + "charLength": 688, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 6, + "endLine": 18, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "71ea72e62bbaaab4" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.ic_more_horiz_black_24dp appears to be unused", + "markdown": "The resource `R.drawable.ic_more_horiz_black_24dp` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/ic_more_horiz_black_24dp.xml" + }, + "region": { + "startLine": 7, + "startColumn": 1, + "endLine": 16, + "endColumn": 10, + "charOffset": 138, + "charLength": 491, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 5, + "endLine": 17, + "snippet": { + "text": " ~ SPDX-License-Identifier: Apache-2.0\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "afa6e3ed05973860" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.drawable.incoming_gradient appears to be unused", + "markdown": "The resource `R.drawable.incoming_gradient` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/drawable/incoming_gradient.xml" + }, + "region": { + "startLine": 8, + "startColumn": 1, + "endLine": 14, + "endColumn": 9, + "charOffset": 205, + "charLength": 233, + "snippet": { + "text": "\n \n" + } + }, + "contextRegion": { + "startLine": 6, + "endLine": 15, + "snippet": { + "text": " ~ SPDX-License-Identifier: GPL-3.0-or-later\n-->\n\n \n\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "d3d1598841aa0905" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.raw.librem_by_feandesign_call appears to be unused", + "markdown": "The resource `R.raw.librem_by_feandesign_call` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/raw/librem_by_feandesign_call.ogg" + }, + "region": { + "startLine": 1 + } } + } + ], + "fixes": [ + ], + "partialFingerprints": { + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.raw.librem_by_feandesign_message appears to be unused", + "markdown": "The resource `R.raw.librem_by_feandesign_message` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/raw/librem_by_feandesign_message.ogg" + }, + "region": { + "startLine": 1 + } } + } + ], + "fixes": [ + ], + "partialFingerprints": { + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.raw.next_voice_message_doodle appears to be unused", + "markdown": "The resource `R.raw.next_voice_message_doodle` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/raw/next_voice_message_doodle.ogg" + }, + "region": { + "startLine": 1 + } } + } + ], + "fixes": [ + ], + "partialFingerprints": { + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.layout.search_layout appears to be unused", + "markdown": "The resource `R.layout.search_layout` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/layout/search_layout.xml" + }, + "region": { + "startLine": 9, + "startColumn": 1, + "endLine": 96, + "endColumn": 9, + "charOffset": 282, + "charLength": 4024, + "snippet": { + "text": "\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n" + } + }, + "contextRegion": { + "startLine": 7, + "endLine": 96, + "snippet": { + "text": " ~ SPDX-License-Identifier: GPL-3.0-or-later\n-->\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "05e7f427634c24cc" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_talk_login_scheme appears to be unused", + "markdown": "The resource `R.string.nc_talk_login_scheme` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/setup.xml" + }, + "region": { + "startLine": 12, + "startColumn": 13, + "endLine": 12, + "endColumn": 40, + "charOffset": 469, + "charLength": 27, + "snippet": { + "text": "name=\"nc_talk_login_scheme\"" + } + }, + "contextRegion": { + "startLine": 10, + "endLine": 15, + "snippet": { + "text": " \n HvAfHtAy/QdFYqAWFFXa1VV_Iv6ZQ1.tf5swMc^45wS_vz=Wm[oyRP5D-\n nc\n false" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "07ba4e06352a94e6" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.project_id appears to be unused", + "markdown": "The resource `R.string.project_id` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/setup.xml" + }, + "region": { + "startLine": 46, + "startColumn": 13, + "endLine": 46, + "endColumn": 30, + "charOffset": 2627, + "charLength": 17, + "snippet": { + "text": "name=\"project_id\"" + } + }, + "contextRegion": { + "startLine": 44, + "endLine": 49, + "snippet": { + "text": " AIzaSyAWIyOcLafaFp8PFL61h64cy1NNZW2cU_s\n 1:829118773643:android:54b65087c544d819\n nextcloud-a7dea\n AIzaSyAWIyOcLafaFp8PFL61h64cy1NNZW2cU_s" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "891710abf696ced1" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_common_create appears to be unused", + "markdown": "The resource `R.string.nc_common_create` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 35, + "startColumn": 13, + "endLine": 35, + "endColumn": 36, + "charOffset": 1737, + "charLength": 23, + "snippet": { + "text": "name=\"nc_common_create\"" + } + }, + "contextRegion": { + "startLine": 33, + "endLine": 38, + "snippet": { + "text": " Dismiss\n Sorry, something went wrong!\n Create\n Unknown" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "7cc037e9d592d643" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_proxy_type_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_proxy_type_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 84, + "startColumn": 13, + "endLine": 84, + "endColumn": 46, + "charOffset": 5005, + "charLength": 33, + "snippet": { + "text": "name=\"nc_settings_proxy_type_key\"" + } + }, + "contextRegion": { + "startLine": 82, + "endLine": 87, + "snippet": { + "text": " \n Advanced\n proxy_type\n Proxy type" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "476b0442bd744ef7" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_proxy_host_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_proxy_host_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 86, + "startColumn": 13, + "endLine": 86, + "endColumn": 46, + "charOffset": 5160, + "charLength": 33, + "snippet": { + "text": "name=\"nc_settings_proxy_host_key\"" + } + }, + "contextRegion": { + "startLine": 84, + "endLine": 89, + "snippet": { + "text": " proxy_type\n Proxy type\n proxy_host\n Proxy host" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "a3f8a3bfc5b1ff94" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_proxy_port_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_proxy_port_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 88, + "startColumn": 13, + "endLine": 88, + "endColumn": 46, + "charOffset": 5315, + "charLength": 33, + "snippet": { + "text": "name=\"nc_settings_proxy_port_key\"" + } + }, + "contextRegion": { + "startLine": 86, + "endLine": 91, + "snippet": { + "text": " proxy_host\n Proxy host\n proxy_port\n Proxy port" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "e99adc2163d81c54" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_proxy_username_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_proxy_username_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 91, + "startColumn": 13, + "endLine": 91, + "endColumn": 50, + "charOffset": 5546, + "charLength": 37, + "snippet": { + "text": "name=\"nc_settings_proxy_username_key\"" + } + }, + "contextRegion": { + "startLine": 89, + "endLine": 94, + "snippet": { + "text": " Proxy port\n Proxy username\n proxy_username\n Proxy password" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "c6eb8d39759d56cd" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_proxy_password_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_proxy_password_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 93, + "startColumn": 13, + "endLine": 93, + "endColumn": 50, + "charOffset": 5717, + "charLength": 37, + "snippet": { + "text": "name=\"nc_settings_proxy_password_key\"" + } + }, + "contextRegion": { + "startLine": 91, + "endLine": 96, + "snippet": { + "text": " proxy_username\n Proxy password\n proxy_password\n Proxy requires credentials" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "281236a0c9096ebd" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_use_credentials_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_use_credentials_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 95, + "startColumn": 13, + "endLine": 95, + "endColumn": 51, + "charOffset": 5901, + "charLength": 38, + "snippet": { + "text": "name=\"nc_settings_use_credentials_key\"" + } + }, + "contextRegion": { + "startLine": 93, + "endLine": 98, + "snippet": { + "text": " proxy_password\n Proxy requires credentials\n proxy_credentials\n Reauthorize account" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "cb5f81a452d8f606" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_account_scheduled_for_deletion appears to be unused", + "markdown": "The resource `R.string.nc_account_scheduled_for_deletion` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 109, + "startColumn": 13, + "endLine": 109, + "endColumn": 53, + "charOffset": 7221, + "charLength": 40, + "snippet": { + "text": "name=\"nc_account_scheduled_for_deletion\"" + } + }, + "contextRegion": { + "startLine": 107, + "endLine": 112, + "snippet": { + "text": " Talk app is not installed on the server you tried to authenticate against\n Your already existing account was updated, instead of adding a new one\n The account is scheduled for deletion, and cannot be changed\n Notifications" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "8d16ff739d680e27" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_call_ringtone_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_call_ringtone_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 112, + "startColumn": 13, + "endLine": 112, + "endColumn": 49, + "charOffset": 7488, + "charLength": 36, + "snippet": { + "text": "name=\"nc_settings_call_ringtone_key\"" + } + }, + "contextRegion": { + "startLine": 110, + "endLine": 115, + "snippet": { + "text": " Notifications\n Calls\n call_ringtone\n Messages" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "8b54bf1e2502b625" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_message_ringtone_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_message_ringtone_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 114, + "startColumn": 13, + "endLine": 114, + "endColumn": 52, + "charOffset": 7659, + "charLength": 39, + "snippet": { + "text": "name=\"nc_settings_message_ringtone_key\"" + } + }, + "contextRegion": { + "startLine": 112, + "endLine": 117, + "snippet": { + "text": " call_ringtone\n Messages\n message_ringtone\n Librem by feandesign" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "e75f3b4b83851ead" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_screen_lock_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_screen_lock_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 133, + "startColumn": 13, + "endLine": 133, + "endColumn": 47, + "charOffset": 9117, + "charLength": 34, + "snippet": { + "text": "name=\"nc_settings_screen_lock_key\"" + } + }, + "contextRegion": { + "startLine": 131, + "endLine": 136, + "snippet": { + "text": " Screen lock\n Lock %1$s with Android screen lock or supported biometric method\n screen_lock\n Screen lock inactivity timeout" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "781d78f21be329eb" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_screen_lock_timeout_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_screen_lock_timeout_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 135, + "startColumn": 13, + "endLine": 135, + "endColumn": 55, + "charOffset": 9303, + "charLength": 42, + "snippet": { + "text": "name=\"nc_settings_screen_lock_timeout_key\"" + } + }, + "contextRegion": { + "startLine": 133, + "endLine": 138, + "snippet": { + "text": " screen_lock\n Screen lock inactivity timeout\n screen_lock_timeout\n Screen security" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "cf6a26c9b1d64cbb" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_settings_screen_security_key appears to be unused", + "markdown": "The resource `R.string.nc_settings_screen_security_key` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 138, + "startColumn": 13, + "endLine": 138, + "endColumn": 51, + "charOffset": 9606, + "charLength": 38, + "snippet": { + "text": "name=\"nc_settings_screen_security_key\"" + } + }, + "contextRegion": { + "startLine": 136, + "endLine": 141, + "snippet": { + "text": " Screen security\n Prevents screenshots in the recent list and inside the app\n screen_security\n Incognito keyboard" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "2abd74153d082efd" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_privacy appears to be unused", + "markdown": "The resource `R.string.nc_privacy` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 165, + "startColumn": 13, + "endLine": 165, + "endColumn": 30, + "charOffset": 11437, + "charLength": 17, + "snippet": { + "text": "name=\"nc_privacy\"" + } + }, + "contextRegion": { + "startLine": 163, + "endLine": 168, + "snippet": { + "text": " No proxy\n About\n Privacy\n Get source code" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "4fafbed3cdc1e31f" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_microphone_enabled_audio_recording appears to be unused", + "markdown": "The resource `R.string.nc_microphone_enabled_audio_recording` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 302, + "startColumn": 13, + "endLine": 302, + "endColumn": 57, + "charOffset": 22088, + "charLength": 44, + "snippet": { + "text": "name=\"nc_microphone_enabled_audio_recording\"" + } + }, + "contextRegion": { + "startLine": 300, + "endLine": 305, + "snippet": { + "text": " To enable voice communication please grant \\\"Microphone\\\" permission.\n To enable bluetooth speakers please grant \\\"Nearby devices\\\" permission.\n Microphone is enabled and audio is recording\n" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "ef15f3eeac3e4b8b" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.set_status appears to be unused", + "markdown": "The resource `R.string.set_status` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 384, + "startColumn": 13, + "endLine": 384, + "endColumn": 30, + "charOffset": 27412, + "charLength": 17, + "snippet": { + "text": "name=\"set_status\"" + } + }, + "contextRegion": { + "startLine": 382, + "endLine": 387, + "snippet": { + "text": "\n \n Set status\n Online status" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "7c12a7a51f29cf37" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_sent_deck_card appears to be unused", + "markdown": "The resource `R.string.nc_sent_deck_card` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 440, + "startColumn": 13, + "endLine": 440, + "endColumn": 37, + "charOffset": 30643, + "charLength": 24, + "snippet": { + "text": "name=\"nc_sent_deck_card\"" + } + }, + "contextRegion": { + "startLine": 438, + "endLine": 443, + "snippet": { + "text": " %1$s sent a video.\n %1$s sent an image.\n %1$s sent a deck card\n You sent a GIF." + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "0b9f94fd4adef7ad" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_message_added_to_notes appears to be unused", + "markdown": "The resource `R.string.nc_message_added_to_notes` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 451, + "startColumn": 13, + "endLine": 451, + "endColumn": 45, + "charOffset": 31392, + "charLength": 32, + "snippet": { + "text": "name=\"nc_message_added_to_notes\"" + } + }, + "contextRegion": { + "startLine": 449, + "endLine": 454, + "snippet": { + "text": " Message read\n Message sent\n Message added to notes\n Offline" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "8dd1a6bc35db2e60" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_add_attachment appears to be unused", + "markdown": "The resource `R.string.nc_add_attachment` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 456, + "startColumn": 13, + "endLine": 456, + "endColumn": 37, + "charOffset": 31710, + "charLength": 24, + "snippet": { + "text": "name=\"nc_add_attachment\"" + } + }, + "contextRegion": { + "startLine": 454, + "endLine": 459, + "snippet": { + "text": " Sending\n Failed to send message:\n Add attachment\n Recent" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "04b883bfbbdeed07" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.emoji_category_recent appears to be unused", + "markdown": "The resource `R.string.emoji_category_recent` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 457, + "startColumn": 13, + "endLine": 457, + "endColumn": 41, + "charOffset": 31771, + "charLength": 28, + "snippet": { + "text": "name=\"emoji_category_recent\"" + } + }, + "contextRegion": { + "startLine": 455, + "endLine": 460, + "snippet": { + "text": " Failed to send message:\n Add attachment\n Recent\n You:" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "0b3367ba1bcaea85" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_owner appears to be unused", + "markdown": "The resource `R.string.nc_owner` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 501, + "startColumn": 13, + "endLine": 501, + "endColumn": 28, + "charOffset": 34414, + "charLength": 15, + "snippet": { + "text": "name=\"nc_owner\"" + } + }, + "contextRegion": { + "startLine": 499, + "endLine": 504, + "snippet": { + "text": " Start group chat\n\n Owner\n Moderator" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "51486733de2298a0" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_description_record_voice appears to be unused", + "markdown": "The resource `R.string.nc_description_record_voice` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 619, + "startColumn": 13, + "endLine": 619, + "endColumn": 47, + "charOffset": 41117, + "charLength": 34, + "snippet": { + "text": "name=\"nc_description_record_voice\"" + } + }, + "contextRegion": { + "startLine": 617, + "endLine": 622, + "snippet": { + "text": " Talk recording from %1$s (%2$s)\n Hold to record, release to send.\n Record voice message\n « Slide to cancel" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "d0a791c0ea0efdc9" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_voice_message_slide_to_cancel appears to be unused", + "markdown": "The resource `R.string.nc_voice_message_slide_to_cancel` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 620, + "startColumn": 13, + "endLine": 620, + "endColumn": 52, + "charOffset": 41194, + "charLength": 39, + "snippet": { + "text": "name=\"nc_voice_message_slide_to_cancel\"" + } + }, + "contextRegion": { + "startLine": 618, + "endLine": 623, + "snippet": { + "text": " Hold to record, release to send.\n Record voice message\n « Slide to cancel\n Play/pause voice message" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "026a9ac68f2aaf75" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.user_status appears to be unused", + "markdown": "The resource `R.string.user_status` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 649, + "startColumn": 13, + "endLine": 649, + "endColumn": 31, + "charOffset": 43455, + "charLength": 18, + "snippet": { + "text": "name=\"user_status\"" + } + }, + "contextRegion": { + "startLine": 647, + "endLine": 652, + "snippet": { + "text": "\n Favorite\n Status\n Encrypted" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "12bebff92ffcef13" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.custom appears to be unused", + "markdown": "The resource `R.string.custom` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 839, + "startColumn": 13, + "endLine": 839, + "endColumn": 26, + "charOffset": 55066, + "charLength": 13, + "snippet": { + "text": "name=\"custom\"" + } + }, + "contextRegion": { + "startLine": 837, + "endLine": 842, + "snippet": { + "text": " Tomorrow\n Later today\n Custom\n Set" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "8ab4ec1459b88c2a" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.calendar appears to be unused", + "markdown": "The resource `R.string.calendar` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 841, + "startColumn": 13, + "endLine": 841, + "endColumn": 28, + "charOffset": 55144, + "charLength": 15, + "snippet": { + "text": "name=\"calendar\"" + } + }, + "contextRegion": { + "startLine": 839, + "endLine": 844, + "snippet": { + "text": " Custom\n Set\n Calendar\n Video call" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "706a9df202fb2c96" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_send_edit_message appears to be unused", + "markdown": "The resource `R.string.nc_send_edit_message` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 851, + "startColumn": 13, + "endLine": 851, + "endColumn": 40, + "charOffset": 55782, + "charLength": 27, + "snippet": { + "text": "name=\"nc_send_edit_message\"" + } + }, + "contextRegion": { + "startLine": 849, + "endLine": 854, + "snippet": { + "text": " Edit message\n Edit\n Update message\n Cancel editing" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "b6307e4ee2e92f29" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_clear_edit_message appears to be unused", + "markdown": "The resource `R.string.nc_clear_edit_message` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 852, + "startColumn": 13, + "endLine": 852, + "endColumn": 41, + "charOffset": 55846, + "charLength": 28, + "snippet": { + "text": "name=\"nc_clear_edit_message\"" + } + }, + "contextRegion": { + "startLine": 850, + "endLine": 855, + "snippet": { + "text": " Edit\n Update message\n Cancel editing\n Messages older than 24 hours can not be edited" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "dc9271f00be65e49" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.nc_conversation_not_found appears to be unused", + "markdown": "The resource `R.string.nc_conversation_not_found` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 857, + "startColumn": 13, + "endLine": 857, + "endColumn": 45, + "charOffset": 56217, + "charLength": 32, + "snippet": { + "text": "name=\"nc_conversation_not_found\"" + } + }, + "contextRegion": { + "startLine": 855, + "endLine": 860, + "snippet": { + "text": " Edit message\n (edited)\n Conversation not found\n Add to Notes" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "4c0690b30ee2ae91" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.get_invitations_error appears to be unused", + "markdown": "The resource `R.string.get_invitations_error` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 862, + "startColumn": 13, + "endLine": 862, + "endColumn": 41, + "charOffset": 56521, + "charLength": 28, + "snippet": { + "text": "name=\"get_invitations_error\"" + } + }, + "contextRegion": { + "startLine": 860, + "endLine": 865, + "snippet": { + "text": " Cancel editing\n Edit\n Failed to fetch pending invitations\n Edited by %1$s" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "6ae75ee1edf462f8" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.show_ban_reason appears to be unused", + "markdown": "The resource `R.string.show_ban_reason` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 875, + "startColumn": 13, + "endLine": 875, + "endColumn": 35, + "charOffset": 57412, + "charLength": 22, + "snippet": { + "text": "name=\"show_ban_reason\"" + } + }, + "contextRegion": { + "startLine": 873, + "endLine": 878, + "snippet": { + "text": " Internal note\n Ban\n Show ban reason\n Error occurred when unbanning participant" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "93ac7177d8156b84" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.status_reverted appears to be unused", + "markdown": "The resource `R.string.status_reverted` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 886, + "startColumn": 13, + "endLine": 886, + "endColumn": 35, + "charOffset": 58369, + "charLength": 22, + "snippet": { + "text": "name=\"status_reverted\"" + } + }, + "contextRegion": { + "startLine": 884, + "endLine": 889, + "snippet": { + "text": " Previously set\n Failed to set conversation Read-only\n Status Reverted\n Your status was set automatically" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "7b8878470b034d6a" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.string.conversation_archived appears to be unused", + "markdown": "The resource `R.string.conversation_archived` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/strings.xml" + }, + "region": { + "startLine": 896, + "startColumn": 13, + "endLine": 896, + "endColumn": 41, + "charOffset": 59008, + "charLength": 28, + "snippet": { + "text": "name=\"conversation_archived\"" + } + }, + "contextRegion": { + "startLine": 894, + "endLine": 899, + "snippet": { + "text": " Archived %1$s\n Unarchived %1$s\n Conversation is archived\n Local time: %1$s" + } + } + } + } + ], + "fixes": [ + ], + "partialFingerprints": { + "sourceContext/v1": "1ed493c014c3649c" + } + }, + { + "ruleId": "UnusedResources", + "ruleIndex": 16, + "message": { + "text": "The resource R.style.TextInputLayoutTheme appears to be unused", + "markdown": "The resource `R.style.TextInputLayoutTheme` appears to be unused" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uriBaseId": "%SRCROOT%", + "uri": "app/src/main/res/values/styles.xml" + }, + "region": { + "startLine": 230, + "startColumn": 12, + "endLine": 230, + "endColumn": 39, + "charOffset": 11894, + "charLength": 27, + "snippet": { + "text": "name=\"TextInputLayoutTheme\"" + } + }, + "contextRegion": { + "startLine": 228, + "endLine": 233, + "snippet": { + "text": " \n\n \n\n