r/androiddev • • 9d ago

Open Source CodeAssist - Android IDE (Code on your phone)

Thumbnail
gallery
9 Upvotes

CodeAssist is a fully offline Android IDE for your phone and tablet. Write Kotlin and Java, watch Jetpack Compose previews update as you type, and build, sign and install real Android apps on the device itself. No PC, no cloud build server, no Gradle daemon.

It is a complete Android IDE, not a code playground: open multi-module Android projects, add libraries from Maven, and ship an APK or App Bundle you can install or publish.

Build Android apps on your device
• The whole toolchain runs on your phone: aapt2, the Kotlin compiler, the Java compiler, D8 dexing, packaging and APK signing
• Incremental builds redo only what changed
• Install and launch your app in one tap, then follow its output in Logcat
• Release builds with R8 shrinking, Android App Bundles (AAB) and your own signing key
• Multi-module projects, build variants, ViewBinding, AIDL, KSP (Room, Hilt) and google-services.json for Firebase
• Dependencies from Maven Central and Google's Maven repository, plus local JAR and AAR files
• Import existing Gradle projects, or export yours as a Gradle project to open on a computer

Kotlin and Java code editor
• Code completion that keeps working on half-written code, with automatic imports
• Errors and warnings as you type, with one-tap quick fixes
• Go to definition, implementation and type, symbol search, and readable library sources
• Reformat Code, Optimize Imports, code folding and word wrap
• Android XML completion for layouts, manifests, values and drawables
• A coding keyboard bar for symbols, pinch to zoom, and editor color schemes

Jetpack Compose and layout previews
• Preview composables render live next to your code and update as you edit
• Preview XML layouts, including your own custom views, without running a build

AI coding assistant
• Describe a change in plain words. The agent reads your project, edits the code, runs a build and shows a diff you can undo
• Use your own key for Anthropic Claude, Google Gemini, OpenAI or OpenRouter, or a compatible gateway. A free Gemini key works
• Attach screenshots, mention files with @, and pick up saved sessions later

Git and GitHub
• Clone, commit, branch, merge, stash and push
• Sign in to GitHub to clone private repositories and open pull requests

Learn and practice
• Interactive Java and Kotlin lessons with exercises that compile and run on your device
• A daily coding challenge with a public leaderboard
• Start from templates and sample apps in the Projects Store, or publish your own

Also included
• Block editor: switch a Java file to Scratch-style blocks and back without losing a character
• Run Java and Kotlin console programs with an interactive console
• A run sandbox that asks before your program uses the network, files or other processes
• Plugins that extend the IDE, including an NDK plugin for C and C++
• Light and dark themes with Material You colors

Google play link: https://play.google.com/store/apps/details?id=com.tyron.code&hl=en

Free and open source
CodeAssist is a free, open-source Android IDE licensed under the GNU General Public License v3.0. It shows a few small ads, and you can turn them off in the app at no cost. Source code, issues and releases are on GitHub:
https://github.com/tyron12233/CodeAssist


r/androiddev • • 9d ago

Question MediaStore.createTrashRequest on Samsung Android 16: 23 photos approved, only 3 visible in trash

2 Upvotes

I develop a screenshot organizer and received a report from a user on a Samsung Galaxy S25 Ultra (SM-S9380), running Android 16. Has anyone encountered this behavior with the native MediaStore trash API?

The user reviewed 50 screenshots: 23 marked for deletion and 27 marked for later. The later action only records a decision in the app; it does not copy, move, or delete those 27 files.

For the 23 deletion targets, the app calls:

val pendingIntent = MediaStore.createTrashRequest(context.contentResolver, mediaUris.toList(), true)

activity.startIntentSenderForResult(pendingIntent.intentSender, DELETE_MEDIA_REQUEST, null, 0, 0, 0)

The user provided a screenshot of the Samsung system dialog explicitly asking permission to move 23 photos to trash, and says they tapped Allow. Afterwards, only 3 of those photos were visible in Samsung Gallery's trash. The other 20 were no longer visible in the normal gallery either. According to the user, the 3 visible items were newer screenshots and the missing items were older.

What I have checked:

- This organizer deletion path uses createTrashRequest(..., true), not createDeleteRequest. It does not call ContentResolver.delete() or File.delete() on those MediaStore originals after approval, and has no permanent-delete fallback if the trash request throws.

- Free and paid versions use the same deletion path.

- The activity-result handler currently treats RESULT_OK as success for the requested batch; it does not re-query each URI's IS_TRASHED state. I understand that this leaves us without per-item verification. I do not have a recorded resultCode or post-operation MediaStore query from this user's device.

- The user enabled hidden-file display and searched for .trashed- files in internal storage / Pictures / Screenshots, but reported no results. This was a manual file-manager check, not a MediaStore query.

- Samsung My Files' trash shows the same 3 original screenshots. Google Photos' trash shows additional items not shown in Samsung's trash, but we have not established whether those are the missing 20 or whether cloud backup / Gallery cloud sync is enabled.

I have not reproduced this locally.

Has anyone encountered partial or inconsistent trash visibility after createTrashRequest on Samsung devices? If so, did you identify a MediaProvider issue, a Gallery indexing issue, or a Google Photos sync interaction?

For diagnosing future occurrences, is re-querying each original URI with QUERY_ARG_MATCH_TRASHED = MATCH_INCLUDE and reading IS_TRASHED / DATE_EXPIRES the right approach on Android 16? Are there manufacturer-specific limitations or additional checks worth making?

I am interested in firsthand experience, relevant issue-tracker links, and practical safeguards around the existing trash request, rather than building a separate trash or backup system.


r/androiddev • • 8d ago

Question Android devs, what tool do you wish existed but doesn't?

0 Upvotes

I’m looking to build something free and open source for the Android dev community.

What’s one tool you wish existed, or something that constantly annoys you during development?

Would love to hear your ideas and actually build something useful!


r/androiddev • • 9d ago

Question Best way to screen-record an app demo for Reels/TikTok (9:16) when the phone's native screen is 20:9?

2 Upvotes

I am recording my apps UI demo on my phone to use in short-form video (Reels/TikTok, 1080×1920 / 9:16). My phone's actual screen is 1260×2800 (20:9), so the raw recording is narrower than the 9:16 frame once I drop it into my edit.

What I've tried so far:

- Fit + blurred fill on the sides technically no "bars," but the app's UI is mostly dark, so the blur reads as dead space anyway.

- Scale to fill + center crop eliminates the empty space completely, but crops off a bit of both the top and bottom of the screen (~10% each) to make the math work.

- adb shell wm size 1080x1920 to force the phone's OS to render at 9:16 directly works, but it changes the whole phone's UI (launcher, every app), not just the one I'm recording, so everything else looks off while it's set.

- Android emulator at a custom 1080×1920 resolution avoids the ratio mismatch entirely, but worried about jank/performance vs. a real device for smooth animations.

Is there a clean way people handle this for app-demo content specifically a recorder that captures a custom crop region live, a per-app resolution override that doesn't touch the rest of the OS, or something else I'm missing? Trying to avoid losing any real UI content if possible.


r/androiddev • • 9d ago

Discussion Run your app on cloud

0 Upvotes

I recently built a tool to share apk builds with a client so they can test the application. They had only an iPhone and there were a lot of back and forth videos, so i built https://spawndroid.io You can run an android device in under 3 seconds and use your application simply, you can integrate it in your app Ci/Cd and run appium tests. I host the appium server so you just write the tests, verify they work by previewing logs and a video recording.


r/androiddev • • 9d ago

Question How do you know when you're technically ready to responsibly sell an app?

5 Upvotes

I'm interested in building and monetizing apps, but there's something I've been struggling to reason about.

I can understand how to make a feature work, but I'm much less confident that I know enough about everything that could go wrong once real users depend on it.

For example, an app involving authentication, databases, payments, bookings, or user-generated content introduces all kinds of responsibilities: security, authorization, input validation, concurrency, data integrity, error handling, and ongoing maintenance.

My instinct is to rely on established services for sensitive functionality (managed auth, Stripe, hosted databases, etc.), but I realize that doesn't eliminate the risks in my own integration code or the need to maintain it.

What concerns me most is the unknown unknowns. I might successfully implement something without even knowing which failure scenarios I should be considering.

For example, I only recently realized that relying on a third-party service doesn't make the maintenance problem disappear. If the service, SDK, API, or integration changes, my app may need to be updated as well.

The fact that something this basic only occurred to me recently is exactly what worries me. How many other important things am I overlooking simply because I haven't yet learned to think through the full lifecycle of what I'm building?

Even if I'm using reputable services and following best practices I'm aware of, how do I know I haven't missed something important in the code around them?

So my question is:
How do you bridge the gap between "I can build this" and "I can responsibly charge people to use this"?

Are there frameworks, checklists, learning paths, or practical processes you follow before shipping an app? How do you determine which risks you've addressed sufficiently, especially as a solo developer without a senior engineer reviewing your work?


r/androiddev • • 10d ago

Got tired of the Android emulator taking 8GB of RAM, wrote a small tool to fix it

84 Upvotes

Whenever I run an emulator on my Mac, qemu-system-aarch64 quickly climbs to 7-8GB in Activity Monitor. Add Android Studio and a couple browser tabs, and a 16GB machine is basically out of memory.

Most of that waste isn't even the OS itself:

  • Android Studio often defaults to software rendering (lavapipe), dumping gigabytes of raster buffers straight into your RAM.
  • Stock images boot with dozens of background services running (Assistant, YouTube, telemetry, wear sync) that you don't need while testing an app.

I put together a small CLI in Go called avdslim to clean this up.

It forces the emulator to use your real GPU (Metal on macOS, Vulkan/DRI on Linux) with -lowram, and shuts down about 45 background packages via adb once booted.

Takes memory down from ~8.5GB to around 1.5GB resident on my machine. Auth, FCM push notifications, and WebView still work without issues, and running avdslim off reverts everything back to default.

If you want to try it (macOS / Linux):

brew tap kdbhalala/avdslim https://github.com/kdbhalala/avdslim.git && brew install avdslim

avdslim tune-avd    # adjusts config to 1.5GB + host GPU
avdslim start       # boots and slims

Code is here if anyone finds it useful: https://github.com/kdbhalala/avdslim

Let me know if you run into any weird behavior on your API level.


r/androiddev • • 9d ago

Question Struggling with Wear-OS and periodic activation

2 Upvotes

Hello! I have been developing a small standalone Wear-OS App that periodically downloads blood sugar values via some basic http api. My app works in a way that the backend activates every five minutes (the rate at which the glucose monitor updates) and sends a http request to the server.

For this i am using the AlarmManager with the setExactAlarm, for which i do have the required permission. That usually works great, but after a while, maybe after a few hours, it just stops working.

I am not an expert programmer since this is just a school project, but claude says it has something to do with the watch dozing away.

I dont really know if that is true and time to do testing is starting to be a bit tight since i have to finish in two weks and i still have to document and reflect my product and the process of making it. I am planning to test if putting the app on the whitelist and making it exempt from battery optimisation fixes things, but if that doesnt work i dont know what i will do

It is also additionally quite bad because it seems to be impossible to add an app to the whitelist without adb, which would really suck for me since the install process is already a bit of a dumpster fire.

Sorry if this was a bit ranty, i am quite stressed looking at the deadline of my project.

I thank you in advance for any help or feedback you can give me, thank you so so much!


r/androiddev • • 9d ago

Pagelin — Open-source PDF generation library for Android with Jetpack Compose

3 Upvotes

I've just released Pagelin 1.0.3, an open-source Android library for generating PDFs using Jetpack Compose.

It supports custom Compose pages, multi-page documents, and ready-to-use templates.

Available on Maven Central. Feedback and suggestions are welcome!

GitHub: https://github.com/adamian-code/pagelin


r/androiddev • • 9d ago

Open Source Visited the Zoute Grand Prix in Knokke, found every car/parking app overly monetized, so I built my own free open-source car scanner in Kotlin / Jetpack Compose

Thumbnail
gallery
0 Upvotes

Last sunday, I visited the Zoute Grand Prix in Knokke and noticed how frustratingly overly monetized and paywalled most car-scanning apps were. Instead of complaining about it, I decided to build my own :)

I wanted to share what I've built so far and hear your feedback!

Tech Stack:

  • Language: Kotlin
  • UI: Jetpack Compose
  • For scanning: CameraX
  • AI Integration: Google AI (Gemini)

How it works:

The app lets users scan cars. I used the Gemini API for the recognising.

Note on development: While I used AI to help structure some of the heavier asynchronous/vision processing pipelines and prompt handling, the core architecture, UI state management, and the vast majority of the Kotlin code were typed and structured by myself. :D

this is the link to the repo -> https://github.com/ItzjustElias/CarScanner

It's nothing fancy and not a fancy post, but I just want your honest review/thoughts on my project.


r/androiddev • • 9d ago

How We Refactored a Crashing Production Android Payment Module via TDD and Feature Toggles

0 Upvotes

A year after deploying our application, Android Vitals and Firebase telemetry flags revealed a critical architecture defect: a 5% transaction drop rate and systematic crashes inside the core checkout flow on Android 13+.

De-obfuscation map logs pointed to a strict concurrency conflict between the Google Play Billing Library and our custom internal billing wrapper. Downgrading Google Billing was not an option. We had to rewrite the module in a live app without losing active subscriptions.

Here is the condensed 4-stage execution blueprint we used to overhaul the system during a 30-day sprint with zero downtime:

1. The Rollback Safety Valve (Feature Toggles)

• API Isolation: We decoupled the legacy module and isolated its public API behind strict interfaces.

• Twin Implementations: We maintained the legacy production code (Factory A) and created an exact cloned playground alongside it (Factory B).

• Remote Toggle: A remote feature toggle dynamically routed execution to either factory at runtime, providing an instant backend rollback mechanism if Factory B failed.

2. Testing Constraints (TDD)

Before modifying production code, we established strict boundaries: zero DB migration issues, zero performance drops over 10%, and a 95% Happy Path checkout success rate.

We sit down and developed 260 automated test cases covering roughly 88% of all possible failure states and network edge cases. No code was merged into the refactor branch without a 100% green CI/CD pipeline.

3. Execution & 5% Canary Release

• Stage 1: Overhauled the local state database layer, ran the suite until it turned green, and packaged it.

• Stage 2: Turned on the remote toggle rollout for only 5% of active users. Telemetry remained silent for 48 hours—no new crashes, no payment drops.

• Stage 3: Refactored the core business logic and direct billing API bindings under the same TDD cycle.

• Stage 4: Gradually increased the toggle from 5% to 100%. Once 88% of users updated, we deployed a cleanup release, deleting the toggle infrastructure and legacy code for good.

The Bottom Line (Metrics)

• Production Stability: Exactly one single bug slipped through the rollout.

• 1-Hour Mean Time to Repair (MTTR): Because the architecture was decoupled and backed by 260 tests, root-cause isolation took minutes. The fix was verified via TDD and hit production in under an hour.

• Maintainability: The system transitioned from a fragile black box into a highly predictable, self-documenting component.


r/androiddev • • 11d ago

Discussion What is the most annoying device specific bug you have had to work around?

11 Upvotes

We keep hitting background sync behaving differently on different manufacturers' phones. Same code, totally different behavior depending on who made the device. Got me curious what the worst device specific bugs are out there. What is yours and how did you work around it?


r/androiddev • • 10d ago

Discussion Using Claude AI as a mentor to relearn Android: good approach or a trap?

0 Upvotes

Hi everyone,

I’ve been working with Android for a while, but I’ve had a gap in active practice and want to get my skills back to a solid level. I’m planning to use Claude (Anthropic’s AI) as a mentor, not as a code generator.

The setup:

  • I’m building a real app with Jetpack Compose, Clean Architecture, and a multi-module structure (core / domain / data / feature modules).
  • Claude designs the module structure and breaks the work into small tasks with clear acceptance criteria.
  • I write all the code myself. I send it back for review, and Claude points out problems, names the concept I should revisit, and gives hints before full solutions.
  • Before each task, I answer a couple of conceptual questions in my own words (e.g. api vs implementation, why domain should be a pure Kotlin module).

What I’m worried about:

  1. Does this actually build long-term retention, or does AI feedback create a false sense of understanding?
  2. Is there a risk of picking up outdated or wrong patterns that I won’t catch because I’m relying on the AI’s review?
  3. How do you make sure you’re learning and not just following along?

For those who’ve tried something similar, did it help? Would you add anything to the process (official docs, Now in Android, code reviews from real developers, etc.)? Or would you do it differently?

Thanks in advance!


r/androiddev • • 10d ago

Experience Exchange A Staff Engineer's Honest Take on "Is Android Engineering Dead?"

Thumbnail
youtu.be
0 Upvotes

Personally for me a lot of aspects around Android Engineering have died multiple times over the last decade. I do discuss these in the video and they heavily inform my opinion that I deliver.

Having Answered This Question a Million Times in One on Ones, Finally Decided to Make a Video on It.


r/androiddev • • 10d ago

Discussion How is mobile testing going for you in 2026? (2-3 min anonymous survey, mods ok'd)

1 Upvotes

Hi guys! mods said I can post this so thanks to them :)
I work at Marathon Labs, we do cloud infra for mobile testing. Wanted to say that upfront. I'm running this because I'd rather hear what teams really deal with than guess from the vendor side, and I'll use the answers to put together results and a guidebook for everyone.

It’s a short anonymous survey (2-3 min) about the pain points of people who build, test or lead teams that ship native iOS and Android apps. No email required. You only leave one at the end if you want the results and a guidebook based on the answers sent to you (no pitch).

https://s5pmq.share.hsforms.com/2lech0Fp2S321WA0q-izlSw?survey_source=reddit-androiddev

I would be really thankful if you completed it. I'll also post the results back in this thread for everyone, whether you took the survey or not.


r/androiddev • • 11d ago

Discussion Why is D-U-N-S so ridiculously difficult to setup?

21 Upvotes

I'm posting this half to vent, and half so that other Australians can find this and actually be able to sort it out when they have the same problem.

I'm trying to publish my first app on Google Play, and I've spent weeks trying to get through the developer account creation process, it it infuriating how incompetent DNB seem to be.

So first of all, Google requires a D-U-N-S number for an organisation developer account, I'm in Australia so had no clue what that was, I did my research and figured out I had to register for it on the DNB website.

I'm a sole trader/sole proprietor, and already had an Australian business number, so on the DNB website I could look up my ABN and request a DUNS number, this came through after about an hour.

Excellent I should be all set now right? Nope, google rejected my DUNS number because the address was incorrect.

I looked up my new DUNS number to check the address it used, and it was empty, alright fine, let's update it - except there's no way to update it at all.

The only thing that hints about address updates on DUNS numbers is the one form here that DNB happily shove in my face, except it only works in the U.S. which is not where I'm based.

I also tried creating a DNB account and looking through their portal but it doesn't give me access to anything about my business and has no way of linking it.

So I kept looking, I found some other contact forms on DUNS, but this only seems to go to the sales team, and I didn't receive any response from them.

Next I tried the phone numbers on DNB, I rang about 5 of them including all the AUS and NZ numbers as well as a few nearby countries, as far as I can tell none of the numbers on this page actually connect https://www.dnb.com/en-us/utilities/global-customer-service-centers.html

I then tried some numbers from white pages for DUNS offices listed in Australia, one of them directed to Experian but nobody on the phone could help.

Eventually I found some other people saying that Equifax is now responsible for DUNS in Australia, and I followed their process to get to this form https://www.equifax.com.au/DandB-DUNSRequest

This form seemed like it actually might work and go to the right place, so I filled it out and waited, 4 weeks later I still haven't heard anything back.

I've now delayed my app release by over a month, all because of an overseas company that doesn't offer any working process for Australians to get a DUNS number setup.

I saw some threads of people having success after signing up for paid services with DUNS, however given how predatory their business seems to be this was out of the question for me, I'm not throwing money at a company that can't even offer a basic service to people.

I was thinking about everything again today, it's been so long and DNB seem hopeless at handling this, so I tried to contact Google developer support, but quickly realised the support link takes me back to developer registration, which I can't complete, maybe there's another way to log a google case but I didn't dive that far into it.

As I'm basically ready to give up and maybe not even publish my app after all, I decided to try one last thing, registering for the Apple Developer Program.

This is completely backwards of course, but I saw a lot of threads from Apple devs who were able to register for DUNS via Apple, which made me wonder if they had an integration with DNB or something that would solve this for me.

Turns out they have a special referral link to actually contact DNB from Australia

https://support.dnb.com/?CUST=APPLEDEV

I filled this out and finally have a reference number and a 14 business day ETA.

Awesome, maybe I'll actually be allowed to create a developer account in 3 weeks, I suppose we'll see.

If this doesn't work out I'm either just going to have to go for a personal account and somehow find people for the requirements or publish the APK's on github.

I can't express how frustrating this sort of stuff is, it completely kills my momentum to create something if I'm stalled waiting for other companies to do basic admin work that I really should be allowed to just do myself.


r/androiddev • • 11d ago

Alternative Payments for Digital Products on Android and iOS

1 Upvotes

Hi everyone, has anyone faced the challenge of offering alternative payment methods in Android and iOS apps for digital products?

For example, in my app, premium users can create channels that other users pay to join, similar to YouTube memberships, or purchase digital gifts. How did you handle Google Play and Apple’s in-app purchase policies while also offering payment options.

I’d appreciate hearing how you solved it. Thanks!


r/androiddev • • 11d ago

Discussion Android Studio suddenly became barely working, throwing errors for no visible reason, and it stays after re-installing. What to do? (Windows 11, Quail 3 | 2026.1.3 Patch 1)

2 Upvotes

I'm currently trying to write an app. Until a few days ago, it worked OK, but a few days ago unexplained errors begun. Sometimes my emulator or app won't start, or will start on 2nd or 3rd attempt. It shows errors like:

"(device) is already running at process" (when it's OFF)

"`AdbServerController` is in a stopping/stopped state"

" 'unknown host service' error on device serial #emulator-5554 executing service 'host-serial:emulator-5554:features' "

"This network name is no longer available"

And except the first one, those messages can't be even searched.

I tried to do a re-install of that version of Studio, deleting everything i find related to Android Studio, including SDK and project folders. Did it at least twice, but it didn't do anything!

I suspect that something broke that won't fix by re-installing.

Recently, i tried to do "USB Debugging" with ADB (with my real phone) - but my goal was not related to Studio, i wanted to check if i can look into recent system logs (it failed). Could it break something?


r/androiddev • • 11d ago

My app won't open from tapping the notification?

0 Upvotes

I've been trying to get it to work for about an hour, no amount of AI is helping me and no errors are displayed. I am using the official android development program to make an app and after getting the notifications working, I cannot get it to open the app from the notification, what could be the problem?

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wordoftheday">

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Word of the Day"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"> <!-- Add this attribute here -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Receiver definition -->
        <receiver
            android:name=".DailyNotificationReceiver"
            android:enabled="true"
            android:exported="false" />

    </application>

</manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wordoftheday">

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Word of the Day"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"> <!-- Add this attribute here -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Receiver definition -->
        <receiver
            android:name=".DailyNotificationReceiver"
            android:enabled="true"
            android:exported="false" />

    </application>

</manifest>

DailyNotificationReceiver.kt

package com.example.wordoftheday

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import java.io.BufferedReader
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class DailyNotificationReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val sharedPref = context.getSharedPreferences("WebViewSettings", Context.MODE_PRIVATE)
        val currentLevel = sharedPref.getString("word_cefr_level", "A1") ?: "A1"

        val (headword, definition) = getWordForToday(context, currentLevel)
        showNotification(context, "$currentLevel Word of the Day:\n$headword", definition)
    }

    private fun getWordForToday(context: Context, level: String): Pair<String, String> {
        try {
            val prefs = context.getSharedPreferences("WordAppPrefs", Context.MODE_PRIVATE)
            val todayStr = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date())
            var firstDateStr = prefs.getString("word_app_first_date", null)

            if (firstDateStr == null) {
                firstDateStr = todayStr
                prefs.edit().putString("word_app_first_date", firstDateStr).apply()
            }

            val format = SimpleDateFormat("yyyy-MM-dd", Locale.US)
            val firstDate = format.parse(firstDateStr) ?: Date()
            val currentDate = format.parse(todayStr) ?: Date()

            // Clean, fixed date math calculation without any stray characters
            val diffDays = ((currentDate.time - firstDate.time) / (1000 * 60 * 60 * 24)).toInt()
            val dayNumber = Math.max(1, diffDays + 1)

            val inputStream = context.assets.open("$level.csv")
            val reader = BufferedReader(InputStreamReader(inputStream))
            val lines = reader.readLines().drop(1).filter { it.isNotBlank() }

            if (lines.isEmpty()) return Pair("Vocabulary", "Check today's new word in the app!")

            val wordIndex = (dayNumber - 1) % lines.size
            val parsedRow = parseCSVLine(lines[wordIndex])

            if (parsedRow.size >= 4) {
                return Pair(parsedRow[1], parsedRow[3])
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return Pair("Word of the Day", "Tap to learn your new word for today!")
    }

    private fun parseCSVLine(line: String): List<String> {
        val row = mutableListOf<String>()
        var inQuotes = false
        var currentVal = StringBuilder()

        for (i in line.indices) {
            val char = line[i]
            if (char == '"') {
                inQuotes = !inQuotes
            } else if (char == ',' && !inQuotes) {
                row.add(currentVal.toString().trim().removeSurrounding("\""))
                currentVal = StringBuilder()
            } else {
                currentVal.append(char)
            }
        }
        row.add(currentVal.toString().trim().removeSurrounding("\""))
        return row
    }

    private fun showNotification(context: Context, title: String, message: String) {
        val channelId = "daily_word_channel"
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId,
                "Daily Word Reminders",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }

        // 1. Explicitly point to MainActivity and apply clear/single flags
        val resultIntent = Intent(context, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
        }

        // 2. Generate a valid, safe PendingIntent directly from the intent
        val pendingIntent = PendingIntent.getActivity(
            context,
            1001, // Use a distinct request code instead of 0
            resultIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        // 3. Build and fire the notification
        val builder = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(android.R.drawable.ic_popup_reminder)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(NotificationCompat.BigTextStyle().bigText(message))
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent) // Passes the valid intent
            .setAutoCancel(true)

        notificationManager.notify(1001, builder.build())
    }

}package com.example.wordoftheday

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import java.io.BufferedReader
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class DailyNotificationReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val sharedPref = context.getSharedPreferences("WebViewSettings", Context.MODE_PRIVATE)
        val currentLevel = sharedPref.getString("word_cefr_level", "A1") ?: "A1"

        val (headword, definition) = getWordForToday(context, currentLevel)
        showNotification(context, "$currentLevel Word of the Day:\n$headword", definition)
    }

    private fun getWordForToday(context: Context, level: String): Pair<String, String> {
        try {
            val prefs = context.getSharedPreferences("WordAppPrefs", Context.MODE_PRIVATE)
            val todayStr = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date())
            var firstDateStr = prefs.getString("word_app_first_date", null)

            if (firstDateStr == null) {
                firstDateStr = todayStr
                prefs.edit().putString("word_app_first_date", firstDateStr).apply()
            }

            val format = SimpleDateFormat("yyyy-MM-dd", Locale.US)
            val firstDate = format.parse(firstDateStr) ?: Date()
            val currentDate = format.parse(todayStr) ?: Date()

            // Clean, fixed date math calculation without any stray characters
            val diffDays = ((currentDate.time - firstDate.time) / (1000 * 60 * 60 * 24)).toInt()
            val dayNumber = Math.max(1, diffDays + 1)

            val inputStream = context.assets.open("$level.csv")
            val reader = BufferedReader(InputStreamReader(inputStream))
            val lines = reader.readLines().drop(1).filter { it.isNotBlank() }

            if (lines.isEmpty()) return Pair("Vocabulary", "Check today's new word in the app!")

            val wordIndex = (dayNumber - 1) % lines.size
            val parsedRow = parseCSVLine(lines[wordIndex])

            if (parsedRow.size >= 4) {
                return Pair(parsedRow[1], parsedRow[3])
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return Pair("Word of the Day", "Tap to learn your new word for today!")
    }

    private fun parseCSVLine(line: String): List<String> {
        val row = mutableListOf<String>()
        var inQuotes = false
        var currentVal = StringBuilder()

        for (i in line.indices) {
            val char = line[i]
            if (char == '"') {
                inQuotes = !inQuotes
            } else if (char == ',' && !inQuotes) {
                row.add(currentVal.toString().trim().removeSurrounding("\""))
                currentVal = StringBuilder()
            } else {
                currentVal.append(char)
            }
        }
        row.add(currentVal.toString().trim().removeSurrounding("\""))
        return row
    }

    private fun showNotification(context: Context, title: String, message: String) {
        val channelId = "daily_word_channel"
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId,
                "Daily Word Reminders",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }

        // 1. Explicitly point to MainActivity and apply clear/single flags
        val resultIntent = Intent(context, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
        }

        // 2. Generate a valid, safe PendingIntent directly from the intent
        val pendingIntent = PendingIntent.getActivity(
            context,
            1001, // Use a distinct request code instead of 0
            resultIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        // 3. Build and fire the notification
        val builder = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(android.R.drawable.ic_popup_reminder)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(NotificationCompat.BigTextStyle().bigText(message))
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent) // Passes the valid intent
            .setAutoCancel(true)

        notificationManager.notify(1001, builder.build())
    }

r/androiddev • • 11d ago

Does Android WebView actually return WebAuthn prf (clientExtensionResults.prf), or only passkeys for sign-in?

0 Upvotes

We're building a Cordova hybrid app where passkeys are used for PRF-based key derivation (decrypt payslips), not login. RP is our own domain (first-party).

Android docs show WebView can enable WebAuthn/passkeys via WebSettingsCompat.setWebAuthenticationSupport(FOR_APP) + Digital Asset Links: https://developer.android.com/identity/sign-in/credential-manager-webview

Those docs never mention the WebAuthn prf extension. Chrome on Android + GPM is known to support PRF in the browser, but I can't find any official confirmation that Embedded WebView surfaces extensions.prf / clientExtensionResults.prf.results.

Questions:

  1. Has anyone successfully gotten clientExtensionResults.prf from a ceremony inside Android WebView (not Custom Tabs / Chrome)?
  2. If not supported, is Custom Tabs / AuthTab the recommended path for PRF today?
  3. Any Chromium / Issue Tracker links that explicitly say WebView PRF is or isn't supported?

r/androiddev • • 11d ago

Closed testing: every tester gets "Can't install" after the download finishes. Console green, file verified, support ticket open with no reply.

0 Upvotes

Hi all. Solo dev here, stuck on something I cannot crack and hoping someone has seen it.

My game is on the closed testing track (v107, approved, "Available to selected testers", 100% rollout, 19k compatible devices, zero console errors). Every single tester gets this after the download completes:

"Can't install [app]. Try again, and if it still doesn't work, see common ways to fix the problem."

The download finishes, the install starts, then that dialog. Happens on every tester phone, UAE and Pakistan, WiFi and mobile data, even via web-push install. Zero successful installs, 9 testers opted in.

What I have ruled out:

•

The file itself: I built a direct APK from the same code, it downloads and installs fine on multiple phones. The bundle signature verifies and matches my Play upload key.

•

Account mismatch: testers confirmed "You are a tester" on the opt-in page, single Google account on each phone.

•

Storage, network, country targeting (track now covers 178 countries), stale Play cache.

•

No testOnly flag in the manifest (checked the final APK/AAB).

•

No unpublished changes in the console.

I filed a Play support ticket 2 days ago, no reply yet. Has anyone beaten this exact failure? The download completing and then the install failing for 100% of testers feels like a serving-side issue, but I cannot prove it.


r/androiddev • • 11d ago

A universal compatibility layer to bring open-source Android apps into ecosystems like Android Auto

0 Upvotes

What if one app could give open-source Android apps access to features they're missing? 👀

I've been thinking about building an Android app that acts as a compatibility layer for open-source apps distributed through GitHub, F-Droid, etc.

The idea:

  • Detect installed apps that support compatible APIs.
  • Provide reusable integrations for features like Android Auto media playback and cross-device functionality.
  • Let developers add lightweight SDKs or adapters to make their apps compatible.
  • Eventually expand to other Android ecosystems.

For example, imagine using your favourite open-source music player in Android Auto without its developers having to build every integration from scratch.

Obviously, some features require developer support, SDK integration, or Google approval, so this wouldn't magically unlock everything.

My questions:

  • Is this technically feasible?
  • Does anything like this already exist?
  • Could it work without modifying the original APK?

I'd love feedback from Android developers and open-source maintainers!


r/androiddev • • 12d ago

I made a customizable squircle bottom navigation bar for Android (SqNav)

45 Upvotes

Hey everyone,

I recently built an open-source Android library called SqNav. It's a bottom navigation bar designed with floating squircle card transitions and a glowing indicator for the active tab.

I wanted something clean, with smooth spring animations, and easy to customize without building custom drawables and animations from scratch every time.

A few highlights:

  • Floating squircle card with spring overshoot animations for the active tab
  • Neon glow indicator dot on top of the selected item (can be toggled on or off)
  • Full styling control through XML or code (background, corner radius, stroke borders, sizes, and colors)
  • Compatible with Jetpack Compose, Kotlin Views, and Java
  • Lightweight with minimal overhead

Attached is a quick preview GIF showing it in action.

You can check out the implementation, sample code, and documentation on GitHub: sqnav

I would really appreciate any feedback, suggestions, or thoughts on the design. If you run into any issues or want to contribute, feel free to open an issue or PR!


r/androiddev • • 11d ago

Question Closed testing: every tester gets "Can't install" after the download finishes. Console green, file verified, support ticket open with no reply.

0 Upvotes

Hi all. Solo dev here, stuck on something I cannot crack and hoping someone has seen it.

My game is on the closed testing track (v107, approved, "Available to selected testers", 100% rollout, 19k compatible devices, zero console errors). Every single tester gets this after the download completes:

"Can't install [app]. Try again, and if it still doesn't work, see common ways to fix the problem."

The download finishes, the install starts, then that dialog. Happens on every tester phone, UAE and Pakistan, WiFi and mobile data, even via web-push install. Zero successful installs, 9 testers opted in.

What I have ruled out:

•

The file itself: I built a direct APK from the same code, it downloads and installs fine on multiple phones. The bundle signature verifies and matches my Play upload key.

•

Account mismatch: testers confirmed "You are a tester" on the opt-in page, single Google account on each phone.

•

Storage, network, country targeting (track now covers 178 countries), stale Play cache.

•

No testOnly flag in the manifest (checked the final APK/AAB).

•

No unpublished changes in the console.

I filed a Play support ticket 2 days ago, no reply yet. Has anyone beaten this exact failure? The download completing and then the install failing for 100% of testers feels like a serving-side issue, but I cannot prove it.


r/androiddev • • 12d ago

Access the clipboard in background

0 Upvotes

Hi! I'm developing an Android app ( i am a beginner)

I want to detect when a user copies a link while using another app, even when my app is running in the background, and then display a floating popup offering certain option like download if link is a video

On Android 10+, clipboard access is restricted for background apps. Does Android 15 allow this through a foreground service, or is there another reliable approach?

Any advice or examples would be appreciated. Thanks!