Tag: android programming

READ_CONTACTS Permission Before and After Marshmallow

The READ_CONTACTS permission is required if you look up a contact (using the code below) on a pre-Marshmallow device (API 23). But, on Marshmallow or above, you don’t seem to need READ_CONTACTS even though READ_CONTACTS is a dangerous permission.

I don’t see why these two cases should be different.

In particular, if you launch the user’s contacts app with this:

val intent = Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
startActivityForResult(intent, RC_CONTACT_LOOKUP)

and then read the contact’s phone number with this in onActivityResult:

RC_CONTACT_LOOKUP -> if (resultCode == RESULT_OK) {
    lateinit var cursor: Cursor
    if (data != null) {
        try {
            cursor =  applicationContext.contentResolver.query(data.data,
                    null, null, null, null)
            cursor.moveToFirst()
            val column = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
            val phoneNumber = cursor.getString(column)
            contactButton.text = phoneNumber
            errorTextView.text = ""
        } catch (exception: Exception) {
            Log.e(tag, "Could not query column db", exception)
        } finally {
            cursor.close()
        }
    }
}

it won’t work in the pre-Marshmallow case unless you’ve required the READ_CONTACTS permission in the manifest. But, for the Marshmallow case, you don’t need to request it (which you would do, of course, at runtime on an as-needed basis because it’s Marshmallow).

Comment

And the Winner for Best Screenplay in an Android Bug Report is …

“People are implementing IPv6 only networks with DHCPv6. Please implement RFC 3315.” by someone named Tyler.

Comment

TextUtils.isDigitsOnly Returns True if Given an Empty String

I happened across this problem while using the Android SDK’s TextUtils.isDigitsOnly() method recently.

This is the body of that method from the API 27 source:

    public static boolean isDigitsOnly(CharSequence str) {
        final int len = str.length();
        for (int cp, i = 0; i < len; i += Character.charCount(cp)) {
            cp = Character.codePointAt(str, i);
            if (!Character.isDigit(cp)) {
                return false;
            }
        }
        return true;
    }

Someone filed a bug report against it in January 2012. It seems no progress toward a fix has been made.

The app I’m coding is in Kotlin, and my first thought was to try to create my own local fix by creating my own local TextUtils.isDigitsOnly implementation in an extension function.

But this is not (yet) possible for a static method whose original definition is in a Java class (as opposed to a Kotlin class). Someone has filed a feature request to make it possible though. (It seems like a sensible request to me because there’s an asymmetry between Kotlin and Java with respect to extension functions: with Kotlin-defined classes you can reimplement both instance and companion object methods, but with Java-defined classes you can only reimplement instance methods.)

Anyway, in the mean time I replaced this expression:

TextUtils.isDigitsOnly(myString)

with this expression:

!TextUtils.isEmpty(myString) && TextUtils.isDigitsOnly(myString)
Comment

Android Studio 3.0 Released. Woo Hoo.

Took me 4 days to realize it, but they have officially released a stable version of Android Studio 3. Woo hoo.

I’m officially looking forward to the stable release of Android Studio 3.1 now.

Comment

Problems with the new GPS Automatic License Notice Generator

Following up on my previous post, here’s a screenshot of the OSS license item for the popular Glide library as generated by version 11.2.2 of the new GPS OSS tools. There are two distinct OSS licenses for the Glide library and the GPS OSS tools finds both of them. But it concatenates the two URLs without a space or line break in between. They’re just stuck together:

To fix that, I added a gradle hack which runs after the app’s preBuild gradle task. The code block, placed at the bottom of build.gradle, carries out a specific edit within third_party_licenses (a text file generated by the OSS gradle plugin):

preBuild.doLast({
    String thirdPartyLicenseFilePath = 'app/src/main/res/raw/third_party_licenses'
    File thirdPartyLicenses = new File(thirdPartyLicenseFilePath)
    if (thirdPartyLicenses.exists()) {
        String contents = thirdPartyLicenses.getText('UTF-8')
        contents = contents.replace("licensehttp://", "license http://")
        thirdPartyLicenses.setText(contents, 'UTF-8')
    } else {
        println "cannot find " + thirdPartyLicenseFilePath
    }
})

Sure enough, the hack adds a space between the two urls:

But there’s a new problem: the ‘t’ at the very end of the second url is no longer present. (Look closely. The url points to a ‘.tx’ file instead of a ‘.txt’ file).

On one of my android devices, it appears that there’s a 92 character length limit on that string. Or something. I have yet to discover where that limit is set.

Comment

Quick Notes On Dockter’s 2015 BABBQ Talk on the Android Gradle Build System

Hans Dockter gave a talk about the Android Gradle build system at Big Android BBQ 2015(No bbq for me … saw it on youtube … woo hoo) 

Dockter addresses the issue of Android build performance in the last half of the talk. A few of my takeaways, for what they’re worth:

  • Android developers should try an upgrade to Gradle 2.8
  • Build times are slow mostly because of dexing and pre-dexing. There’s nothing Gradle can do to improve dexing time, per se.
  • Right now, a clean build deletes your pre-dexed libraries. So, they must be re pre-dexed each time. But, in the future, there will be an optimization where pre-dexed versions of libraries necessary to your project are cached resiliently. So, even if you clean your project, their dexed versions persist.
  • Future improvements in the Android toolchain or Gradle for Android will include incremental dexing and concurrent dexing.

Dockter also mentioned the possibility of caching pre-dexed libraries on a CI Server so they’d be available to all developers in the organization. (Or something like that.)

I wonder if teams that use a third party, CI server in the cloud will also be able to take advantage of this sort of optimization. 

Comment

Why I Try Not to Implement Parcelable

The short answer is: Parcelable implementations are overly complicated and brittle,  I’m bad at finding and fixing “Unmarshalling unknown type code” errors and I’m tired of being surprised by them.

There are hundreds of questions about Parcelable errors on StackOverflow. I’ve had my fill of trying to implement solutions (e.g. proguard configuration adjustments, read/write out of order, etc) and then hoping that the errors stop happening.

If my app runs in a single process and I want to pass some arbitrary custom object to an Activity or Fragment, I’ll create a singleton and store the object as a property on that singleton. Then my Activity or Fragment can get that custom object by calling a “get” method on the singleton. (Of course, it’s important to keep that singleton from holding on to excessive amounts of memory.)

Anyway, the official documentation apparently says we should avoid using Parcelable unless we have to pass an object instance to another process.

And, even in that case, there are questions about the performance gains attributed to Parcelable as compared to Serializable. 

 

Comment

Saving State in a Compound Control

If you’re writing an android compound control and you want to save state between config changes, you may want to tell the Android SDK to butt out.

That is, you may want your compound control to be fully in charge of saving and restoring the states of its internal views.

Why would you want to do that – why not just let the Android SDK save and restore those interior view states?

Because in order to correctly save the states of those interior views, the Android SDK needs each of them to have unique ids.

And when does that become problematic?

When a client of your compound control puts multiple instances of it into a single one of their layouts. In this case, the interior views will all get the same ids or no ids at all. (Unless you want to deal with a certain amount of awkwardness in code.)

So, if, for example, your compound control consists of a LinearLayout which wraps some other stock views, it can be desirable for your LinearLayout to tell Android to simply avoid saving the states of those interior views. You can do this by calling dispatchFreezeSelfOnly and dispatchThawSelfOnly.

A helpful example of this is Charles Harley’s Lock Combination Picker on GitHub.

A discussion about how BaseSavedState should be used to save the state of your compound view is found in this StackOverflow question.

Comment