DEV Community

loading...
Cover image for Matt's Tidbits #59 - Unexpected new lint failures

Matt's Tidbits #59 - Unexpected new lint failures

mpeng3 profile image Matthew Groves Originally published at Medium ・3 min read

Last week I wrote about an issue you might run into when upgrading the Android Gradle Plugin to 3.6. This time, I have a story about another issue related to that same upgrade.

After resolving the compilation issues from my last tidbit, everything seemed good to go — until we submitted a pull request and our continuous integration server reported some lint errors.

For some reason we were receiving the following error:

Error: TypedArrayUtils can only be called from within the same library group prefix (referenced groupId=androidx.core with prefix androidx from groupId=my-project) [RestrictedApi]

This seemed really odd — we hadn’t changed any code, only the version of the Android Gradle Plugin (and other code that was using WorkManager).

So, I downloaded the Android source code and went on a mission to try to figure out when this API had changed — thinking perhaps it had only recently been restricted. Unfortunately, that ended up being a bit of a wild goose chase — this code had been shuffled around a bunch during the migration to AndroidX, but it looked like that @RestrictTo annotation had been there for at least 2 years… So, that wasn’t it.

Instead, I checked out a version of my project right before the Android Gradle Plugin upgrade (using version 3.5.3), and went and looked at the source for TypedArrayUtils — the annotation was definitely still there. And, just to make sure I wasn’t imagining things, when I ran lint, no error was reported.

The only thing I’m able to conclude is that there must have been some kind of bug in lint that the latest version of the Android Gradle Plugin resolves. The release notes have the following note, which isn’t quite the same thing, but perhaps it’s related?

D8 now respects CLASS retention policy for annotations
When compiling your app, D8 now respects when annotations apply a CLASS retention policy, and those annotations are no longer available at runtime. This behavior also exists when setting the app’s target SDK to API level 23, which previously allowed access to these annotations during runtime when compiling your app using older versions of the Android Gradle plugin and D8.

Google is pretty clear that they hold the right to graylist/blacklist APIs with each new release of Android: https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces

After consulting with the rest of my team, we all came to the conclusion that it was best to try to resolve the underlying issue (and stop using the restricted API), instead of simply ignoring the lint error.

The code that was using this restricted API looked like this:

public class MyListPreference extends ListPreference {
  public MyListPreference(Context context, AttributeSet attrs) {
    this(
      context,
      attrs,
      TypedArrayUtils.getAttr(
        context,
        androidx.preference.R.attr.dialogPreferenceStyle,
        android.R.attr.dialogPreferenceStyle
      )
    );
    setLayoutResource(R.layout.settings_layout);
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

Looking at this more closely, I recognized a pattern I had seen before — from one of my previous Tidbits, in fact! (#56)

While not strictly a View class, this class also follows the typical Android pattern of having 4 constructors with increasing numbers of arguments.

The implementation of the 2-argument constructor for ListPreference looks like this:

public ListPreference(Context context, AttributeSet attrs) {
  this(
    context,
    attrs,
    TypedArrayUtils.getAttr(
      context,
      R.attr.dialogPreferenceStyle,
      android.R.attr.dialogPreferenceStyle
    )
  );
}
Enter fullscreen mode Exit fullscreen mode

If it looks familiar, it’s because it’s exactly what our code was doing! Then I realized the solution — instead of calling our 4-argument constructor, we should be calling the 2-argument version of super() and allowing it to set the default style attribute for us.

Now we no longer rely on a restricted API, and our code is that much better for it! We will not be susceptible to problems if Android decides to change the default style for ListPreferences in the future.

And, this should serve as another reminder — you should really call the appropriate/corresponding constructors instead of supplying default arguments yourself to the 4-argument constructor.

Hopefully you learned something that will help you if you encounter a similar problem! And, please let me know if you encounter other issues after upgrading to the latest version of the Android Gradle Plugin — leave a comment below! And, please follow me on Medium if you’re interested in being notified of future tidbits.

Interested in joining the awesome team here at Intrepid? We’re hiring!

This tidbit was discovered on March 4, 2020.

Discussion

pic
Editor guide