nextcloud / nextcloud/android

When the file name contains "%2[", switching the grid view stably crashes.

Open
#15,930 0 comments 0 reactions 0 assignees View on GitHub
0. Needs triage bug hotspot: filename handling
Dominant language
Kotlin
Stars
5.6k
Forks
2k
Avg merge
2d 18h
Merged PRs (30d)
92

Description

### ⚠️ Before posting ⚠️

- [x] This is a **bug**, not a question or an enhancement.
- [x] I've [searched for similar issues](https://github.com/nextcloud/android/issues) and didn't find a duplicate.
- [x] I've written a clear and descriptive title for this issue, not just "Bug" or "Crash".
- [x] I agree to follow Nextcloud's [Code of Conduct](https://nextcloud.com/contribute/code-of-conduct/).

### Steps to reproduce

Click the button to switch the grid view.

### Expected behaviour

Switch to the grid view correctly instead of crashing.

### Actual behaviour

No matter what file type it is, switching the grid view will immediately crash when there is "%2[" in the file name.

### Android version

12

### Device brand and model

Xiaomi Civi

### Stock or custom OS?

Stock

### Nextcloud android app version

3.34.0

### Nextcloud server version

31.0.4

### Using a reverse proxy?

Yes

### Android logs

### Cause of error
```java
Exception in thread "main" java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern : %2[
at java.net.URLDecoder.decode(URLDecoder.java:178)
at com.owncloud.android.utils.FileStorageUtils.containsBidiControlCharacters(FileStorageUtils.java:82)
at com.owncloud.android.ui.adapter.OCFileListAdapter.handleGridMode(OCFileListAdapter.java:582)
at com.owncloud.android.ui.adapter.OCFileListAdapter.setFilenameAndExtension(OCFileListAdapter.java:575)
at com.owncloud.android.ui.adapter.OCFileListAdapter.bindHolder(OCFileListAdapter.java:490)
at com.owncloud.android.ui.adapter.OCFileListAdapter.onBindViewHolder(OCFileListAdapter.java:473)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7747)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7847)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6646)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6917)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6757)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6753)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2362)
at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:584)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1622)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:687)
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:182)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4645)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4348)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4919)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:689)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1103)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1818)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1584)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:145)
at com.google.android.material.appbar.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:43)
at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:2461)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:918)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at androidx.drawerlayout.widget.DrawerLayout.onLayout(DrawerLayout.java:1263)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:866)
at android.view.View.layout(View.java:23563)
at android.view.ViewGroup.layout(ViewGroup.java:6452)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3863)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3313)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2277)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9037)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1142)
at android.view.Choreographer.doCallbacks(Choreographer.java:946)
at android.view.Choreographer.doFrame(Choreographer.java:875)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1127)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8283)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)

```

### App information
* ID: `com.nextcloud.client`
* Version: `30340090`
* Build flavor: `gplay`

### Device information
* Brand: `Xiaomi`
* Device: `mona`
* Model: `2109119BC`
* Id: `SKQ1.211006.001`
* Product: `mona`

### Firmware
* SDK: `31`
* Release: `12`
* Incremental: `V13.0.6.0.SKVCNXM`

### Server error logs

```bash

```

### Additional information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.