Mark L. Murphy's Blog, page 12

March 18, 2021

Checking for Poisoned Projects, Again

A bit less than two months ago, I wrote ���Checking for Poisoned Projects���.This outlined how malware embedded in a Visual Studio project ��� not inthe app the project would build, but in the project itself. Designed to infectsecurity researchers, this malware was distributed as a Windows DLL that wouldbe executed through ���build events��� on the researchers��� machines.

Today, we find out that iOS developers were attacked in a similar fashion.Apparently, Xcode offers ���run scripts��� that run as part of the build process.In this case, the run script downloaded spyware and installed it on the developers���machines.

It is merely a matter of time before we find out that Android developers are beingsimilarly attacked.

Please be very very careful when working with projects that you get from theInternet, including from popular sources like GitHub. In���Checking for Poisoned Projects���,I point out some of the standard developer security advice regarding usingsomebody else���s project that I have been giving for years. Basically, be verycareful about the Gradle wrapper, as that is an easy way for an attackerto get malware onto your development machine. There are other attack avenues as well,such as Gradle plugins, compiler plugins, and annotation processors, that we needto worry about.

It would be lovely if somehow Android app development was immune to this sort ofproblem. That is very unrealistic. Someday, I fear that we will get a better pictureof exactly how unrealistic it is.

 •  0 comments  •  flag
Share on Twitter
Published on March 18, 2021 16:43

March 17, 2021

Random Musings on the Android 12 Developer Preview 2

Each time Google releases a follow-on developer preview, I rummage throughthe incremental API differences reportthe release notes,and even the release blog post,to see if there are things that warrant more attention from developers. I try to emphasize things that mainstream developers might use but may notget quite as much attention, because they are buried in the JavaDocs.

Just shy of a month after Developer Preview 1 was released, we got Developer Preview2!

What Amuses Me

Google has gotten into a bit of a habit of soft-releasing certain changes. Theyinclude the changes in the SDK, but do not talk about them in the announcementsand documentation. Then, when the next developer preview comes around, they starttouting the ���new��� stuff��� even when it had been in the SDK already. So, you may wantto start by reviewing my Developer Preview 1 musings,as I mention some things there that only formally got announced today, including:

Hiding application overlay windows

Secure lockscreen notification actions

App digest API

Keeping companion apps awake

And, as a result, these random musings will be a mix of stuff that is ���really real���here in DP2 and a preview of stuff that might get announced in DP3 in a month or so.

What I Apparently Missed For Years

I never noticed the bandwidth estimation APIstucked away in the NetworkCapabilities object. They have been around since Android 5.0;Android 12 is improving them a fair bit, in terms of expected accuracy and relevance.

What May Cause Problems For You

If you use the accelerometer, gyroscope, or magnetic field sensors, you may needto declare a permission to read those at high rates.

What Is Finally Getting Some Love

App widgets ��� which had been a moribund backwater for years ��� are gettingsome updates. It���s almost as if competition matters or something.

But, we canapparently use subclasses of CompoundButton now,including RadioButton and RadioGroup.A bunch of new methods were added for configuring particular elements(e.g., setColorStateList()). We can request specific sizesand control the maximum size for a resize operation.And we can provide a descriptionand a layout to use instead of an image for the preview.I thought app widgets might get replaced someday, but at least for now, Googleis trying to improve what we already have.

What Just Keeps Getting More and More Love

Notifications now have a CallStyle.Despite the description, based on other options,this appears to be designed for VOIP apps or other apps that might raise a notificationrepresenting an incoming call.

What May Make a Splash in DP3

SplashScreenis a thing now.I seem to recall a certain firm decrying the use of splash screens a few years ago ���wonder whatever became of them���

What Makes Me Wish I Knew More About Mobile Carriers

Apparently, 5G networks can be ���sliced���.Mobile carriers can ���virtually divide theirnetworks in portions and use different portions for specific use cases; for example,a corporation can have a deal/agreement with a carrier that all of its employees���devices use data on a slice dedicated for enterprise use.��� I am not well-versed in 5G,but I am still surprised that I had not heard about this capability.

There is a new VcnManagerto be able to ���configure and manage Virtual Carrier Networks���. I am not an expertin mobile networks, but this feels a bit like exposing Google Fi-like ability tocombine multiple networks into a seamless aggregate network.

What May Be Good or May Be Bad

There is a new SCHEDULE_EXACT_ALARM permission,described as ���allows an app to use exact alarm scheduling APIs to perform timing sensitive background work���.I do not know if this means that the exact family of AlarmManager APIs willnow work better (good!) or if this means that you need a permission to be ableto use them even in their current state (less good!).

What Is Here Today, Gone Tomorrow

The SMS_FINANCIAL_TRANSACTIONS permissionis deprecated. And the DP1 BACKGROUND_CAMERA and RECORD_BACKGROUND_AUDIOpermissions were removed outright.

A version of sendStickyBroadcast()was added and deprecated��� both in Android 12 DP2, if the docs are to be believed.

What Is Gone Today, Stumbling Around Like a Zombie Tomorrow

The deprecated AnalogClock widget got new methods.

What Is Still Missing in Action

The app search APIs were revisedbut were not yet announced.

What Else Seems Interesting

Apps can now persist a preferred night mode behavior.

There may be a new option to initialize the native heap with zeros,which, if true, is a nice safety enhancement.

There are now List forms of methods like checkUriPermissions(),for being able to check a list of Uri values at once.

We can now ask a PendingIntent what it is used for,such as isActivity().

There is now a new external storage directory for recordings.

We can control the thumb and track icons used by a Switch,as well as the button icon for a CompoundButton.

We now have solid and patterned ripples.

Apps can control notification channel��� fields?.

There is a new MediaMetricsManager.that does��� something with media metrics.

There are now an official system color palette.

We may be getting APIs for determining the status of individual batteries.It���s unclear if this is for devices with multiple internal batteries or ifthis is for some sort of external battery.

There may be an optionfor enabling hardware-assisted memory tagging.

There may be new options for different types of app installs, such as���bulk���.

We now have headless usersand foreground users.

 •  0 comments  •  flag
Share on Twitter
Published on March 17, 2021 16:48

March 15, 2021

���Elements of Android Room��� Version 0.5 Released

Subscribers now haveaccess to Version 0.5 of Elements of Android Room,in PDF, EPUB, and MOBI/Kindle formats. Just log intoyour Warescription page to download it,or set up an account and subscribe!

This update adds two more chapters, covering:

Executing PRAGMAs as part of starting up Room

SQLCipher for Android management, including backup/restore

In addition:

A bunch of dependencies were updated, notably Room itself

Various bugs were fixed

 •  0 comments  •  flag
Share on Twitter
Published on March 15, 2021 06:31

March 7, 2021

���Elements of Kotlin Coroutines��� Version 0.3 Released

Subscribers now haveaccess to Version 0.3 of Elements of Kotlin Coroutines,in PDF, EPUB, and MOBI/Kindle formats. Just log intoyour Warescription page to download it,or set up an account and subscribe!

This is a small update, with one new chapter on creating custom coroutine scopes.

Also, the material was updated for version 1.4.2 of the coroutines libraries.This includes a substantial revision to the chapter on SharedFlow and StateFlow.Also material on channels has been more firmly placed in a secondary role, comparedto flows��� though channels still have their uses.

And, as usual, there were lots of bug fixes.

This book continues to languish, as it gets the tail end of my writing time. ����

The good news is that I think that I will be able to pick up the pace somewhat,with updates every 3-4 months rather than the��� um��� somewhat longer times forthe past two updates.

If it helps, updates to Elements of Android Room and Elements of Kotlin shouldbe rolling out in the next few weeks.

 •  0 comments  •  flag
Share on Twitter
Published on March 07, 2021 15:23

February 27, 2021

Don���t Put All Your Eggs in One Basket

I am glad that the fight between Google and the developers of Terrariaappears to have been resolved.However, the effects of the ban on Terraria���s primary developer remind me that notall solo developersrealize the potential impacts of distributing apps through the Play Store.

If you are an ordinary person doing ordinary things, it is highly unlikely that Googlewill have a need to ban your Google account. Saying that you use Google for emailand movies and calendars and music and file storage and games and document tools and so onis not completely ridiculous.

Once you decide to distribute your apps through Google, though, that situationchanges. Now you are doing something that Google deems risky, and theirbot-and-cheap-labor vetting process means that you are at an above-average riskof having your account be banned. And due to the opaque nature of their banningprocess, it is not safe to assume that you are being banned for any actual violationof any actual terms of service. In the end, they can ban you for any reason they feel like.

So, if you are going to distribute apps through the Play Store, you owe it to yourself to:

Stop using as many Google services as is practical, and

Aim to isolate your app-distribution Google account(s) from any personal account(s) that you may have

The biggest service by far to get off of is Gmail. Losing access to a movie you boughtthrough Google Play is unfortunate. Losing a chunk of your ability to communicatewith the outside world may have a far greater impact. There areplenty ofotheremail providers out there. Gmail has not been ���head and shoulders���better than the competition in quite some time. I abandoned Gmail many years agoand have not missed a beat. When I get dragged back into Gmail by a client, my reaction toit is decidedly ���meh��� ��� the competition has similar features and capabilities.And the competition is unlikely to ban you because of issues with your app.

Google Drive and Google Docs are the other major areas of risk. Basically, you are givingGoogle an easy way to hold your data hostage. Use other cloud storage providers. Use otherdocument tools, including (gasp!) ones that run on your own hardware.

For whatever remains, you need to recognize that your access to those Google servicescould vanish at any point. That���s not even necessarily tied to your apps. For example,back when I ���drank the Kool-Aid���, I set up commonsware.com as a business accountwith Google. Google apparently has no way to reverse that action. After I discontinuedmy business account, commonsware.com remains incapable of accessing most Google servicesthat have ties to their business services (e.g., Docs, Drive). Life goes on.

One way to help minimize the risk is to keep your personal and ���business���Google accounts separate. Even if you have not set up a business for your app and donot think of yourself in business terms, it is best to treat your interactions withGoogle as if you were running a business. Distribute your apps under a separate Googleaccount. Try to minimize ���mixing business with pleasure��� by using your personal accountfor app-related activity. Ideally, Google���s banhammer will have no idea that yourpersonal account has anything to do with this app that they dislike.

Most solo developers will not run into any problems. However, the semi-random natureof Google���s enforcement actions means that even developers that are sure theyare doing the right thing might encounter problems. Do yourself a favor and tryto minimize the effects of distributing apps through the Play Store��� even ifall you are doing is writing a puppy adoption app.Google does lots of good things, but not everything that Google does is goodfor you.

In other words, Google is not your friend.

 •  0 comments  •  flag
Share on Twitter
Published on February 27, 2021 05:39

February 21, 2021

Random Musings on the Android 12 Developer Preview 1

Each time Google releases a new developer preview, I rummage throughthe API differences reportthe high-level overviews,and even the release blog post,to see if there are things that warrant more attention from developers. I try to emphasize mainstream features that any developermight reasonably use, along with things that may notget quite as much attention, because they are buried in the JavaDocs.

As with the previous four releases, Android 12 seems to be lacking a prominentuser-facing feature. I have no idea what I willtell my mother that she���ll gain if her phone gets the update at some point.Admittedly, Google appears to be sandbagging a bit, holding out some changesfor later releases, so perhaps something compelling to ordinary people will appearlater.

But, as has been common in a similar timeframe, the interesting bits for developersare not covered in the DP1 release notes.

What Will Irritate Developers

In principle, I am a fan of requiring positive declaration of exported components.However, this desperately needs a Lint warning, though hopefully one is forthcoming,perhaps in the current canary release of Android Studio 2020.3.1 Arctic Fox My Goodness This Name Is Long.I am hopeful that the error messagewill improve, though, as tens of thousands of developers next year are going toencounter this change, and approximately zero of those developers will be readingthe documentation. Helen of Troy had ���the face that launched a thousand ships���;this sort of inscrutable error message for an all-but-guaranteed failure is���the error that launched a thousand Stack Overflow questions���.

I had no idea that nested Intentswere much of a thing, making me wonder if this was a technique used by certainlibraries (e.g., ad networks). That, andrequiring mutability flags on PendingIntent,worry me less for apps directly and more for libraries that might not be receivingupdates. Of course, depending on where those libraries were published,the libraries may be gone, anyway.

I foresee a blog post in my future on writing activity trampolines.

Perhaps the one that worries me most is the limit on starting foreground services from the background.In theory, this is fine. In practice, foreground services are already unreliable,with timing-related OS bugs yielding Context.startForegroundService() did not then call Service.startForeground()or similar sorts of errors. My concern is that, just as Google seems unconcerned aboutthose errors, Google will not care about follow-on errors related to timing ofwhen you can and cannot start a foreground service. Hopefully, my fears are unfounded.

Fortunately, all of the preceding changes in this section only take effect once yourtargetSdkVersion hits 31(?) or higher. That means it probably will affect those of usexperimenting with DP1 for a few months, and then the bulk of developers sometime next year.

One change that might take effect more quickly ��� though I have not yet tested it ���is that there are new permissions for using the cameraand using the microphonein the background. These are dangerous permissions, ones that we have to requestat runtime.It is also unclear how future camera and microphone togglesmight behave and how apps will find out about the state changes.

And the new VERSION_CODES value is messed up,as usual.

What Is Neat But Confusing

The unified content API,for accepting media from paste, drag-and-drop, and other sources, is nice. However,it is unclear why this is a new framework API, since the documentation depicts itas being a wrapper around existing APIs with a backport already in AndroidX. Ifthe backport is complete, why did we need a framework API? And if we needed a frameworkAPI, what is the gap between what Android 12 offers and what the backport offers?

PackageManager has gained some interesting, if under-documented, features:

You can request checksums of installed apps.

There is a new form of ���property��� that you can declare ona componentor elsewhere in the manifest. It is unclear how this relates to the long-standing<meta-data> option in the manifest.

A package can have attributionsin the <manifest>, defined in <attribution> elements.It is unclear if this ties into data access auditing,though, or what role these ���attributions��� otherwise play.

What Is Subtly Nice

The postponed foreground service notificationsfeature should help with user distraction. Often, we need a foreground service becausewe cannot be certain that a background service will complete in time��� but ifthe work is completed quickly, we hassle the users with a short-lived notification.This change should help eliminate that.

Apps have improved options for blocking touch input passed through other windows,including a permission to be able to enable such a blockand a window option to implement the block.Frankly, this is long overdue, as is banning apps from closing system dialogs.

Since the beginning, we have built up some heuristics for which types of Contextare safe for UI operations and which ones are not. Finally, Google is formalizingthe concept, with a dedicated API to tell you if this Context is OK for UI work.There is a corresponding option in StrictModeto warn you about incorrect Context usage.

PowerManager can now give us real-world estimates of remaining battery life,which might be useful for some apps to better scale back work in low-battery states.

And, as Romain Guy tweeted about,we have a new API to apply a RenderEffect to a View,which should give us an easy blur option.

What Needs Third-Party Love

ImageDecoder now supports decoding the full animations of GIF and WebP images.It will be interesting if image-loading libraries start adopting it on Android 12and newer devices ��� my guess is that they will only if if provides obviousbenefits over their existing code for handling these animations.

What���s Dead (Or Seriously Morphed)

At least in DP1, there are relatively few massive deprecations, like the deprecationof AsyncTask in Android 10.

However:

LocationManageris significantly changing its API for obtaining locations

Obtaining the WiFi connection infoor IP address has moved to newlocations in the SDK

DevicePolicyManager is overhauling its passphrase quality API,resulting in a bunch of deprecations

You can no longer use GET_INTENT_FILTERSwhen querying the PackageManager

If you were using FLAG_BLUR_BEHIND or TYPE_STATUS_BAR_PANEL on WindowManger.LayoutParams,those values have been removed from the SDK entirely

What Is the Human Resources Department Doing In My Developer Preview?

There is a new PeopleManagersystem service. Google added a lightweight concept of ���conversations��� to the NotificationAPI over the past few releases. This appears to try extend that further.

This might tie into the conversation app widgets described in some Android 12 document leaks.There also is a new way to tie a NotificationChannel to conversations.

What Is the Insect Resources Department Doing In My Developer Preview?

There is a BugreportManagerin Android 12, though it is unclear exactly how useful it will turn out to be.

What Makes Me Go ���Hmmmmm���

And now, we get to a list of other things that caught my eye in the APIdifferences report that did not get included in Google���s DP1 overview:

There is a new AppSearchManagerthat appears to be an on-device search engine. It will be interesting if thisgets covered more in future developer previews.

The fused location provider has appeared in the SDK for the first time.It will be interesting to see if this means that you can start using this onnon-Play devices.

We now have a new facet of a Configuration: fontWeightAdjustment.I do not see an option for this in the Settings app. It also remains to be seenif this triggers a new type of configuration change.

We can now control whether we get click events for a disabled View.

It appears as though an <intent-filter> can now filter Uri values basedon a suffixand some sort of ���advanced pattern���.It is unclear what is so advanced about that pattern, though.

There are two new Notification categories. CATEGORY_WORKOUTsuggests that Google is going to have more explicit support for fitness-relatedapps, perhaps stemming from their acquisition of Fitbit. And I do not know whatCATEGORY_LOCATION_SHARINGmeans, such as ���sharing with who?���.

If you played with Android 10���s device controls, there is new control type: the thumbnail.I am uncertain what the use case is, though security cameras might be one.

There is a new requireDeviceScreenOnattribute on��� something. It is described as ���Whether the device must be screen on before routing data to this service. The default is true.���.That default seems odd; otherwise, I would have thought that perhaps this attributegoes on <service> in the manifest. It is possible that this ties into a new option to require unlocking the device before processing a notification action.

There is a new AppUriAuthenticationPolicy,though it is unclear how it will be used.

We can have more sophisticated haptics, with multiple blended vibration patterns.Alas, the name of the class for thiswill spawn yet another round of off-color jokes.

What Happens Now?

While I do plan on writing an Elements of Android S along the lines of itsQ and Rpredecessors, I plan on waiting to release something. I waste too much timechasing changes that eventually themselves change or outright vanish.So, my current plan is to wait to ship a Version 0.1 of the book until thelast developer preview or first beta release. If you feel that this is a mistake,and I should publish something more rapidly,let me know!.

 •  0 comments  •  flag
Share on Twitter
Published on February 21, 2021 06:26

February 20, 2021

Using Repository Artifact Safelists in Gradle

With JCenter going away,we are going to be peeking more at our repositories and artifacts. After all, we need to makesure that we will continue to get the libraries that we need from their newhomes, for any that were published purely to JCenter.

The timing is interesting, as ���supply-chain��� attacksare on the rise. It is far too easy for somebody topublish a malware-laden libraryand have it be picked up automatically by developers. This can even affectprivate artifacts in private repositories.

Ideally, while we are cleaning up our Gradle scripts, we would lock down wherewe get our artifacts from. The good news is that modern versions of Gradlegive us somewhat better options for this. The bad news is that implementing thoseoptions is rather painful.

The problem with the default way that we declare dependencies in an Androidproject is that we do not say where each dependency comes from. Gradle largelydisassociates artifacts (e.g., all those implementation lines) from repositories.We do not say ���get this artifact from this repository���. We just list the supportedrepositories and desired artifacts, and Gradle fulfills our requests on its own.

And, by default, all Gradle does is use a top-down search against each repository.In other words, it uses this algorithm:

For each artifact For each repository in the order they are listed If the repository offers this artifact, download it EndEnd

There is little stopping an artifact from being offered in more than onerepository, which is at the root of some of these supply-chain attacks. Dependingon the order of the repositories in your Gradle script, you might get differentactual artifacts than another project requesting the same artifacts but usinga different repository order.

Ideally, we would say ���get this artifact from this repository���. We can do that,to an extent.

Starting with Gradle 5.1, we can safelist what artifacts we get from a givenrepository. To do this, we add a content {} closure to the repository declaration,and in there use include...() functions to stipulate what artifacts to obtainfrom that repository:

jcenter { content { includeModule("org.jetbrains.trove4j", "trove4j") }}

Here, we are saying that the only thing that we want to obtain from JCenteris org.jetbrains.trove4j:trove4j. JCenter will not be used for other artifacts.

The three main safelist functions are:

includeModule(), where you provide the artifact group (org.jetbrains.trove4j) and artifact ID (trove4j)

includeGroup(), to support any artifact from a specified artifact group

includeGroupByRegex(), which allows you to specify a regular expression and supportany artifact group that matches that expression (e.g., includeGroupByRegex("org\\.jetbrains\\..*"))

If all of your repository declarations include one or more include...() functions,then the build should work purely off of those safelists:

The artifacts that you are using will obtained from their associated repositories and nowhere else

No artifacts that are not on the safelist will be used in your build

See this blog post for a bit more on the options.

The problem is that the safelists not only need to handle your direct dependencies,but also all of the transitive dependencies.

That can get rather lengthy.

This sample project is based onthe tutorial project that we build in Exploring Android.The project requests 33 artifacts for the module, plus three classpath entriesfor Gradle plugins.

After adding all of the necessary include...() functions,the top-level build.gradle fileis over 150 lines long, mostly involving those functions. And that is with cheatingand using includeGroup() and includeGroupByRegex(), both of which are a bitless secure than includeModule().

Basically, what happens is that you add include...() calls for all of yourdirect dependencies, then try doing a build. In particular, adding --refresh-dependenciesto a command-line build (e.g., gradle --refresh-dependencies app:assembleDebug)will confirm that Gradle can download all of your dependencies. You will wind upwith a bunch of errors:

* What went wrong:A problem occurred configuring root project 'GradleSafelist'.> Could not resolve all artifacts for configuration ':classpath'. > Could not resolve org.glassfish.jaxb:jaxb-runtime:2.3.1. Required by: project : > com.android.tools.build:gradle:4.1.2 > androidx.databinding:databinding-compiler-common:4.1.2 project : > com.android.tools.build:gradle:4.1.2 > com.android.tools.build:builder:4.1.2 > com.android.tools:sdklib:27.1.2 > com.android.tools:repository:27.1.2 > Could not resolve org.glassfish.jaxb:jaxb-runtime:2.3.1. > Could not parse POM https://repo.maven.apache.org/maven2/... > Could not resolve com.sun.xml.bind.mvn:jaxb-runtime-parent:2.3.1. > Could not resolve com.sun.xml.bind.mvn:jaxb-runtime-parent:2.3.1. > Could not parse POM https://repo.maven.apache.org/maven2/... > Could not resolve com.sun.xml.bind.mvn:jaxb-parent:2.3.1. > Could not resolve com.sun.xml.bind.mvn:jaxb-parent:2.3.1. > Could not parse POM https://repo.maven.apache.org/maven2/... > Could not find com.sun.xml.bind:jaxb-bom-ext:2.3.1. > Could not resolve com.google.auto.value:auto-value-annotations:1.6.2. Required by: project : > com.android.tools.build:gradle:4.1.2 > com.android.tools.build:bundletool:0.14.0 > Could not resolve com.google.auto.value:auto-value-annotations:1.6.2. > Could not parse POM https://repo.maven.apache.org/maven2/... > Could not resolve com.google.auto.value:auto-value-parent:1.6.2. > Could not resolve com.google.auto.value:auto-value-parent:1.6.2. > Could not parse POM https://repo.maven.apache.org/maven2/... > Could not find com.google.auto:auto-parent:6.

The end leaf of each branch shows a transitive dependency that is not covered by yourinclude...() functions ��� in this case, com.sun.xml.bind:jaxb-bom-ext:2.3.1 andcom.google.auto:auto-parent:6. After adding those, you run the test again and get a bunchof fresh errors from the transitive dependencies of the transitive dependencies.And, as the shampoo instructions state, lather, rinse, repeat,until eventually you get no more errors.

This process sucked��� and this is not a big project.With luck, we can create some tooling to help make generating these safelists easier.

But, this is a more secure build than what it started with.The more important your project, the more likely it is that you are going to wantto explore options like this for ensuring that your artifacts come from whereyou expect them to.

 •  0 comments  •  flag
Share on Twitter
Published on February 20, 2021 16:37

February 14, 2021

Notes on the Jetpack Compose alpha11 to alpha12 Upgrade Process

Upgrading an app from Compose alpha11 to alpha12 was more troublesome thannormal. I took some notes along the way and wanted to pass them along.

Note: all of the Gradle samples show the classic Groovy approach ��� you willneed to tweak those for build.gradle.kts if you are going that route.

The obvious change is moving your Compose Gradle plugin and all of theCompose runtime dependencies to 1.0.0-alpha12, along with your kotlinCompilerExtensionVersionin composeOptions. If you have been working with Compose for a while, this isa standard change, and hopefully you have consolidated all of those versionreferences into a single constant.

Compose alpha12 also requires Kotlin 1.4.30, for its Gradle plugin and forits runtime dependencies. With luck, you have a single constantfor that as well:

buildscript { ext { kotlinVersion = "1.4.30" composeVersion = '1.0.0-alpha12' } ...}

The release notesalso show having this Gradle snippet outside of your android {}closure in your modules:

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions { jvmTarget = "1.8" freeCompilerArgs += ["-Xallow-jvm-ir-dependencies"] }}

After doing those things, I then ran into a bunch of IDE errors akin to the following:

���padding(Dp): Modifier��� is only available since Kotlin 1.4.30 and cannot be used in Kotlin 1.4


At first, I tried upgrading to ���Android Studio Arctic Fox | 2020.3.1 Canary 6���(hereafter referred to as ���Canary 6��� for simplicity). That did not clear up the problem.

The solution is to upgrade the Kotlin plugin in the IDE to support 1.4.30. Unfortunately,this is not yet stable. So, you need to:

Open the Settings dialog in Canary 6 Go into ���Languages & Frameworks��� > Kotlin Switch your ���Update channel��� to ���Early Access Preview 1.4.x��� Choose to upgrade your Kotlin plugin to 203-1.4.30-RC-AS6682.9 (or newer, depending on when you are reading this) Restart Android Studio afterwards

This appears to be undocumented, unless you countKotlinlang Slack messages from Google developersas documentation.

You should also check all your third-party dependencies and make sure that you havetheir latest versions, as otherwise you may fail when you build the module.In my case, I needed to upgrade dev.chrisbanes.accompanist:accompanist-coilto 0.5.1.

That got me to the point where things would run, but you are likely to encountera bunch of deprecations.

The one that will affect most of you is thatsetContent() on Activity will show up as deprecated. That is because it movedout of a mainline Compose dependency. You will need to add:

implementation "androidx.activity:activity-compose:1.3.0-alpha02"

to your module���s list of dependencies. Note the alpha02 ��� while alpha01was released this past week, alpha02 shipped hours later to fix a significant bug.

Once you have that dependency in place, you can replace:

import androidx.compose.ui.platform.setContent

with:

import androidx.activity.compose.setContent

If you happen to be using the Jetpack ViewModel in your Compose UI code, you may runinto a similar deprecation notice on viewModel(). That is another case where theextension function moved from a mainline Compose dependency to another one.You will need to add:

implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha01"

to your module���s dependencies. Then, you can change:

import androidx.compose.ui.viewinterop.viewModel

to:

import androidx.lifecycle.viewmodel.compose.viewModel

There is a ���long tail��� of other deprecations that you might encounter. In mysamples, one was that imageResource() is deprecated. The replacements,though, will vary by circumstance:

If you need a Bitmap, you will wind up changing imageResource(R.drawable.whatever)to imageFromResource(LocalContext.current.resources, R.drawable.whatever)

Otherwise, painterResource(R.drawable.whatever) will probably suffice

This upgrade process was more involved than usual, exacerbated by gaps indocumentation. I will be honest: this worries me, with a possible move to ���beta���versions coming in the next couple of weeks.

 •  0 comments  •  flag
Share on Twitter
Published on February 14, 2021 06:35

February 11, 2021

Quieting the SQL Syntax Warnings

val db: SQLiteDatabase = TODO("open a database")val st = db.compileStatement("ATTACH DATABASE ? AS plaintext KEY ''")

By default, Android Studio does not like this SQL statement. It puts ared undersquiggle below KEY, complaining that it is expecting a ; instead.

According to SQLite, Android Studio is correct.

This error is coming from a SQL ���language injection���. Rebecca Franks wrotea great blog postabout language injections a few weeks ago. There is a ���SQLiteDatabase methods���language injection set up in my Android Studio 4.1.2 installation, and I assume thatit shipped with Studio itself.

However, in my case, I���m right, and Android Studio is wrong.

That is becausein this code I am not using plain SQLite ��� I am using SQLCipher for Android.SQLCipher for Android has an extended form of ATTACH DATABASE that takes a KEYoption to supply a passphrase (shown here as the empty string '').

It is unclear why a language injection for android.database.sqlite.SQLiteDatabaseis affecting calls to net.sqlcipher.database.SQLiteDatabase. Perhaps it is becausenet.sqlcipher.database.SQLiteDatabase implements androidx.sqlite.db.SupportSQLiteDatabase, the SQLite indirection API that allows you to use things like SQLCipher for Androidwith Room and SQLDelight. Or maybe this is a limitation of the scoping rules forlanguage injections, and anything named SQLiteDatabase will be affected.

Regardless, the red undersquiggle was annoying me.

I could disable that language injection, but then I lose syntax highlighting andvalidation everywhere else. Instead, I want to be able to mark certain statementsas being correct and suppress the warning, akin to how @SuppressLint() works.However, this is not a Lint check, so @SuppressLint itself does not help here.

Rebecca���s post gave me an idea, though, which turns out to work, in a couple of different ways.

In her post, she shows that you can use a //language= comment to cause a particularlanguage injection to be applied in a spot it might not normally be applied.So, while this would result in no errors:

private const val ATTACH_THIS = "ATTACH DATABASE ? AS plaintext KEY ''"

���this would complain about KEY:

//language=sqlprivate const val ATTACH_THIS = "ATTACH DATABASE ? AS plaintext KEY ''"

In the first snippet, the IDE has no idea that this string is a SQL statement andso does not apply any language injections. In the second, we teach it that thisstatement contains SQL, so the IDE applies the appropriate language injection.

So, one workaround is to pull the offending SQL out of the SQLiteDatabase calls:

val db: SQLiteDatabase = TODO("open a database")val st = db.compileStatement(ATTACH_THIS)

If we skip the //language=sql comment on the ATTACH_THIS declaration, thenwe will not get any complaints about KEY.

Another workaround is to override the language injection at the call site:

val db: SQLiteDatabase = TODO("open a database")//language=textval st = db.compileStatement("ATTACH DATABASE ? AS plaintext KEY ''")

Here, we tell the IDE ���Treat this as plain text. Yes, yes, I know, it looks likeit should be SQL. And, yeah, I do not really know if you know what ���plain text��� is.Just skip any syntax validation on the string, please.���

(fortunately, the comment is shorter)

At least for now, these workarounds give you fine-grained ability to suppress SQL syntax warnings,in cases where Android Studio���s SQL parser either has bugs or is confused by extendedSQL syntax.

 •  0 comments  •  flag
Share on Twitter
Published on February 11, 2021 05:16

February 8, 2021

Data Over Sound

Bootstrapping communications between two devices can be a challenge. While yourlong-term communications might be over WiFi, for example, you may have an initialstep of getting a device onto that WiFi network. This is reasonably common in IoTscenarios, where you have some device that has limited input options and you needto teach it a WiFi network SSID and passphrase, so it can try to connect.

There are many options for that bootstrapping process, though they all have theirhardware requriements:

Bluetooth or BLE NFC QR code scanned via a camera And so on

A lesser-used technique ��� at least in terms of obvious usage ��� is ���data over sound���.One device plays an audio clip that contains embedded data, and the other devicereceives it via a microphone and decodes it. Google Nearby uses this, in the formof near ultrasound, as one of its communications paths.

Google Nearby is nice but is closed source as part of Play Services. Google offersvery limited cross-platform support, and the system is fairly tightly tied to theGoogle Play ecosystem. This makes it impractical for many IoT scenarios, and italso limits the auditabilty of the code (from a privacy standpoint).

There have been various attempts at addressing this over the years. I had contemplatedcreating one (code name: chirpr) years ago and never found the time.

Georgi Gerganov is taking another stab at it, with an interesting approach. Hisfocus is purely on converting data to and from raw PCM audio clips, leaving it upto individual platforms to handle the actual audio I/O. For the data-to-sound conversions, hehas an MIT-licensed C/C++/WASM library thatallows for use on just about every platform imaginable. Right now, he has demosfor Android, iOS, and macOS/Linux/Windows desktops, in addition to the browser.He also has CLIs and a Web service for the raw sound clip conversions. Basically,he has proven that his code can run pretty much anywhere.

His Android and iOS demos though are just that: demos. What the project lacksis an Android library and iOS framework/Cocoapod for adding his data-over-soundcode to an app. I took a shot at it, but while I am pretty decent at Android overall,I am not strong with the NDK or with lower-level audio APIs. The Android librarywould need both of those in time, and so I am ill-suited to create the library,though I could help test and perhaps maintain it.

With luck, somebody else stronger in those areas will have a similar itch to scratchand will take the lead on creating a proper Android library for this project.

 •  0 comments  •  flag
Share on Twitter
Published on February 08, 2021 04:48