TIL: Lorem ipsum text for Compose Previews

When working with Compose, I miss the tools:sample data that’s available in android View XML for rendering some sample data in view previews.

TIL: There’s nothing as extensive, but compose does provide a Lorem Ipsum preview parameter for previewing sample text.

@Preview
@Composable
private fun TextPreview(@PreviewParameter(LoremIpsum::class) text: String) {
    Box(
        modifier = Modifier
            .size(128.dp)
            .background(Color.LightGray)
            .padding(8.dp),
    ) {
        Text(text = text, overflow = TextOverflow.Ellipsis)
    }
}
Screenshot of the output showing a block of text consisting of random lorem ipsum
The output

ADB over Wifi, pre Android 11

Yep, this is doable too. But it requires an initial connection over USB.

  1. Connect the device over USB, with USB debugging enabled
  2. Open a terminal and check the device is connected:
    > adb devices
  3. Ask the device to listen for adb connections on a particular port:
    > adb tcpip 12345 or
    > adb -s DEVICE_ID tcpip 12345
  4. Once the adb has restarted, disconnect the device from USB.
  5. Check the device IP address, and connect to it over wifi:
    > adb connect 192.168.0.2:12345
  6. Ready to develop.
  7. Once done with dev, return the device to USB mode to not let the tcp port open as as security risk:
    > adb usb

It’s a bit more work than the simple settings toggle on Android 11, but works just as well once connected.

Note: The devices need to be on the same wifi network, and not be connected through VPN.

Awesome sauce: wireless adb debugging

tldr: Android 11 has introduced adb debugging over wifi. It is super awesome!

My test device, a Pixel 1, stopped working recently. It shutdown while connected over USB during a test, and then never restarted. Debugging with an emulator on my old (though still much loved) laptop is tiresome. So, I needed an alternative to continue development before I could buy another testing device.

Solution: A different applicationIdSuffix1 for my debug apk so I can install it alongside the production version. When combined with wireless debugging, I’m all set up to continue development on my main device, a Pixel 2 XL.

It’s awesome sauce.

Continue reading

TIL: How to publish an Android library with github+jitpack

Key steps I was missing:

  1. Ensure that the repository root has a settings.gradle file with a line referring to the library:
    include ':customcomponents'
  2. Add apply plugin: 'com.android.library'​ at the top of the library’s build.gradle file.
  3. Add group, version and base name to library’s build.gradle file:
    group = "com.github.adityabhaskar"
    version = android.defaultConfig.versionName
    archivesBaseName = 'customcomponents'
  4. Push to Github. Preferably, give it a version tag.
  5. Open jitpack.io. Connect to Github. Select library
    • If using a free account, the github repository needs to be public/OSS.
  6. Select a commit, or a branch snapshot and click on ‘Get it’. Build process will start in the background. If all goes well, the library will be available to use in projects.

Continue reading

TIL: Automatic date in version name // Android+Gradle

I name my app versions as YYYY.MMDD.Major.Minor.Working. As an example, the current version of an app while I’m working on it may be 2020.0506.1.24.3 while the published version may be 2020.0501.1.23.

I’ve got a good habit of updating the versions section—the Major.Minor.Working bit. But I often forget to update the date bit, specially the DD section. So, after a bit of research (THANK YOU STACKOVERFLOW, FOR EVERYTHING), I got this bit working.

This is all it took:

// build.gradle (app module)

def versionString="0.6.1"

static def getDate() {
    return new Date().format('yyyy.MMdd')
}

android {
    ...
    defaultConfig {
    ...
    versionName "${getDate()}.${versionString}"
    ...

I manually update the versionString when I move to the next version. The build process automatically adds the date to it. Simple, and robust :)

TIL: Retrofit2

Discovering, using and loving Retrofit in PhotoPress.

Got the starter boilerplate code from Retrofit website, and updated a couple of methods for the WordPress.com API. Got it to work, then started expanding the interface with more methods and data classes to flesh it out more.

It’s a delight to work with—simplifies things a lot by taking care of request creation, error handling, and response parsing. It has also helped make the API calls a lot more robust.

I’m already planning to convert AcceleReader for Instapaper to Retrofit as well! It’ll take more work because of the slightly wild-west nature of Instapaper API, but should be doable, and good for the code (and my learning).

Continue reading

Splashing around

I’m interviewing at one of my dream workplaces. To prepare for the first interview, I started looking at their repositories on Github. Since I enjoy learning by doing, I decided to look if they have any easy outstanding issues. They did. They even helpfully marked them as ‘good first issue.’ That’s how I landed up on the task at hand.

A user reported that even when his app was set to dark mode, when opening, it first created an all white flash screen, before opening the activity in dark mode. A team member had suggested that they probably didn’t have the correct background colour resource for dark mode. Seemed like a trivial fix, so I decided to look into it.

After a bit of digging around, it became clear that this wasn’t the cause. The theme and colours had been setup properly. The flash was occurring before the theme was even applied.

They were setting the night mode at the beginning of the activity. The recommendation is to set it in the application class. My guess was that this was causing the issue. But I couldn’t replicate the issue, so I couldn’t really test if this was really the cause. Nonetheless, I made the change and sent in a PR, stating that I didn’t know if this was really the cause.

The team member had a look and reported that the bug was still occurring. He also gave detailed instructions on creating the bug. He may have also suggested that it was a low priority bug not worth spending much time on. But, now that I had a way to reproduce the bug, I had to give it another go.

This time I got the diagnosis correct. The bug occurs not because the theme is not applied. It occurs that when an app is launched, the system always creates a splash window for it. For this splash, the system uses the windowBackground attribute in the app’s default theme. If there are day/night variants, it applies the variant according to current system night mode. Not according to the app’s specified night mode.

This difference between the system and app night mode was what created the unique condition for this issue. It only occurs when the system night mode is different from the app’s night mode. Moreover it never appears when the night mode is set to ‘Follow system’ in the app. Which is why I had been unable to replicate it.

Now that I knew the cause, there were two clear solutions:

  1. Set an attribute in the app theme to hide the splash window:
    <item name="android:windowDisablePreview">true</item>
    This approach is very simple. But it produces a visible delay between the user pressing the app button, and the app window actually appearing.
  2. Create a special splash theme with a background that appears neutral on  both night and dark theme.
    I use this in my Todo.txt app—background in primary colour with the app icon on it. I recommended this approach.

After another round of feedback, I created a new theme for their app with brand colour as background and a clear white logo centered on screen. I set it as the default application theme, and added the actual app theme to the individual activities. Works like a charm.

I’ve updated the code and am ready to send in another PR. Their team is having a discussion on size of the logo—I’d set it at 96dp, the designer wanted to check how 72dp looked. (I now prefer the 72dp logo.) Once that is confirmed, I’ll update the size and send the PR.


Side effects

Working on that introduced me to two changes I needed to make to my apps.

Todo.txt uses a green splash screen that works (mostly) in both dark and light modes. However, I use a special Splash Activity to with this theme. The activity doesn’t have any content. It’s just there to ensure the splash theme is used. It just forwards all launch intents to the Main Activity.

My first intent was to just update the manifest with splash theme as the default application theme, and the actual app theme as default theme for various activities. Sadly, the system is smart. If both the application and the launch activity have a theme, it ignores the application theme and just uses the activity theme. Which means no splash :(

I have now set the Splash theme as the default application theme in the manifest. Next, I created a base ThemedAppCompatActivity from which all my applications extend. All that this activity does is to apply the actual app theme. It uses the old default theme. A child activity can override the themeId variable with another theme’s id to use it. Simples. These changes allowed me to get rid of the SplashActivity. (Code deletion dance! Yay!)

AcceleReader for Instapaper uses night mode specific splash screen. A light or dark background with the pink app icon centered in it. Now that I know the special case of the original issue, I verified that AcceleReader suffers from it as well. Set the app theme to dark and the system theme to light. Open the app. It shows the light mode splash screen before opening the app in dark mode.

I need to change this to a single splash screen irrespective of night mode. Just need to find the right colour. I don’t think a full pink screen will work :)


tldr: System uses system night mode to create splash screen, not the app’s specified night mode. This causes an issue when app and system are in different night modes. To rectify, specify a single splash theme with a neutral windowBackground that works in both day and night mode.

TIL: Webview @JavascriptInterface methods run in a different thread

I was trying to update a LiveData in a ViewModel from a Javascript method within the Webview. The Kotlin method was being called but the LiveData was not being updated. There were no errors either.

This fails silently:

@JavascriptInterface
fun onSelection(selection: String) {
    readerViewModel.setSelectedText(text)
}

After a lot of frustrating tinkering, I got the LiveData to update when I wrapped the update statement within a CoroutineScope.launch  on the Main thread.

This works:

@JavascriptInterface
fun onSelection(selection: String) {
    setSelectedText(selection)
}
...
private fun setSelectedText(text: String) {
    CoroutineScope(Dispatchers.Main).launch {
        readerViewModel.setSelectedText(text)
    }
}

It appears that the @JavascriptInterface methods are executed on a separate non-Main thread. Usually an exception is thrown when a ViewModel is updated from a non-Main thread in Kotlin. Surprisingly (and very confusingly), this exception isn’t thrown when updating the ViewModel from @JavascriptInterface. It just fails silently :/