Mark L. Murphy's Blog

April 25, 2026

cw-json 0.2.0

The cw-json repository now has version 0.2.0 of kmp-jsonpointer and kmp-jsonpointer-kxs. The primary change is the addition of URI fragment encoding of a JSON Pointer, based on RFC 6901. Call JsonPointer.fromFragment() to create a JsonPointer given a fragment, and call toFragment() on a JsonPointer to get the fragment encoding for it.

The Dokka documentation has been updated for 0.2.0. I think I have the Dokka versioning plugin set up properly to allow me to host past and current versions of the docs ��� we will find out when I publish 0.3.0. ����

 •  0 comments  •  flag
Share on Twitter
Published on April 25, 2026 10:20

April 22, 2026

22 April 2026 Artifact Wave

Nav3 is on more multiplatform targets:

androidx.navigation:navigation-common-tvosarm64 androidx.navigation:navigation-common-tvossimulatorarm64 androidx.navigation:navigation-common-watchosarm32 androidx.navigation:navigation-common-watchosarm64 androidx.navigation:navigation-common-watchosdevicearm64 androidx.navigation:navigation-common-watchossimulatorarm64 androidx.navigation:navigation-runtime-tvosarm64 androidx.navigation:navigation-runtime-tvossimulatorarm64 androidx.navigation:navigation-runtime-watchosarm32 androidx.navigation:navigation-runtime-watchosarm64 androidx.navigation:navigation-runtime-watchosdevicearm64 androidx.navigation:navigation-runtime-watchossimulatorarm64 androidx.navigation:navigation-testing-tvosarm64 androidx.navigation:navigation-testing-tvossimulatorarm64 androidx.navigation:navigation-testing-watchosarm32 androidx.navigation:navigation-testing-watchosarm64 androidx.navigation:navigation-testing-watchosdevicearm64 androidx.navigation:navigation-testing-watchossimulatorarm64

Also, we got two other new artifacts:

androidx.text:text-vertical-compose androidx.xr.glimmer:glimmer-google-fonts

The roster of nearly 1000 updated artifacts can be found here!

 •  0 comments  •  flag
Share on Twitter
Published on April 22, 2026 14:19

April 15, 2026

#OpenToWork

Alas, my previous employer hit a bumpy patch. As a result, for the first time in a very long while ��� before LinkedIn really existed ��� I am #OpenToWork.

If anyone out there is in need of an Android/Kotlin Multiplatform developer, a serial entrepreneur, or a client-side developer advocate, perhaps I can be of service!

In the meantime, I am back to what I was doing as CommonsWare: working on interesting technologies, writing about them, helping others with them, and seeing where things go. There are a few changes:

My personal preference now is toward Kotlin Multiplatform, rather than pure-play Android projects.

I have long considered myself to be a teacher and a toolsmith. I did little toolsmithing during my main CommonsWare years, but I expect to be doing more of that, and more open source in general, in the future.

Part of that toolsmithing will be in service of using coding agents with local AI models alongside of, or in lieu of, hosted frontier models. I expect that those frontier models will get a lot more expensive, and I have ethical concerns about them. So I want to help developers leverage coding agents, just with less impact on their budgets and on society writ large. Pedal Assist Coding is where I will be doing most of my writing on that.

I hope to get into ATProto and ActivityPub this year and next, as a sneak peek of one of the areas you will see me working on.

But, while I am on those journeys, if your organization could use an extra pair of hands,maybe I can help!

 •  0 comments  •  flag
Share on Twitter
Published on April 15, 2026 11:10

April 13, 2026

Announcing: ���Pedal Assist Coding��� Newsletter

Why have just one newsletter when you can have two? ����

My second newsletter is Pedal Assist Coding. That name is weird enough that I dedicated the second issue to an explanation.

Overall, the newsletter is about coding agents and AI, just not in the ���unabashed fanboi��� mode that you see a lot of. LLMs, especially for coding agents, have tremendous potential. They also have tremendous problems, especially those using frontier models. I am not going to extol the virtues of running dozens of agents in a swarm and ���tokenmaxxing���, but I also am not going to ignore the realities and potential of this technology.

Instead, I am focusing on how to using coding agents (and LLM technology more generally) with an eye towards ethics and developer security (DevSec), with a slight Kotlin Multiplatform bent. For example, today���s post is about the risks of coding agents doing harm to your development environment and one way to try to stop that. Future issues will:

Explain how I am blending a bit of frontier models with local models for a coding agent environment, in the hopes that local models will take on more and more of the work over time

Illustrate the rationale behind some of the Kotlin Multiplatform tooling I am building up in support of that frontier/local blend��� including one I will talk more about here later this week

Demonstrate how to use coding agents for things other than pure coding, such as mutation testing or ���red-teaming���

Highlight uses of LLMs that are not societal risks, but rather help smooth out rough edges in UX or tackle other small problems

If this sounds interesting to you, it is free to subscribe:

Or, add the RSS feed to your favorite feed reader, which does not have to be FeedFlow, though it is my current fave.

You can learn more about the intentions of the newsletter, such as frequency and scope, in my inaugural issue.

I do not know if I will be publishing this newsletter five years from launch, the way I have been for my Jetpack Compose/Compose Multiplatform newsletter. But, for a while, it will be my main vehicle for sharing my discoveries and disasters in small-scale AI and coding agents, with this blog serving more for Android stuff and general CommonsWare news.

 •  0 comments  •  flag
Share on Twitter
Published on April 13, 2026 05:17

April 8, 2026

8 April 2026 Artifact Wave

In terms of totally-new artifacts, androidx.sqlite:sqlite-async and its multiplatform targets are new:

androidx.sqlite:sqlite-async androidx.sqlite:sqlite-async-android androidx.sqlite:sqlite-async-iosarm64 androidx.sqlite:sqlite-async-iossimulatorarm64 androidx.sqlite:sqlite-async-js androidx.sqlite:sqlite-async-jvm androidx.sqlite:sqlite-async-linuxarm64 androidx.sqlite:sqlite-async-linuxx64 androidx.sqlite:sqlite-async-macosarm64 androidx.sqlite:sqlite-async-tvosarm64 androidx.sqlite:sqlite-async-tvossimulatorarm64 androidx.sqlite:sqlite-async-wasm-js androidx.sqlite:sqlite-async-watchosarm32 androidx.sqlite:sqlite-async-watchosarm64 androidx.sqlite:sqlite-async-watchosdevicearm64 androidx.sqlite:sqlite-async-watchossimulatorarm64

The roster of nearly 600 updated artifacts can be found here.

 •  0 comments  •  flag
Share on Twitter
Published on April 08, 2026 13:01

April 7, 2026

Announcing cw-json

A long time ago, I published a bunch of Android libraries. Most have since been retired, and it has been quite some time since I published any new code.

I am starting to do more Kotlin Multiplatform work, and so I have published my first KMP library: cw-json.

This will be a collection of artifacts all dealing with JSON. Right now, two are available, both tied to JSON Pointer:

com.commonsware.json:kmp-jsonpointer is a JSON Pointer implementation for KMP, defining a JsonPointer type with functions to let you manipulate pointers

com.commonsware.json:kmp-jsonpointer-kxs lets you access and mutate JsonObject and JsonArray types from Kotlin Serialization JSON using pointers

Both artifacts are pretty small, but they are the first building blocks in something larger that I have planned.

They are pure Kotlin and are set up to support most major KMP platforms. If you encounter any problems, please raise an issue.

 •  0 comments  •  flag
Share on Twitter
Published on April 07, 2026 05:20

April 1, 2026

1 April 2026 Artifact Wave

It���s not April Fools! Media3 1.10.0 went stable!

Also, we have 1.1.0-beta01 of Navigation Event, including its various multiplatform targets.

Here is what we got overall:

androidx.gradle:gradle-version-catalog:2026.03.01 androidx.gradle:gradle-version-catalog-alpha:2026.03.01 androidx.gradle:gradle-version-catalog-beta:2026.03.01 androidx.media3:media3-cast:1.10.0 androidx.media3:media3-common:1.10.0 androidx.media3:media3-common-ktx:1.10.0 androidx.media3:media3-container:1.10.0 androidx.media3:media3-database:1.10.0 androidx.media3:media3-datasource:1.10.0 androidx.media3:media3-datasource-cronet:1.10.0 androidx.media3:media3-datasource-okhttp:1.10.0 androidx.media3:media3-datasource-rtmp:1.10.0 androidx.media3:media3-decoder:1.10.0 androidx.media3:media3-effect:1.10.0 androidx.media3:media3-effect-lottie:1.10.0 androidx.media3:media3-exoplayer:1.10.0 androidx.media3:media3-exoplayer-dash:1.10.0 androidx.media3:media3-exoplayer-hls:1.10.0 androidx.media3:media3-exoplayer-ima:1.10.0 androidx.media3:media3-exoplayer-midi:1.10.0 androidx.media3:media3-exoplayer-rtsp:1.10.0 androidx.media3:media3-exoplayer-smoothstreaming:1.10.0 androidx.media3:media3-exoplayer-workmanager:1.10.0 androidx.media3:media3-extractor:1.10.0 androidx.media3:media3-inspector:1.10.0 androidx.media3:media3-inspector-frame:1.10.0 androidx.media3:media3-muxer:1.10.0 androidx.media3:media3-session:1.10.0 androidx.media3:media3-test-utils:1.10.0 androidx.media3:media3-test-utils-robolectric:1.10.0 androidx.media3:media3-transformer:1.10.0 androidx.media3:media3-ui:1.10.0 androidx.media3:media3-ui-compose:1.10.0 androidx.media3:media3-ui-compose-material3:1.10.0 androidx.media3:media3-ui-leanback:1.10.0 androidx.navigationevent:navigationevent:1.1.0-beta01 androidx.navigationevent:navigationevent-android:1.1.0-beta01 androidx.navigationevent:navigationevent-compose:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-android:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-desktop:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-iosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-iossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-js:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-linuxarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-linuxx64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-macosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-mingwx64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-tvosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-tvossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-wasm-js:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-watchosarm32:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-watchosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-watchosdevicearm64:1.1.0-beta01 androidx.navigationevent:navigationevent-compose-watchossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-desktop:1.1.0-beta01 androidx.navigationevent:navigationevent-iosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-iossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-js:1.1.0-beta01 androidx.navigationevent:navigationevent-linuxarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-linuxx64:1.1.0-beta01 androidx.navigationevent:navigationevent-macosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-mingwx64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-android:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-iosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-iossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-js:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-jvm:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-linuxarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-linuxx64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-macosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-mingwx64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-tvosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-tvossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-wasm-js:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-watchosarm32:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-watchosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-watchosdevicearm64:1.1.0-beta01 androidx.navigationevent:navigationevent-testing-watchossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-tvosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-tvossimulatorarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-wasm-js:1.1.0-beta01 androidx.navigationevent:navigationevent-watchosarm32:1.1.0-beta01 androidx.navigationevent:navigationevent-watchosarm64:1.1.0-beta01 androidx.navigationevent:navigationevent-watchosdevicearm64:1.1.0-beta01 androidx.navigationevent:navigationevent-watchossimulatorarm64:1.1.0-beta01
 •  0 comments  •  flag
Share on Twitter
Published on April 01, 2026 17:17

March 27, 2026

Random Musings on the Android 17 Beta 3

Well, Android 17 Beta 3 dropped. Ordinarily, we would expect a third beta to be a very minor release, especially since the point of this release is that Android 17 ���officially reached platform stability���. Instead, Beta 3 might be the biggest of the pre-release versions in terms of the amount of change, and we have the least time to cope with that change. I am curious as to who in Google thinks that this approach is a good idea, and why.

Compounding the challenge is that a lot of the changes that I see in the API differences report seem to be undocumented.

So, let���s start in on the random musings���

What Feels Like Double-Speak

They added a new setExactAndAllowWhileIdle() overload on AlarmManager that takes a listener. It is ���ideal for apps that currently rely on continuous wakelocks��� according to the announcement blog post, but it is explained in the same post as ���reducing wakelocks���. It is unclear how continuous wakelocks represent a reduction.

What Feels Like Double-Speak, Part Deux

Android now provides a user setting to hide app names (labels) on the home screen workspace. Ensure your app icon is distinct and recognizable.


Well, our app icon cannot be ���distinct and recognizable��� based on colors, courtesy of mandatory Material You theming. And our app icon cannot be ���distinct and recognizable��� based on outer shape, courtesy of user-configurable launcher icon shapes. Google���s entire point seems to be to make it such that app icons are not ���distinct and recognizable���, and now some users might wind up not even having captions for those indistinguishable icons. ����

What Needs More Documentation

Media projection is the Android SDK���s area for screenshots and screencasts. That seems to have been expanded to cover ���app content projection���, but it is unclear what that is.

There is a new SerialManager for access to serial ports. It is unclear whether this is limited to direct serial ports or if it includes things like USB-to-serial adapters.

There is a new WebAppManager ���that manages the installation and querying of Web Apps��� and serves as ���the entry point for managing Web Apps installed as Android apps���. It is unclear whether this is communicating with the user���s default Web browser or what.

There is a new PccSandboxManager and a lot of other new APIs tied to a Private Compute Core (PCC) sandbox. It is not completely clear what use cases this is intended for and who is allowed to actually employ it.

There is a new VoiceInteractionManager that seems like it is tied to assistant or assistive technologies, but could really use more details.

What Makes It Seems Like Android Desktops Are Coming Soon

A few items showed up in this beta tied to desktop mode, such as:

ActivityManager.AppTask.WINDOWING_LAYER_PINNED, which allows picture-in-picture to support interactive pinned windows (but pay attention to the warnings on the associated permission)

App widgets can now appear on different displays, though this might be more for foldables than it is for desktop mode

What Makes Me Wonder If Spam Is Everywhere

There are now caps on how many keys an app can put in the Android Keystore.

What Seems Blurry

SurfaceView now has getBlurRegions() and setBlurRegions(). Apparently, these let you blur sections of the SurfaceView. Given the nature of SurfaceView, I am not surprised that they needed to add a dedicated API for this ��� with TextureView, you should be able to do your own blurs as needed.However, a bit more documentation on this would be nice.

What Is a Secret, Sometimes

ShowSecretsSetting is how we find out whether ���characters entered into a password, pin or other secret field��� should either be shown or echoed briefly���, with separate values for physical keyboards versus touchscreen keyboards.

What Signals Your Impending Doom

You can now find out when you are nearing your ANR timeout. Your job is to head to the escape pods before your process is terminated.

What���s Going��� Going��� Gone

As part of the ���extensive features and refinements from OpenJDK 21 and OpenJDK 25���, Google got rid of getChars() from String. That had trickle-down effects, with getChars() being removed from SpannedString and SpannableStringBuilder, among other places.

ACTION_TAG_DISCOVERED is deprecated in favor of ACTION_NDEF_DISCOVERED, ACTION_TECH_DISCOVERED, or other approaches for NFC integration.

getInstance() on DnsResolver was removed, replaced by an equivalent constructor.

What Else is Curious

Android finally has a FileManager. However, in this case, it is not an app, but instead is a ���system service manager for handling privileged, long-running file operations���. It would appear that they are trying to give us better options for background disk I/O that do not require WorkManager. See also the requests and results that it appears that you can use.

DocumentsContract defines a CATEGORY_APPROVED_DOCUMENT_HANDLER. You add this to the of ACTION_SEND and/or ACTION_SEND_MULTIPLE activities that are capable of handling document intents. The system might surface your activity in new and exciting places, as the user tries sharing documents.

StrictMode now has policies tied to implicit Uri permission grants. That capability is going away with Android 18. Strangely, this policy seems to be on the recipient of the Uri, even though the bug is in the sender of the Uri for not explicitly granting permission.

getByteArray() and putByteArray() moved from Bundle to BaseBundle. If you are using PersistableBundle, this change might be very useful, if you were using hacks to get around the lack of ByteArray support previously.

Android 17 supports bridged notifications, which is ���a notification sent from another device via a bridging application. The notification is displayed with customized content to differentiate it to the user from a local notification.��� It is unclear what differs ���bridged notifications��� from notifications displayed on a projected device, though.

There is now a way to get an attribution for the source of an app interaction, though it is unclear if this is something that ordinary Android app developers might be able to leverage.

Android 17 has a new framework for supporting sending SMS-style messages over alternative transports, such as RCS or carrier pigeons or whatever.

What Ends the Annual Gaslighting

The version code for Android 17 now officially is 37, not 10000.

 •  0 comments  •  flag
Share on Twitter
Published on March 27, 2026 07:41

March 25, 2026

25 March 2026 Artifact Wave

Room3 Paging got more multiplatform targets:

androidx.room3:room3-paging-js androidx.room3:room3-paging-tvossimulatorarm64 androidx.room3:room3-paging-wasm-js androidx.room3:room3-paging-watchosarm32 androidx.room3:room3-paging-watchosarm64 androidx.room3:room3-paging-watchosdevicearm64 androidx.room3:room3-paging-watchossimulatorarm64

Also, we got a new artifact group, androidx.wear.compose.remote, containing a singleartifact, androidx.wear.compose.remote:remote-material3. It is unclear if this is tied to RemoteCompose, using a wearable as a remote control, or something else.

In addition, we got androidx.xr.runtime:runtime-interfaces as a new artifact.

The roster of 900+ updated artifacts can be found here.

 •  0 comments  •  flag
Share on Twitter
Published on March 25, 2026 13:11

March 18, 2026

18 March 2026 Artifact Wave

This week, we got patch releases and an RC for Media3:

androidx.gradle:gradle-version-catalog:2026.03.00 androidx.gradle:gradle-version-catalog-alpha:2026.03.00 androidx.gradle:gradle-version-catalog-beta:2026.03.00 androidx.media3:media3-cast:1.10.0-rc02 androidx.media3:media3-cast:1.9.3 androidx.media3:media3-common:1.10.0-rc02 androidx.media3:media3-common:1.9.3 androidx.media3:media3-common-ktx:1.10.0-rc02 androidx.media3:media3-common-ktx:1.9.3 androidx.media3:media3-container:1.10.0-rc02 androidx.media3:media3-container:1.9.3 androidx.media3:media3-database:1.10.0-rc02 androidx.media3:media3-database:1.9.3 androidx.media3:media3-datasource:1.10.0-rc02 androidx.media3:media3-datasource:1.9.3 androidx.media3:media3-datasource-cronet:1.10.0-rc02 androidx.media3:media3-datasource-cronet:1.9.3 androidx.media3:media3-datasource-okhttp:1.10.0-rc02 androidx.media3:media3-datasource-okhttp:1.9.3 androidx.media3:media3-datasource-rtmp:1.10.0-rc02 androidx.media3:media3-datasource-rtmp:1.9.3 androidx.media3:media3-decoder:1.10.0-rc02 androidx.media3:media3-decoder:1.9.3 androidx.media3:media3-effect:1.10.0-rc02 androidx.media3:media3-effect:1.9.3 androidx.media3:media3-effect-lottie:1.10.0-rc02 androidx.media3:media3-exoplayer:1.10.0-rc02 androidx.media3:media3-exoplayer:1.9.3 androidx.media3:media3-exoplayer-dash:1.10.0-rc02 androidx.media3:media3-exoplayer-dash:1.9.3 androidx.media3:media3-exoplayer-hls:1.10.0-rc02 androidx.media3:media3-exoplayer-hls:1.9.3 androidx.media3:media3-exoplayer-ima:1.10.0-rc02 androidx.media3:media3-exoplayer-ima:1.9.3 androidx.media3:media3-exoplayer-midi:1.10.0-rc02 androidx.media3:media3-exoplayer-midi:1.9.3 androidx.media3:media3-exoplayer-rtsp:1.10.0-rc02 androidx.media3:media3-exoplayer-rtsp:1.9.3 androidx.media3:media3-exoplayer-smoothstreaming:1.10.0-rc02 androidx.media3:media3-exoplayer-smoothstreaming:1.9.3 androidx.media3:media3-exoplayer-workmanager:1.10.0-rc02 androidx.media3:media3-exoplayer-workmanager:1.9.3 androidx.media3:media3-extractor:1.10.0-rc02 androidx.media3:media3-extractor:1.9.3 androidx.media3:media3-inspector:1.10.0-rc02 androidx.media3:media3-inspector:1.9.3 androidx.media3:media3-inspector-frame:1.10.0-rc02 androidx.media3:media3-muxer:1.10.0-rc02 androidx.media3:media3-muxer:1.9.3 androidx.media3:media3-session:1.10.0-rc02 androidx.media3:media3-session:1.9.3 androidx.media3:media3-test-utils:1.10.0-rc02 androidx.media3:media3-test-utils:1.9.3 androidx.media3:media3-test-utils-robolectric:1.10.0-rc02 androidx.media3:media3-test-utils-robolectric:1.9.3 androidx.media3:media3-transformer:1.10.0-rc02 androidx.media3:media3-transformer:1.9.3 androidx.media3:media3-ui:1.10.0-rc02 androidx.media3:media3-ui:1.9.3 androidx.media3:media3-ui-compose:1.10.0-rc02 androidx.media3:media3-ui-compose:1.9.3 androidx.media3:media3-ui-compose-material3:1.10.0-rc02 androidx.media3:media3-ui-compose-material3:1.9.3 androidx.media3:media3-ui-leanback:1.10.0-rc02 androidx.media3:media3-ui-leanback:1.9.3
 •  0 comments  •  flag
Share on Twitter
Published on March 18, 2026 14:13