Commons Android app: Make upload more reliable

10 min readAug 23, 2023

Hi, my name is Ritika Pahwa and I’m a Google Summer of Code (GSoC) contributor from India. I contributed to the Wikimedia Commons Android app and worked towards upload reliability. Here’s what I accomplished as a part of GSoC this year 👇

Overview

Wikimedia Commons Android app allows users to upload and view pictures from their Android phone/tablet on the Commons server. Files from Commons are used across all the Wikimedia Foundation’s projects, including Wikipedia.

The Commons Android app

The project

This project aims at fixing three major bugs reported on the Commons app:

  1. Picture location is sometimes lost despite being present in EXIF [Issue #5196]
  2. Upload often fails or gets stuck, especially when uploading 3 or more pictures [Issue #5128]
  3. Retried uploads stuck in queued state [Issue #5136]

Tech stack used: WorkManager (Android Jetpack), Java, Kotlin, RxJava, XML

Mentors

Nicolas Raoul, Kaartic Sivaraam

The location loss issue

EXIF metadata contains some crucial information about the pictures, including their location. Users may opt to share these location tags on the Commons app. Unfortunately, these tags used to get stripped off before the app could retrieve them. I discovered two major reasons for this 👇

The new Android photo picker redacts location tags

The new Photo Picker introduced by Android restricts location access and redacts location tags from the EXIF data despite using the ACCESS_MEDIA_LOCATION runtime permission. This is more prevalent on newer versions of Android, especially Android 11 and above. While the Commons app did not invoke this photo picker explicitly, the GET_CONTENT takeover triggers it on some devices and is expected to impact a lot more devices in the future.

Since the issue is specific to the Android media provider and does not impact the documents provider, I suggested switching to the ACTION_OPEN_DOCUMENT intent.

ACTION_GET_CONTENT intent, however, displayed a wide range of third-party gallery app providers, something that ACTION_OPEN_DOCUMENT does not show. We decided to leave it up to the users for better user experience — they can choose the one they like from the Settings.

Here’s a list of changes I made:

✅ Made the ACTION_OPEN_DOCUMENT intent as default to prevent location loss

✅ Implemented a toggle in the Settings that allows users to choose the right picker and added a popup that redirects the users to the website where they can find more information about various pickers

Toggle switch with a warning

✅ Removed tech jargon from photo picker related information (yet to be merged)

This solved the location loss issue for the normal selector in the Contributions and Nearby fragments.

Related pull requests

Merged:

Not merged yet:

The default camera apps on some devices may strip location tags off

The Commons app uses the ACTION_IMAGE_CAPTURE intent for the in-app camera functionality. This intent triggers the default camera application on the device to handle the image capture process and return the result to the app.

The default camera application may vary from the one set by the manufacturer to the one set by the users. Now, it solely depends on these applications if they return location tags along with the image as the result.

Tasks accomplished:

✅ Implemented a popup that explains the users why they need to provide location access to the app to use the in-app camera

✅ Enabled location recording before and after image capture

✅ Used the location recorded after the image capture to set the location coordinates of the image (without modifying the EXIF metadata) in the upload wizard only if the difference between location before and after image capture comes out to be less than 100 metres

Related pull request

Not merged yet:

The failing/stuck upload issue

Uploading large sets of images on the Commons app while the screen was turned off frequently resulted in upload failures or getting stuck in the process. This happened primarily because of:

  • Battery optimisations on Android
  • The app is killed/closed by the user, or the device is rebooted

Since all the users may not prefer to turn battery optimisations off, I tried to make the upload experience smoother even for those users who have their battery savers turned on and/or use the app with ‘Optimised’ battery usage mode.

Tasks accomplished:

✅ Changed compileSdkVersion to 33 as suggested in the documentation and upgraded to the latest stable release of WorkManager

✅ Fixed the stuck uploads issue to a large extent and automated retries — failed uploads are retried as soon as the user returns to the app

✅ Added a popup with detailed instructions that suggests users to turn battery optimisation off and takes them to the relevant Settings page

Suggesting users to turn battery optimisation off

Results

While the changes have not been merged yet, my mentors tested the changes for a considerable amount of time. Here are some improvement metrics:

Test conditions:

  • Real Pixel6pro smartphone.
  • Good WiFi
  • “Throttly” bandwidth limitation app set to “Regular 3G”.
  • Launch a multi-upload of 3 pictures taken by that phone (around 5MB each), then immediately turn the smartphone’s screen off.
  • Not connected to any power source, but more than 20% of battery left.
  • Seven trials.

Results before GSoC, optimized battery mode:

  • 3 successes: 3 occurrences
  • 2 successes 1 fail: 1 occurrence
  • 1 success 2 fails: 2 occurrences
  • 3 fails: 1 occurrence

Results after GSoC, unrestricted battery mode:

  • 3 successes: 6 occurrences
  • 3 successes but 1 erroneously shown by the app as failed: 1 occurrence

Results after GSoC, optimised battery mode:

  • 3 successes without switching screen on: 5 occurrences
  • First 2 successes, for the third switch screen on briefly 2 times with 10+ minutes in-between, also successful in the end: 1 occurrence
  • 3 successes but 1 erroneously shown by the app as failed: 1 occurrence

Test results analysis

Judging by these tests in a slow internet environment, the app went from a 57% failure rate to a 14% failure rate (0% failure rate if we consider as success a picture which has been successfully uploaded but reported in the app as failed) as a result of improvements I implemented.

Related pull request

Not merged yet:

The third issue?

Users can retry failed uploads on the Commons app. While automatic retries have alleviated the issue, there is still a possibility of ending up with retries getting stuck in ‘Queued’ state if the user tries to press the retry button manually under certain circumstances. If the user retries ten uploads, then it is very likely that nine of them show up as ‘Queued’ and remain queued forever.

I realised that doWork() in the UploadWorker fetches all the images having states as STATE_QUEUED or STATE_QUEUED_LIMITED_CONNECTION_MODE. So, when the first image is retried, doWork() fetches it. For the rest of them, while the state changes in the database, doWork() is not aware of these changes as they are not fetched again.

This would simply need a check after the first retried upload gets completed to detect new changes and process them accordingly. Since this issue requires the upload issue-related pull request to get merged first, much discussion has not been done yet on it.

Related pull request

Not merged yet:

Blog Series

I wrote detailed blogs on my findings during GSoC this year, where I discussed my thought process, multiple ways of approaching the same problem and why I chose a particular solution for it.

Curious to know more about my GSoC journey? You may check out all my blog posts here 👇

GSoC'23 with Wikimedia Foundation

8 stories

Future Work

While this project has improved upload reliability to a great extent, there are still some aspects that can make the upload process even more reliable. Some of them, if not all, are:

  • Enqueuing failed uploads: As of now, failed uploads are automatically retried as soon as the user returns to the app. They are uploaded simultaneously with the ongoing upload. Enqueuing them gracefully will work more efficiently even when the internet speed is slow.
  • uploadstash-file-not-foundException: Unfortunately, we still encounter anuploadstash-file-not-found exception which does not allow the retries to proceed.
  • Stuck uploads after the app has been closed/killed or the device has been rebooted.
  • Handling the erroneous transaction: This happens when the stash upload is successful, but the Wikidata edit does not take place(this is just when the internet goes off). So, it shows up on the server but is not marked as successful on the app because the Wikidata edit does not take place. An upload is considered successful only after the Wikidata edit. When this does not happen, the upload is marked as “Failed”, and the upload is started again when the connection is back.

I plan to continue working towards these aspects to facilitate a smooth upload experience for all the Commons app users :)

Apart from this, the in-app camera still fails to record location information sometimes, especially during the first run due to GPS initialisation delay. Less accurate, but a quick solution could be using network provider conditionally. For more accuracy, we might educate the users about the potential delay. Here’s the link to the issue:

Acknowledgement

I would like to express my extreme gratitude to my mentors, Nicolas Raoul and Kaartic Sivaraam, for their constant support and guidance throughout this GSoC. Testing alone would have been a big challenge but my mentors tested my branches frequently, thereby helping out with the edge cases I missed. Their invaluable experience immensely helped me come up with more feasible solutions. A special mention to Kartikay Kaushik for reviewing my pull requests and sharing his valuable suggestions and thought-provoking insights. Well, things wouldn’t have been so smooth without having a structured exposure to almost everything — thanks to Wikimedia Foundation as well as the GSoC team!

My key takeaways

GSoC was fun for me — full of thrill and challenges and imparting life lessons at the same time! Sharing my key takeaways from the last four months:

  • Always expecting the unexpected: After spending 2 weeks of the community bonding period and 1 week of the coding period just trying to reproduce the issue, I never knew I could figure out a solution for the first bug! I believe that the location loss issue took longer than expected. I never expected tons of exceptions cropping up in the same issue — NullPointerException, SocketTimeoutException, IOException, uploadstash-file-not-found to name a few. Being prepared to face the unexpected occurrences might help in planning and managing in a much better way.
  • Asking for help at the right time: My problem: I don’t ask for help unless I’m double sure that I’ve exhausted all the other options — going through the code, reading the documentation thoroughly, searching stack overflow, or sometimes even giving dozens of prompts to ChatGPT or Bard in case none of them work to figure out something I may have overlooked (they are even more careless than me, and generate things that do not even exist :p). My mentor suggested me to reach out to the person who’d written the stashed upload-related code, but I did not do that without being sure that I’d done my research. Result: that’s still up on my to-do list. Asking for help at the right time might have helped fix it promptly.
  • Simpler tasks are as important as the other crucial tasks: To be honest, most of the blunders I committed during GSoC account for super simple tasks. I probably tried wrapping them up quickly for other tasks that I believed were crucial (For me, crucial = something I don’t know how to fix and need more research). Learnt that carefully handling simpler tasks can save a lot of time and efforts👍

This GSoC helped me gain my curiosity back — curiosity to explore, to learn, to experiment and to take risks maybe? There’s still a long way to go, but my learning from this GSoC will help me with almost everything.

Thank you for reading! I’m always looking for feedback to improve my work, so please feel free to comment on this blog post with your suggestions. You can also connect with me on LinkedIn or follow me on GitHub to stay updated about my latest projects :)

--

--

Ritika Pahwa
Ritika Pahwa

Written by Ritika Pahwa

Documenting my journey 📝 | CSE Undergrad at IGDTUW

No responses yet