blob: 9f0cd3a76e8799000bebab403ca676860b86a6e1 [file] [log] [blame] [view]
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001# Library API guidelines
2
3[TOC]
4
5## Introduction {#introduction}
6
7s.android.com/api-guidelines,
8which covers standard and practices for designing platform APIs.
9
10All platform API design guidelines also apply to Jetpack libraries, with any
11additional guidelines or exceptions noted in this document. Jetpack libraries
12also follow
13[explicit API mode](https://kotlinlang.org/docs/reference/whatsnew14.html#explicit-api-mode-for-library-authors)
14for Kotlin libraries.
15
16## Modules {#module}
17
18### Packaging and naming {#module-naming}
19
20Java packages within Jetpack follow the format `androidx.<feature-name>`. All
21classes within a feature's artifact must reside within this package, and may
22further subdivide into `androidx.<feature-name>.<layer>` using standard Android
23layers (app, widget, etc.) or layers specific to the feature.
24
25Maven artifacts use the groupId format `androidx.<feature-name>` and artifactId
26format `<feature-name>` to match the Java package.
27
28Sub-features that can be separated into their own artifact should use the
29following formats:
30
31Java package: `androidx.<feature-name>.<sub-feature>.<layer>`
32
33Maven groupId: `androidx.<feature-name>`
34
35Maven artifactId: `<feature-name>-<sub-feature>`
36
37#### Common sub-feature names {#module-naming-subfeature}
38
39* `-testing` for an artifact intended to be used while testing usages of your
40 library, e.g. `androidx.room:room-testing`
41* `-core` for a low-level artifact that *may* contain public APIs but is
42 primarily intended for use by other libraries in the group
43* `-ktx` for an Kotlin artifact that exposes idiomatic Kotlin APIs as an
AndroidX Core Team0db91f02021-05-06 22:45:18 +000044 extension to a Java-only library (see
45 [additional -ktx guidance](#module-ktx))
AndroidX Core Team2e416b22020-12-03 22:58:07 +000046* `-<third-party>` for an artifact that integrates an optional third-party API
47 surface, e.g. `-proto` or `-rxjava2`. Note that a major version is included
48 in the sub-feature name for third-party API surfaces where the major version
49 indicates binary compatibility (only needed for post-1.x).
50
51Artifacts **should not** use `-impl` or `-base` to indicate that a library is an
52implementation detail shared within the group. Instead, use `-core`.
53
54#### Splitting existing modules
55
56Existing modules _should not_ be split into smaller modules; doing so creates
57the potential for class duplication issues when a developer depends on a new
58sub-module alongside the older top-level module. Consider the following
59scenario:
60
61* `androidx.library:1.0.0`
AndroidX Core Team43201242021-01-26 21:38:01 +000062 * contains class `androidx.library.A`
63 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +000064
65This module is split, moving `androidx.library.util.B` to a new module:
66
67* `androidx.library:1.1.0`
68 * contains class `androidx.library.A`
AndroidX Core Team43201242021-01-26 21:38:01 +000069 * depends on `androidx.library.util:1.1.0`
70* `androidx.library.util:1.1.0`
71 * contains class `androidx.library.util.B`
AndroidX Core Team2e416b22020-12-03 22:58:07 +000072
AndroidX Core Team43201242021-01-26 21:38:01 +000073A developer writes an app that depends directly on `androidx.library.util:1.1.0`
74and also transitively pulls in `androidx.library:1.0.0`. Their app will no
75longer compile due to class duplication of `androidx.library.util.B`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +000076
77While it is possible for the developer to fix this by manually specifying a
78dependency on `androidx.library:1.1.0`, there is no easy way for the developer
79to discover this solution from the class duplication error raised at compile
80time.
81
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +000082Same-version groups are a special case for this rule. Existing modules that are
83already in a same-version group may be split into sub-modules provided that (a)
84the sub-modules are also in the same-version group and (b) the full API surface
85of the existing module is preserved through transitive dependencies, e.g. the
86sub-modules are added as dependencies of the existing module.
87
AndroidX Core Teamee1457a2021-02-25 16:13:10 +000088#### Same-version (atomic) groups {#modules-atomic}
AndroidX Core Team2e416b22020-12-03 22:58:07 +000089
90Library groups are encouraged to opt-in to a same-version policy whereby all
91libraries in the group use the same version and express exact-match dependencies
92on libraries within the group. Such groups must increment the version of every
93library at the same time and release all libraries at the same time.
94
95Atomic groups are specified in
AndroidX Core Team408c27b2020-12-15 15:57:00 +000096[`LibraryGroups.kt`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt):
AndroidX Core Team2e416b22020-12-03 22:58:07 +000097
98```kotlin
99// Non-atomic library group
100val APPCOMPAT = LibraryGroup("androidx.appcompat", null)
101// Atomic library group
102val APPSEARCH = LibraryGroup("androidx.appsearch", LibraryVersions.APPSEARCH)
103```
104
105Libraries within an atomic group should not specify a version in their
106`build.gradle`:
107
108```groovy
109androidx {
110 name = 'AppSearch'
111 publish = Publish.SNAPSHOT_AND_RELEASE
112 mavenGroup = LibraryGroups.APPSEARCH
113 inceptionYear = '2019'
114 description = 'Provides local and centralized app indexing'
115}
116```
117
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000118The benefits of using an atomic group are:
119
120- Easier for developers to understand dependency versioning
121- `@RestrictTo(LIBRARY_GROUP)` APIs are treated as private APIs and not
122 tracked for binary compatibility
123- `@RequiresOptIn` APIs defined within the group may be used without any
124 restrictions between libraries in the group
125
126Potential drawbacks include:
127
128- All libraries within the group must be versioned identically at head
129- All libraries within the group must release at the same time
130
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000131#### Early-stage development {#modules-atomic-alpha}
132
133There is one exception to the same-version policy: newly-added libraries within
134an atomic group may be "quarantined" from other libraries to allow for rapid
135iteration until they are API-stable.
136
137A quarantined library must stay within the `1.0.0-alphaXX` cycle until it is
138ready to conform to the same-version policy. While in quarantime, a library is
139treated at though it is in a separate group from its nomical same-version group:
140
141- Must stay in `1.0.0-alphaXX`, e.g. same-version policy is not enforced
142- May use `project` or pinned version dependencies, e.g. strict-match
143 dependencies are not enforced
144- May release on a separate cadence from other libraries within group
145- Must not reference restricted `LIBRARY-GROUP`-scoped APIs
146
147When the library would like to leave quarantine, it must wait for its atomic
148group to be within a `beta` cycle and then match the version. It is okay for a
149library in this situation to skip versions, e.g. move directly from
150`1.0.0-alpha02` to `2.1.3-beta06`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000151
152### Choosing a `minSdkVersion` {#module-minsdkversion}
153
154The recommended minimum SDK version for new Jetpack libraries is currently
155**17** (Android 4.2, Jelly Bean). This SDK was chosen to represent 99% of active
156devices based on Play Store check-ins (see Android Studio
157[distribution metadata](https://dl.google.com/android/studio/metadata/distributions.json)
158for current statistics). This maximizes potential users for external developers
159while minimizing the amount of overhead necessary to support legacy versions.
160
161However, if no explicit minimum SDK version is specified for a library, the
162default is 14.
163
164Note that a library **must not** depend on another library with a higher
165`minSdkVersion` that its own, so it may be necessary for a new library to match
166its dependent libraries' `minSdkVersion`.
167
168Individual modules may choose a higher minimum SDK version for business or
169technical reasons. This is common for device-specific modules such as Auto or
170Wear.
171
172Individual classes or methods may be annotated with the
173[@RequiresApi](https://developer.android.com/reference/android/annotation/RequiresApi.html)
174annotation to indicate divergence from the overall module's minimum SDK version.
175Note that this pattern is _not recommended_ because it leads to confusion for
176external developers and should be considered a last-resort when backporting
177behavior is not feasible.
178
AndroidX Core Team0db91f02021-05-06 22:45:18 +0000179### Kotlin extension `-ktx` libraries {#module-ktx}
180
181New libraries should prefer Kotlin sources with built-in Java compatibility via
182`@JvmName` and other affordances of the Kotlin language; however, existing Java
183sourced libraries may benefit from extending their API surface with
184Kotlin-friendly APIs in a `-ktx` library.
185
186A Kotlin extension library **may only** provide extensions for a single base
187library's API surface and its name **must** match the base library exactly. For
188example, `work:work-ktx` may only provide extensions for APIs exposed by
189`work:work`.
190
191Additionally, an extension library **must** specify an `api`-type dependency on
192the base library and **must** be versioned and released identically to the base
193library.
194
195Kotlin extension libraries _should not_ expose new functionality; they should
196only provide Kotlin-friendly versions of existing Java-facing functionality.
197
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000198## Platform compatibility API patterns {#platform-compatibility-apis}
199
AndroidX Core Team37584142021-02-25 17:58:46 +0000200NOTE For all library APIs that wrap or provide parity with platform APIs,
201_parity with the platform APIs overrides API guidelines_. For example, if the
202platform API being wrapped has incorrect `Executor` and `Callback` ordering
203according to the API Guidelines, the corresponding library API should have the
204exact same (incorrect) ordering.
205
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000206### Static shims (ex. [ViewCompat](https://developer.android.com/reference/android/support/v4/view/ViewCompat.html)) {#static-shim}
207
208When to use?
209
210* Platform class exists at module's `minSdkVersion`
211* Compatibility implementation does not need to store additional metadata
212
213Implementation requirements
214
215* Class name **must** be `<PlatformClass>Compat`
216* Package name **must** be `androidx.<feature>.<platform.package>`
217* Superclass **must** be `Object`
218* Class **must** be non-instantiable, i.e. constructor is private no-op
219* Static fields and static methods **must** match match signatures with
220 `PlatformClass`
221 * Static fields that can be inlined, ex. integer constants, **must not**
222 be shimmed
223* Public method names **must** match platform method names
224* Public methods **must** be static and take `PlatformClass` as first
225 parameter
226* Implementation _may_ delegate to `PlatformClass` methods when available
227
228#### Sample {#static-shim-sample}
229
230The following sample provides static helper methods for the platform class
231`android.os.Process`.
232
233```java
234/**
235 * Helper for accessing features in {@link Process}.
236 */
237public final class ProcessCompat {
238 private ProcessCompat() {
239 // This class is non-instantiable.
240 }
241
242 /**
243 * [Docs should match platform docs.]
244 *
245 * Compatibility behavior:
246 * <ul>
247 * <li>SDK 24 and above, this method matches platform behavior.
248 * <li>SDK 16 through 23, this method is a best-effort to match platform behavior, but may
249 * default to returning {@code true} if an accurate result is not available.
250 * <li>SDK 15 and below, this method always returns {@code true} as application UIDs and
251 * isolated processes did not exist yet.
252 * </ul>
253 *
254 * @param [match platform docs]
255 * @return [match platform docs], or a value based on platform-specific fallback behavior
256 */
257 public static boolean isApplicationUid(int uid) {
258 if (Build.VERSION.SDK_INT >= 24) {
259 return Api24Impl.isApplicationUid(uid);
260 } else if (Build.VERSION.SDK_INT >= 17) {
261 return Api17Impl.isApplicationUid(uid);
262 } else if (Build.VERSION.SDK_INT == 16) {
263 return Api16Impl.isApplicationUid(uid);
264 } else {
265 return true;
266 }
267 }
268
269 @RequiresApi(24)
270 static class Api24Impl {
271 static boolean isApplicationUid(int uid) {
272 // In N, the method was made public on android.os.Process.
273 return Process.isApplicationUid(uid);
274 }
275 }
276
277 @RequiresApi(17)
278 static class Api17Impl {
279 private static Method sMethod_isAppMethod;
280 private static boolean sResolved;
281
282 static boolean isApplicationUid(int uid) {
283 // In JELLY_BEAN_MR2, the equivalent isApp(int) hidden method moved to public class
284 // android.os.UserHandle.
285 try {
286 if (!sResolved) {
287 sResolved = true;
288 sMethod_isAppMethod = UserHandle.class.getDeclaredMethod("isApp",int.class);
289 }
290 if (sMethod_isAppMethod != null) {
291 return (Boolean) sMethod_isAppMethod.invoke(null, uid);
292 }
293 } catch (Exception e) {
294 e.printStackTrace();
295 }
296 return true;
297 }
298 }
299
300 ...
301}
302```
303
304### Wrapper (ex. [AccessibilityNodeInfoCompat](https://developer.android.com/reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html)) {#wrapper}
305
306When to use?
307
308* Platform class may not exist at module's `minSdkVersion`
309* Compatibility implementation may need to store additional metadata
310* Needs to integrate with platform APIs as return value or method argument
311* **Note:** Should be avoided when possible, as using wrapper classes makes it
312 very difficult to deprecate classes and migrate source code when the
313 `minSdkVersion` is raised
314
315#### Sample {#wrapper-sample}
316
317The following sample wraps a hypothetical platform class `ModemInfo` that was
318added to the platform SDK in API level 23:
319
320```java
321public final class ModemInfoCompat {
322 // Only guaranteed to be non-null on SDK_INT >= 23. Note that referencing the
323 // class itself directly is fine -- only references to class members need to
324 // be pushed into static inner classes.
325 private final ModemInfo wrappedObj;
326
327 /**
328 * [Copy platform docs for matching constructor.]
329 */
330 public ModemInfoCompat() {
331 if (SDK_INT >= 23) {
332 wrappedObj = Api23Impl.create();
333 } else {
334 wrappedObj = null;
335 }
336 ...
337 }
338
339 @RequiresApi(23)
340 private ModemInfoCompat(@NonNull ModemInfo obj) {
341 mWrapped = obj;
342 }
343
344 /**
345 * Provides a backward-compatible wrapper for {@link ModemInfo}.
346 * <p>
347 * This method is not supported on devices running SDK < 23 since the platform
348 * class will not be available.
349 *
350 * @param info platform class to wrap
351 * @return wrapped class, or {@code null} if parameter is {@code null}
352 */
353 @RequiresApi(23)
354 @NonNull
355 public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info) {
356 return new ModemInfoCompat(obj);
357 }
358
359 /**
360 * Provides the {@link ModemInfo} represented by this object.
361 * <p>
362 * This method is not supported on devices running SDK < 23 since the platform
363 * class will not be available.
364 *
365 * @return platform class object
366 * @see ModemInfoCompat#toModemInfoCompat(ModemInfo)
367 */
368 @RequiresApi(23)
369 @NonNull
370 public ModemInfo toModemInfo() {
371 return mWrapped;
372 }
373
374 /**
375 * [Docs should match platform docs.]
376 *
377 * Compatibility behavior:
378 * <ul>
379 * <li>API level 23 and above, this method matches platform behavior.
380 * <li>API level 18 through 22, this method ...
381 * <li>API level 17 and earlier, this method always returns false.
382 * </ul>
383 *
384 * @return [match platform docs], or platform-specific fallback behavior
385 */
386 public boolean isLteSupported() {
387 if (SDK_INT >= 23) {
388 return Api23Impl.isLteSupported(mWrapped);
389 } else if (SDK_INT >= 18) {
390 // Smart fallback behavior based on earlier APIs.
391 ...
392 }
393 // Default behavior.
394 return false;
395 }
396
397 // All references to class members -- including the constructor -- must be
398 // made on an inner class to avoid soft-verification errors that slow class
399 // loading and prevent optimization.
400 @RequiresApi(23)
401 private static class Api23Impl {
402 @NonNull
403 static ModemInfo create() {
404 return new ModemInfo();
405 }
406
407 static boolean isLteSupported(PlatformClass obj) {
408 return obj.isLteSupported();
409 }
410 }
411}
412```
413
414Note that libraries written in Java should express conversion to and from the
415platform class differently than Kotlin classes. For Java classes, conversion
416from the platform class to the wrapper should be expressed as a `static` method,
417while conversion from the wrapper to the platform class should be a method on
418the wrapper object:
419
420```java
421@NonNull
422public static ModemInfoCompat toModemInfoCompat(@NonNull ModemInfo info);
423
424@NonNull
425public ModemInfo toModemInfo();
426```
427
428In cases where the primary library is written in Java and has an accompanying
429`-ktx` Kotlin extensions library, the following conversion should be provided as
430an extension function:
431
432```kotlin
433fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
434```
435
436Whereas in cases where the primary library is written in Kotlin, the conversion
437should be provided as an extension factory:
438
439```kotlin
440class ModemInfoCompat {
441 fun toModemInfo() : ModemInfo
442
443 companion object {
444 @JvmStatic
445 @JvmName("toModemInfoCompat")
446 fun ModemInfo.toModemInfoCompat() : ModemInfoCompat
447 }
448}
449```
450
451#### API guidelines {#wrapper-api-guidelines}
452
453##### Naming {#wrapper-naming}
454
455* Class name **must** be `<PlatformClass>Compat`
456* Package name **must** be `androidx.core.<platform.package>`
457* Superclass **must not** be `<PlatformClass>`
458
459##### Construction {#wrapper-construction}
460
461* Class _may_ have public constructor(s) to provide parity with public
462 `PlatformClass` constructors
463 * Constructor used to wrap `PlatformClass` **must not** be public
464* Class **must** implement a static `PlatformClassCompat
465 toPlatformClassCompat(PlatformClass)` method to wrap `PlatformClass` on
466 supported SDK levels
467 * If class does not exist at module's `minSdkVersion`, method must be
468 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
469 introduced
470
471#### Implementation {#wrapper-implementation}
472
473* Class **must** implement a `PlatformClass toPlatformClass()` method to
474 unwrap `PlatformClass` on supported SDK levels
475 * If class does not exist at module's `minSdkVersion`, method must be
476 annotated with `@RequiresApi(<sdk>)` for SDK version where class was
477 introduced
478* Implementation _may_ delegate to `PlatformClass` methods when available (see
479 below note for caveats)
480* To avoid runtime class verification issues, all operations that interact
481 with the internal structure of `PlatformClass` must be implemented in inner
482 classes targeted to the SDK level at which the operation was added.
483 * See the [sample](#wrapper-sample) for an example of interacting with a
484 method that was added in SDK level 23.
485
486### Standalone (ex. [ArraySet](https://developer.android.com/reference/android/support/v4/util/ArraySet.html), [Fragment](https://developer.android.com/reference/android/support/v4/app/Fragment.html)) {#standalone}
487
488When to use?
489
490* Platform class may exist at module's `minSdkVersion`
491* Does not need to integrate with platform APIs
492* Does not need to coexist with platform class, ex. no potential `import`
493 collision due to both compatibility and platform classes being referenced
494 within the same source file
495
496Implementation requirements
497
498* Class name **must** be `<PlatformClass>`
499* Package name **must** be `androidx.<platform.package>`
500* Superclass **must not** be `<PlatformClass>`
501* Class **must not** expose `PlatformClass` in public API
AndroidX Core Teamee1457a2021-02-25 16:13:10 +0000502 * In exceptional cases, a _released_ standalone class may add conversion
503 between itself and the equivalent platform class; however, _new_ classes
504 that support conversion should follow the [Wrapper](#wrapper)
505 guidelines. In these cases, use a `toPlatform<PlatformClass>` and
506 `static toCompat<PlatformClass>` method naming convention.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000507* Implementation _may_ delegate to `PlatformClass` methods when available
508
509### Standalone JAR library (no Android dependencies) {#standalone-jar-library-no-android-dependencies}
510
511When to use
512
513* General purpose library with minimal interaction with Android types
514 * or when abstraction around types can be used (e.g. Room's SQLite
515 wrapper)
516* Lib used in parts of app with minimal Android dependencies
517 * ex. Repository, ViewModel
518* When Android dependency can sit on top of common library
519* Clear separation between android dependent and independent parts of your
520 library
521* Clear that future integration with android dependencies can be layered
522 separately
523
524**Examples:**
525
526The **Paging Library** pages data from DataSources (such as DB content from Room
527or network content from Retrofit) into PagedLists, so they can be presented in a
528RecyclerView. Since the included Adapter receives a PagedList, and there are no
529other Android dependencies, Paging is split into two parts - a no-android
530library (paging-common) with the majority of the paging code, and an android
531library (paging-runtime) with just the code to present a PagedList in a
532RecyclerView Adapter. This way, tests of Repositories and their components can
533be tested in host-side tests.
534
535**Room** loads SQLite data on Android, but provides an abstraction for those
536that want to use a different SQL implementation on device. This abstraction, and
537the fact that Room generates code dynamically, means that Room interfaces can be
538used in host-side tests (though actual DB code should be tested on device, since
539DB impls may be significantly different on host).
540
541## Implementing compatibility {#compat}
542
543### Referencing new APIs {#compat-newapi}
544
545Generally, methods on extension library classes should be available to all
546devices above the library's `minSdkVersion`.
547
548#### Checking device SDK version {#compat-sdk}
549
550The most common way of delegating to platform or backport implementations is to
551compare the device's `Build.VERSION.SDK_INT` field to a known-good SDK version;
552for example, the SDK in which a method first appeared or in which a critical bug
553was first fixed.
554
555Non-reflective calls to new APIs gated on `SDK_INT` **must** be made from
556version-specific static inner classes to avoid verification errors that
557negatively affect run-time performance. For more information, see Chromium's
558guide to
559[Class Verification Failures](https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md).
560
561Methods in implementation-specific classes **must** be paired with the
562`@DoNotInline` annotation to prevent them from being inlined.
563
564```java {.good}
565public static void saveAttributeDataForStyleable(@NonNull View view, ...) {
566 if (Build.VERSION.SDK_INT >= 29) {
567 Api29Impl.saveAttributeDataForStyleable(view, ...);
568 }
569}
570
571@RequiresApi(29)
572private static class Api29Impl {
573 @DoNotInline
574 static void saveAttributeDataForStyleable(@NonNull View view, ...) {
575 view.saveAttributeDataForStyleable(...);
576 }
577}
578```
579
580Alternatively, in Kotlin sources:
581
582```kotlin {.good}
583@RequiresApi(29)
AndroidX Core Team23c50442021-05-18 13:03:40 -0400584private object Api29Impl {
585 @JvmStatic
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000586 @DoNotInline
587 fun saveAttributeDataForStyleable(view: View, ...) { ... }
588}
589```
590
591When developing against pre-release SDKs where the `SDK_INT` has not been
592finalized, SDK checks **must** use `BuildCompat.isAtLeastX()` methods.
593
594```java {.good}
595@NonNull
596public static List<Window> getAllWindows() {
597 if (BuildCompat.isAtLeastR()) {
598 return ApiRImpl.getAllWindows();
599 }
600 return Collections.emptyList();
601}
602```
603
604#### Device-specific issues {#compat-oem}
605
606Library code may work around device- or manufacturer-specific issues -- issues
607not present in AOSP builds of Android -- *only* if a corresponding CTS test
608and/or CDD policy is added to the next revision of the Android platform. Doing
609so ensures that such issues can be detected and fixed by OEMs.
610
611#### Handling `minSdkVersion` disparity {#compat-minsdk}
612
613Methods that only need to be accessible on newer devices, including
614`to<PlatformClass>()` methods, may be annotated with `@RequiresApi(<sdk>)` to
615indicate they will fail to link on older SDKs. This annotation is enforced at
616build time by Lint.
617
618#### Handling `targetSdkVersion` behavior changes {#compat-targetsdk}
619
620To preserve application functionality, device behavior at a given API level may
621change based on an application's `targetSdkVersion`. For example, if an app with
622`targetSdkVersion` set to API level 22 runs on a device with API level 29, all
623required permissions will be granted at installation time and the run-time
624permissions framework will emulate earlier device behavior.
625
626Libraries do not have control over the app's `targetSdkVersion` and -- in rare
627cases -- may need to handle variations in platform behavior. Refer to the
628following pages for version-specific behavior changes:
629
630* API level 29:
631 [Android Q behavior changes: apps targeting Q](https://developer.android.com/preview/behavior-changes-q)
632* API level 28:
633 [Behavior changes: apps targeting API level 28+](https://developer.android.com/about/versions/pie/android-9.0-changes-28)
634* API level 26:
635 [Changes for apps targeting Android 8.0](https://developer.android.com/about/versions/oreo/android-8.0-changes#o-apps)
636* API level 24:
637 [Changes for apps targeting Android 7.0](https://developer.android.com/about/versions/nougat/android-7.0-changes#n-apps)
638* API level 21:
639 [Android 5.0 Behavior Changes](https://developer.android.com/about/versions/android-5.0-changes)
640* API level 19:
641 [Android 4.4 APIs](https://developer.android.com/about/versions/android-4.4)
642
643#### Working around Lint issues {#compat-lint}
644
645In rare cases, Lint may fail to interpret API usages and yield a `NewApi` error
646and require the use of `@TargetApi` or `@SuppressLint('NewApi')` annotations.
647Both of these annotations are strongly discouraged and may only be used
648temporarily. They **must never** be used in a stable release. Any usage of these
649annotation **must** be associated with an active bug, and the usage must be
650removed when the bug is resolved.
651
652### Delegating to API-specific implementations {#delegating-to-api-specific-implementations}
653
654#### SDK-dependent reflection
655
656Starting in API level 28, the platform restricts which
657[non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces)
658can be accessed via reflection by apps and libraries. As a general rule, you
659will **not** be able to use reflection to access hidden APIs on devices with
660`SDK_INT` greater than `Build.VERSION_CODES.P` (28).
661
662On earlier devices, reflection on hidden platform APIs is allowed **only** when
663an alternative public platform API exists in a later revision of the Android
664SDK. For example, the following implementation is allowed:
665
666```java
667public AccessibilityDelegate getAccessibilityDelegate(View v) {
668 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
669 // Retrieve the delegate using a public API.
670 return v.getAccessibilityDelegate();
671 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
672 // Retrieve the delegate by reflecting on a private field. If the
673 // field does not exist or cannot be accessed, this will no-op.
674 if (sAccessibilityDelegateField == null) {
675 try {
676 sAccessibilityDelegateField = View.class
677 .getDeclaredField("mAccessibilityDelegate");
678 sAccessibilityDelegateField.setAccessible(true);
679 } catch (Throwable t) {
680 sAccessibilityDelegateCheckFailed = true;
681 return null;
682 }
683 }
684 try {
685 Object o = sAccessibilityDelegateField.get(v);
686 if (o instanceof View.AccessibilityDelegate) {
687 return (View.AccessibilityDelegate) o;
688 }
689 return null;
690 } catch (Throwable t) {
691 sAccessibilityDelegateCheckFailed = true;
692 return null;
693 }
694 } else {
695 // There is no way to retrieve the delegate, even via reflection.
696 return null;
697 }
698```
699
700Calls to public APIs added in pre-release revisions *must* be gated using
701`BuildCompat`:
702
703```java
704if (BuildCompat.isAtLeastQ()) {
705 // call new API added in Q
706} else if (Build.SDK_INT.VERSION >= Build.VERSION_CODES.SOME_RELEASE) {
707 // make a best-effort using APIs that we expect to be available
708} else {
709 // no-op or best-effort given no information
710}
711```
712
713### Inter-process communication {#inter-process-communication}
714
715Protocols and data structures used for IPC must support interoperability between
716different versions of libraries and should be treated similarly to public API.
717
718#### Data structures
719
720**Do not** use Parcelable for any class that may be used for IPC or otherwise
721exposed as public API. The data format used by Parcelable does not provide any
722compatibility guarantees and will result in crashes if fields are added or
723removed between library versions.
724
725**Do not** design your own serialization mechanism or wire format for disk
726storage or inter-process communication. Preserving and verifying compatibility
727is difficult and error-prone.
728
729If you expose a `Bundle` to callers that can cross processes, you should
730[prevent apps from adding their own custom parcelables](https://android.googlesource.com/platform/frameworks/base/+/6cddbe14e1ff67dc4691a013fe38a2eb0893fe03)
731as top-level entries; if *any* entry in a `Bundle` can't be loaded, even if it's
732not actually accessed, the receiving process is likely to crash.
733
734**Do** use protocol buffers or, in some simpler cases, `VersionedParcelable`.
735
736#### Communication protocols
737
738Any communication prototcol, handshake, etc. must maintain compatibility
739consistent with SemVer guidelines. Consider how your protocol will handle
740addition and removal of operations or constants, compatibility-breaking changes,
741and other modifications without crashing either the host or client process.
742
743## Deprecation and removal
744
745While SemVer's binary compatibility guarantees restrict the types of changes
746that may be made within a library revision and make it difficult to remove an
747API, there are many other ways to influence how developers interact with your
748library.
749
750### Deprecation (`@deprecated`)
751
752Deprecation lets a developer know that they should stop using an API or class.
753All deprecations must be marked with a `@Deprecated` Java annotation as well as
754a `@deprecated <migration-docs>` docs annotation explaining how the developer
755should migrate away from the API.
756
757Deprecation is an non-breaking API change that must occur in a **major** or
758**minor** release.
759
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +0000760APIs that are added during a pre-release cycle and marked as `@Deprecated`
761within the same cycle, e.g. added in `alpha01` and deprecated in `alpha06`,
762[must be removed](versioning.md#beta-checklist) before moving to `beta01`.
763
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000764### Soft removal (@removed)
765
766Soft removal preserves binary compatibility while preventing source code from
767compiling against an API. It is a *source-breaking change* and not recommended.
768
769Soft removals **must** do the following:
770
771* Mark the API as deprecated for at least one stable release prior to removal.
772* Mark the API with a `@RestrictTo(LIBRARY)` Java annotation as well as a
773 `@removed <reason>` docs annotation explaining why the API was removed.
774* Maintain binary compatibility, as the API may still be called by existing
775 dependent libraries.
776* Maintain behavioral compatibility and existing tests.
777
778This is a disruptive change and should be avoided when possible.
779
780Soft removal is a source-breaking API change that must occur in a **major** or
781**minor** release.
782
783### Hard removal
784
785Hard removal entails removing the entire implementation of an API that was
786exposed in a public release. Prior to removal, an API must be marked as
787`@deprecated` for a full **minor** version (`alpha`->`beta`->`rc`->stable),
788prior to being hard removed.
789
790This is a disruptive change and should be avoided when possible.
791
792Hard removal is a binary-breaking API change that must occur in a **major**
793release.
794
795### For entire artifacts
796
797We do not typically deprecate or remove entire artifacts; however, it may be
798useful in cases where we want to halt development and focus elsewhere or
799strongly discourage developers from using a library.
800
801Halting development, either because of staffing or prioritization issues, leaves
802the door open for future bug fixes or continued development. This quite simply
803means we stop releasing updates but retain the source in our tree.
804
805Deprecating an artifact provides developers with a migration path and strongly
806encourages them -- through Lint warnings -- to migrate elsewhere. This is
807accomplished by adding a `@Deprecated` and `@deprecated` (with migration
808comment) annotation pair to *every* class and interface in the artifact.
809
810The fully-deprecated artifact will be released as a deprecation release -- it
811will ship normally with accompanying release notes indicating the reason for
812deprecation and migration strategy, and it will be the last version of the
813artifact that ships. It will ship as a new minor stable release. For example, if
814`1.0.0` was the last stable release, then the deprecation release will be
815`1.1.0`. This is so Android Studio users will get a suggestion to update to a
816new stable version, which will contain the `@deprecated` annotations.
817
818After an artifact has been released as fully-deprecated, it can be removed from
819the source tree.
820
821## Resources {#resources}
822
823Generally, follow the official Android guidelines for
824[app resources](https://developer.android.com/guide/topics/resources/providing-resources).
825Special guidelines for library resources are noted below.
826
827### Defining new resources
828
829Libraries may define new value and attribute resources using the standard
830application directory structure used by Android Gradle Plugin:
831
832```
833src/main/res/
834 values/
835 attrs.xml Theme attributes and styleables
836 dimens.xml Dimensional values
837 public.xml Public resource definitions
838 ...
839```
840
841However, some libraries may still be using non-standard, legacy directory
842structures such as `res-public` for their public resource declarations or a
843top-level `res` directory and accompanying custom source set in `build.gradle`.
844These libraries will eventually be migrated to follow standard guidelines.
845
846#### Naming conventions
847
848Libraries follow the Android platform's resource naming conventions, which use
849`camelCase` for attributes and `underline_delimited` for values. For example,
850`R.attr.fontProviderPackage` and `R.dimen.material_blue_grey_900`.
851
852#### Attribute formats
853
854At build time, attribute definitions are pooled globally across all libraries
855used in an application, which means attribute `format`s *must* be identical for
856a given `name` to avoid a conflict.
857
858Within Jetpack, new attribute names *must* be globally unique. Libraries *may*
859reference existing public attributes from their dependencies. See below for more
860information on public attributes.
861
862When adding a new attribute, the format should be defined *once* in an `<attr
863/>` element in the definitions block at the top of `src/main/res/attrs.xml`.
864Subsequent references in `<declare-styleable>` elements *must* not include a
865`format`:
866
867`src/main/res/attrs.xml`
868
869```xml
870<resources>
871 <attr name="fontProviderPackage" format="string" />
872
873 <declare-styleable name="FontFamily">
874 <attr name="fontProviderPackage" />
875 </declare-styleable>
876</resources>
877```
878
879### Public resources
880
881Library resources are private by default, which means developers are discouraged
882from referencing any defined attributes or values from XML or code; however,
883library resources may be declared public to make them available to developers.
884
885Public library resources are considered API surface and are thus subject to the
886same API consistency and documentation requirements as Java APIs.
887
888Libraries will typically only expose theme attributes, ex. `<attr />` elements,
889as public API so that developers can set and retrieve the values stored in
890styles and themes. Exposing values -- such as `<dimen />` and `<string />` -- or
891images -- such as drawable XML and PNGs -- locks the current state of those
892elements as public API that cannot be changed without a major version bump. That
893means changing a publicly-visible icon would be considered a breaking change.
894
895#### Documentation
896
897All public resource definitions should be documented, including top-level
898definitions and re-uses inside `<styleable>` elements:
899
900`src/main/res/attrs.xml`
901
902```xml
903<resources>
904 <!-- String specifying the application package for a Font Provider. -->
905 <attr name="fontProviderPackage" format="string" />
906
907 <!-- Attributes that are read when parsing a <fontfamily> tag. -->
908 <declare-styleable name="FontFamily">
909 <!-- The package for the Font Provider to be used for the request. This is
910 used to verify the identity of the provider. -->
911 <attr name="fontProviderPackage" />
912 </declare-styleable>
913</resources>
914```
915
916`src/main/res/colors.xml`
917
918```xml
919<resources>
920 <!-- Color for Material Blue-Grey 900. -->
921 <color name="material_blue_grey_900">#ff263238</color>
922</resources>
923```
924
925#### Public declaration
926
927Resources are declared public by providing a separate `<public />` element with
928a matching type:
929
930`src/main/res/public.xml`
931
932```xml
933<resources>
934 <public name="fontProviderPackage" type="attr" />
935 <public name="material_blue_grey_900" type="color" />
936</resources>
937```
938
939#### More information
940
941See also the official Android Gradle Plugin documentation for
942[Private Resources](https://developer.android.com/studio/projects/android-library#PrivateResources).
943
944### Manifest entries (`AndroidManifest.xml`) {#resources-manifest}
945
946#### Metadata tags (`<meta-data>`) {#resources-manifest-metadata}
947
948Developers **must not** add `<application>`-level `<meta-data>` tags to library
949manifests or advise developers to add such tags to their application manifests.
950Doing so may _inadvertently cause denial-of-service attacks against other apps_.
951
952Assume a library adds a single item of meta-data at the application level. When
953an app uses the library, that meta-data will be merged into the resulting app's
954application entry via manifest merger.
955
956If another app attempts to obtain a list of all activities associated with the
957primary app, that list will contain multiple copies of the `ApplicationInfo`,
958each of which in turn contains a copy of the library's meta-data. As a result,
959one `<metadata>` tag may become hundreds of KB on the binder call to obtain the
960list -- resulting in apps hitting transaction too large exceptions and crashing.
961
962```xml {.bad}
963<manifest xmlns:android="http://schemas.android.com/apk/res/android"
964 package="androidx.librarypackage">
965 <application>
966 <meta-data
967 android:name="keyName"
968 android:value="@string/value" />
969 </application>
970</manifest>
971```
972
973Instead, developers may consider adding `<metadata>` nested inside of
974placeholder `<service>` tags.
975
976```xml {.good}
977<manifest xmlns:android="http://schemas.android.com/apk/res/android"
978 package="androidx.librarypackage">
979 <application>
980 <service
981 android:name="androidx.librarypackage.MetadataHolderService"
982 android:enabled="false"
983 android:exported="false">
984 <meta-data
985 android:name="androidx.librarypackage.MetadataHolderService.KEY_NAME"
986 android:resource="@string/value" />
987 </service>
988 </application>
989```
990
991```java {.good}
992package androidx.libraryname.featurename;
993
994/**
995 * A placeholder service to avoid adding application-level metadata. The service
996 * is only used to expose metadata defined in the library's manifest. It is
997 * never invoked.
998 */
999public final class MetadataHolderService {
1000 private MetadataHolderService() {}
1001
1002 @Override
1003 public IBinder onBind(Intent intent) {
1004 throw new UnsupportedOperationException();
1005 }
1006}
1007```
1008
1009## Dependencies {#dependencies}
1010
alanv11786ae2021-05-25 10:55:11 -07001011### Specification types {#dependencies-spec}
1012
1013- Project `project(":core:core")` uses the tip-of-tree sources for the
1014 `androidx.core:core` library and requires that they be loaded in the
1015 workspace.
1016- Playground `projectOrArtifact(":core:core")` is used for
1017 [Playground](playground.md) projects and will use tip-of-tree sources, if
1018 present in the workspace, or `SNAPSHOT` prebuilt artifacts from
1019 [androidx.dev](http://androidx.dev) otherwise.
1020- Explicit `"androidx.core:core:1.4.0"` uses the prebuilt AAR and requires
1021 that it be checked in to the `prebuilts/androidx/internal` local Maven
1022 repository.
1023
1024Libraries should prefer explicit dependencies with the lowest possible versions
1025that include the APIs or behaviors required by the library, using project or
1026Playground specs only in cases where tip-of-tree APIs or behaviors are required.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001027
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001028### System health {#dependencies-health}
1029
1030Libraries should consider the system health implications of their dependencies,
1031including:
1032
1033- Large dependencies where only a small portion is needed (e.g. APK bloat)
1034- Dependencies that slow down build times through annotation processing or
1035 compiler overhead
1036
1037#### Kotlin {#dependencies-kotlin}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001038
AndroidX Core Team43201242021-01-26 21:38:01 +00001039Kotlin is _strongly recommended_ for new libraries; however, it's important to
1040consider its size impact on clients. Currently, the Kotlin stdlib adds a minimum
1041of 40kB post-optimization. It may not make sense to use Kotlin for a library
1042that targets Java-only clients or space-constrained (ex. Android Go) clients.
1043
1044Existing Java-based libraries are _strongly discouraged_ from using Kotlin,
1045primarily because our documentation system does not currently provide a
1046Java-facing version of Kotlin API reference docs. Java-based libraries _may_
1047migrate to Kotlin, but they must consider the docs usability and size impacts on
1048existing Java-only and space-constrained clients.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001049
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001050#### Kotlin coroutines {#dependencies-coroutines}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001051
1052Kotlin's coroutine library adds around 100kB post-shrinking. New libraries that
1053are written in Kotlin should prefer coroutines over `ListenableFuture`, but
1054existing libraries must consider the size impact on their clients. See
1055[Asynchronous work with return values](#async-return) for more details on using
1056Kotlin coroutines in Jetpack libraries.
1057
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001058#### Guava {#dependencies-guava}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001059
1060The full Guava library is very large and *must not* be used. Libraries that
1061would like to depend on Guava's `ListenableFuture` may instead depend on the
1062standalone `com.google.guava:listenablefuture` artifact. See
1063[Asynchronous work with return values](#async-return) for more details on using
1064`ListenableFuture` in Jetpack libraries.
1065
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001066#### Java 8 {#dependencies-java8}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001067
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001068Libraries that take a dependency on a library targeting Java 8 must _also_
1069target Java 8, which will incur a ~5% build performance (as of 8/2019) hit for
AndroidX Core Team4074b462021-06-01 06:53:40 -07001070clients. New libraries targeting Java 8 may use Java 8 dependencies.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001071
1072The default language level for `androidx` libraries is Java 8, and we encourage
1073libraries to stay on Java 8. However, if you have a business need to target Java
10747, you can specify Java 7 in your `build.gradle` as follows:
1075
1076```Groovy
1077android {
1078 compileOptions {
1079 sourceCompatibility = JavaVersion.VERSION_1_7
1080 targetCompatibility = JavaVersion.VERSION_1_7
1081 }
1082}
1083```
1084
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001085### Open-source compatibility {#dependencies-aosp}
1086
1087[Jetpack Principles](principles.md) require that libraries consider the
1088open-source compatibility implications of their dependencies, including:
1089
1090- Closed-source or proprietary libraries or services that may not be available
1091 on AOSP devices
1092- Dependencies that may prevent developers from effectively isolating their
1093 tests from third-party libraries or services
1094
1095Primary artifacts, e.g. `workmanager`, **must not** depend on closed-source
1096components including libraries and hard-coded references to packages,
1097permissions, or IPC mechanisms that may only be fulfulled by closed-source
1098components.
1099
1100Optional artifacts, e.g. `workmanager-gcm`, _may_ depend on closed-source
1101components or configure a primary artifact to be backed by a closed-source
1102component via service discovery or initialization.
1103
1104Some examples of safely depending on closed-source components include:
1105
1106- WorkManager's GCM Network Manager integration, which uses manifest metadata
1107 for service discovery and provides an optional artifact exposing the
1108 service.
1109- Ads Identifier's Play Services integration, which provides a default backend
1110 and uses `Intent` handling as a service discovery mechanism for Play
1111 Services.
1112- Downloadable Fonts integration with Play Services, which plugs in via a
1113 `ContentProvider` as a service discovery mechanism with developer-specified
1114 signature verification for additional security.
1115
1116Note that in all cases, the developer is not _required_ to use GCM or Play
1117Services and may instead use another compatible service implementing the same
1118publicly-defined protocols.
1119
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001120## More API guidelines {#more-api-guidelines}
1121
1122### Annotations {#annotation}
1123
1124#### Annotation processors {#annotation-processor}
1125
1126Annotation processors should opt-in to incremental annotation processing to
1127avoid triggering a full recompilation on every client source code change. See
1128Gradle's
1129[Incremental annotation processing](https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing)
1130documentation for information on how to opt-in.
1131
alanvf5ca4b92021-02-10 13:07:47 -08001132### Experimental `@RequiresOptIn` APIs {#experimental-api}
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001133
1134Jetpack libraries may choose to annotate API surfaces as unstable using either
1135Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001136[`@RequiresOptIn` annotation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-requires-opt-in/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001137for APIs written in Kotlin or Jetpack's
alanvf5ca4b92021-02-10 13:07:47 -08001138[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001139for APIs written in Java.
1140
1141In both cases, API surfaces marked as experimental are considered alpha and will
1142be excluded from API compatibility guarantees. Due to the lack of compatibility
alanvf5ca4b92021-02-10 13:07:47 -08001143guarantees, stable libraries *must never* call experimental APIs exposed by
1144other libraries outside of their
1145[same-version group](#same-version-atomic-groups) and *may not* use the `@OptIn`
1146annotation except in the following cases:
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001147
1148* A library within a same-version group *may* call an experimental API exposed
1149 by another library **within its same-version group**. In this case, API
1150 compatibility guarantees are covered under the same-version group policies
alanvf5ca4b92021-02-10 13:07:47 -08001151 and the library *may* use the `@OptIn` annotation to prevent propagation of
1152 the experimental property. **Library owners must exercise care to ensure
1153 that post-alpha APIs backed by experimental APIs actually meet the release
1154 criteria for post-alpha APIs.**
1155* An `alpha` library may use experimental APIs from outside its same-version
1156 group. These usages must be removed when the library moves to `beta`.
1157
1158NOTE JetBrains's own usage of `@RequiresOptIn` in Kotlin language libraries
1159varies and may indicate binary instability, functional instability, or simply
1160that an API is really difficult to use. Jetpack libraries should treat instances
1161of `@RequiresOptIn` in JetBrains libraries as indicating **binary instability**
1162and avoid using them outside of `alpha`; however, teams are welcome to obtain
1163written assurance from JetBrains regarding binary stability of specific APIs.
1164`@RequiresOptIn` APIs that are guaranteed to remain binary compatible _may_ be
1165used in `beta`, but usages must be removed when the library moves to `rc`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001166
1167#### How to mark an API surface as experimental
1168
alanvf5ca4b92021-02-10 13:07:47 -08001169All libraries using `@RequiresOptIn` annotations *must* depend on the
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001170`androidx.annotation:annotation-experimental` artifact regardless of whether
1171they are using the `androidx` or Kotlin annotation. This artifact provides Lint
1172enforcement of experimental usage restrictions for Kotlin callers as well as
1173Java (which the Kotlin annotation doesn't handle on its own, since it's a Kotlin
1174compiler feature). Libraries *may* include the dependency as `api`-type to make
alanvf5ca4b92021-02-10 13:07:47 -08001175`@OptIn` available to Java clients; however, this will also unnecessarily expose
1176the `@RequiresOptIn` annotation.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001177
1178```java
1179dependencies {
1180 implementation(project(":annotation:annotation-experimental"))
1181}
1182```
1183
1184See Kotlin's
alanvf5ca4b92021-02-10 13:07:47 -08001185[opt-in requirements documentation](https://kotlinlang.org/docs/reference/opt-in-requirements.html)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001186for general usage information. If you are writing experimental Java APIs, you
1187will use the Jetpack
alanvf5ca4b92021-02-10 13:07:47 -08001188[`@RequiresOptIn` annotation](https://developer.android.com/reference/kotlin/androidx/annotation/RequiresOptIn)
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001189rather than the Kotlin compiler's annotation.
1190
1191#### How to transition an API out of experimental
1192
1193When an API surface is ready to transition out of experimental, the annotation
1194may only be removed during an alpha pre-release stage since removing the
1195experimental marker from an API is equivalent to adding the API to the current
1196API surface.
1197
1198When transitioning an entire feature surface out of experimental, you *should*
1199remove the associated annotations.
1200
1201When making any change to the experimental API surface, you *must* run
1202`./gradlew updateApi` prior to uploading your change.
1203
1204### Restricted APIs {#restricted-api}
1205
1206Jetpack's library tooling supports hiding Java-visible (ex. `public` and
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001207`protected`) APIs from developers using a combination of the `@RestrictTo`
1208source annotation, and the `@hide` docs annotation (`@suppress` in Kotlin).
1209These annotations **must** be paired together when used, and are validated as
1210part of presubmit checks for Java code (Kotlin not yet supported by Checkstyle).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001211
1212The effects of hiding an API are as follows:
1213
1214* The API will not appear in documentation
1215* Android Studio will warn the developer not to use the API
1216
1217Hiding an API does *not* provide strong guarantees about usage:
1218
1219* There are no runtime restrictions on calling hidden APIs
1220* Android Studio will not warn if hidden APIs are called using reflection
1221* Hidden APIs will still show in Android Studio's auto-complete
1222
1223#### When to use `@hide` {#restricted-api-usage}
1224
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001225In other cases, avoid using `@hide` / `@suppress`. These annotations indicates
1226that developers should not call an API that is _technically_ public from a Java
1227visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API
1228surface, and priority should be given to creating public, maintainable APIs and
1229using Java visibility modifiers.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001230
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001231*Do not* use `@hide`/`@suppress` to bypass API tracking and review for
1232production APIs; instead, rely on API+1 and API Council review to ensure APIs
1233are reviewed on a timely basis.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001234
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001235*Do not* use `@hide`/`@suppress` for implementation detail APIs that are used
1236between libraries and could reasonably be made public.
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001237
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001238*Do* use `@hide`/`@suppress` paired with `@RestrictTo(LIBRARY)` for
1239implementation detail APIs used within a single library (but prefer Java
1240language `private` or `default` visibility).
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001241
1242#### `RestrictTo.Scope` and inter- versus intra-library API surfaces {#private-api-types}
1243
1244To maintain binary compatibility between different versions of libraries,
1245restricted API surfaces that are used between libraries (inter-library APIs)
1246must follow the same Semantic Versioning rules as public APIs. Inter-library
1247APIs should be annotated with the `@RestrictTo(LIBRARY_GROUP)` source
1248annotation.
1249
1250Restricted API surfaces used within a single library (intra-library APIs), on
1251the other hand, may be added or removed without any compatibility
1252considerations. It is safe to assume that developers _never_ call these APIs,
1253even though it is technically feasible. Intra-library APIs should be annotated
1254with the `@RestrictTo(LIBRARY)` source annotation.
1255
1256The following table shows the visibility of a hypothetical API within Maven
1257coordinate `androidx.concurrent:concurrent` when annotated with a variety of
1258scopes:
1259
1260<table>
1261 <tr>
1262 <td><code>RestrictTo.Scope</code></td>
1263 <td>Visibility by Maven coordinate</td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001264 <td>Versioning</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001265 </tr>
1266 <tr>
1267 <td><code>LIBRARY</code></td>
1268 <td><code>androidx.concurrent:concurrent</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001269 <td>No compatibility gurantees (same as private)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001270 </tr>
1271 <tr>
1272 <td><code>LIBRARY_GROUP</code></td>
1273 <td><code>androidx.concurrent:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001274 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001275 </tr>
1276 <tr>
1277 <td><code>LIBRARY_GROUP_PREFIX</code></td>
1278 <td><code>androidx.*:*</code></td>
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001279 <td>Semantic versioning (including deprecation)</td>
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001280 </tr>
1281</table>
1282
AndroidX Core Team03b4da32021-03-10 23:20:41 +00001283#### `@IntDef` `@StringDef` and `@LongDef` and visibility
1284
1285All `@IntDef`, `@StringDef`, and `@LongDef` will be stripped from resulting
1286artifacts to avoid issues where compiler inlining constants removes information
1287as to which `@IntDef` defined the value of `1`. The annotations are extracted
1288and packaged separately to be read by Android Studio and lint which enforces the
1289types in application code.
1290
1291* Libraries _must_ `@hide` all `@IntDef`, `@StringDef`, and `@LongDef`
1292 declarations.
1293* Libraries _must_ expose constants used to define the `@IntDef` etc at the
1294 same Java visibility as the hidden `@IntDef`
1295* Libraries _should_ also use @RestrictTo to create a warning when the type
1296 used incorrectly.
1297
1298Here is a complete example of an `@IntDef`
1299
1300```java
1301// constants match Java visibility of ExifStreamType
1302// code outside this module interacting with ExifStreamType uses these constants
1303public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
1304public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
1305
1306/** @hide */
1307@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
1308@Retention(RetentionPolicy.SOURCE)
1309@IntDef({
1310 STREAM_TYPE_FULL_IMAGE_DATA,
1311 STREAM_TYPE_EXIF_DATA_ONLY,
1312})
1313public @interface ExifStreamType {}
1314```
1315
1316Java visibilty should be set as appropriate for the code in question (`private`,
1317`package` or `public`) and is unrelated to hiding.
1318
1319For more, read the section in
1320[Android API Council Guidelines](https://android.googlesource.com/platform/developers/docs/+/refs/heads/master/api-guidelines/index.md#no-public-typedefs)
1321
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001322### Constructors {#constructors}
1323
1324#### View constructors {#view-constructors}
1325
1326The four-arg View constructor -- `View(Context, AttributeSet, int, int)` -- was
1327added in SDK 21 and allows a developer to pass in an explicit default style
1328resource rather than relying on a theme attribute to resolve the default style
1329resource. Because this API was added in SDK 21, care must be taken to ensure
1330that it is not called through any < SDK 21 code path.
1331
1332Views _may_ implement a four-arg constructor in one of the following ways:
1333
13341. Do not implement.
13351. Implement and annotate with `@RequiresApi(21)`. This means the three-arg
1336 constructor **must not** call into the four-arg constructor.
1337
1338### Asynchronous work {#async}
1339
1340#### With return values {#async-return}
1341
1342Traditionally, asynchronous work on Android that results in an output value
1343would use a callback; however, better alternatives exist for libraries.
1344
1345Kotlin libraries should prefer
1346[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and
1347`suspend` functions, but please refer to the guidance on
1348[allowable dependencies](#dependencies-coroutines) before adding a new
1349dependency on coroutines.
1350
1351Java libraries should prefer `ListenableFuture` and the
1352[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter)
1353implementation provided by the `androidx.concurrent:concurrent-futures` library.
1354
1355Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a
1356large API surface that permits arbitrary mutation of the future's value and has
1357error-prone defaults.
1358
1359See the [Dependencies](#dependencies) section for more information on using
1360Kotlin coroutines and Guava in your library.
1361
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001362#### Cancellation
1363
1364Libraries that expose APIs for performing asynchronous work should support
1365cancellation. There are _very few_ cases where it is not feasible to support
1366cancellation.
1367
1368Libraries that use `ListenableFuture` must be careful to follow the exact
1369specification of
1370[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-)
1371behavior.
1372
1373```java {.bad}
1374@Override
1375public boolean cancel(boolean mayInterruptIfRunning) {
1376 // Does not support cancellation.
1377 return false;
1378}
1379```
1380
1381```java {.bad}
1382@Override
1383public boolean cancel(boolean mayInterruptIfRunning) {
1384 // Aggressively does not support cancellation.
1385 throw new UnsupportedOperationException();
1386}
1387```
1388
1389```java {.good}
1390@Override
1391public boolean cancel(boolean mayInterruptIfRunning) {
1392 // Pseudocode that ignores threading but follows the spec.
1393 if (mCompleted
1394 || mCancelled
1395 || mRunning && !mayInterruptIfRunning) {
1396 return false;
1397 }
1398 mCancelled = true;
1399 return true;
1400}
1401```
1402
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001403#### Avoid `synchronized` methods
1404
1405Whenever multiple threads are interacting with shared (mutable) references those
1406reads and writes must be synchronized in some way. However synchronized blocks
1407make your code thread-safe at the expense of concurrent execution. Any time
1408execution enters a synchronized block or method any other thread trying to enter
1409a synchronized block on the same object has to wait; even if in practice the
1410operations are unrelated (e.g. they interact with different fields). This can
1411dramatically reduce the benefit of trying to write multi-threaded code in the
1412first place.
1413
1414Locking with synchronized is a heavyweight form of ensuring ordering between
1415threads, and there are a number of common APIs and patterns that you can use
1416that are more lightweight, depending on your use case:
1417
1418* Compute a value once and make it available to all threads
1419* Update Set and Map data structures across threads
1420* Allow a group of threads to process a stream of data concurrently
1421* Provide instances of a non-thread-safe type to multiple threads
1422* Update a value from multiple threads atomically
1423* Maintain granular control of your concurrency invariants
1424
1425### Kotlin {#kotlin}
1426
AndroidX Core Teamee9c1aa2021-04-06 17:29:05 +00001427#### Nullability from Java (new APIs)
1428
1429All new Java APIs should be annotated either `@Nullable` or `@NonNull` for all
1430reference parameters and reference return types.
1431
1432```java
1433 @Nullable
1434 public Object someNewApi(@NonNull Thing arg1, @Nullable List<WhatsIt> arg2) {
1435 if(/** something **/) {
1436 return someObject;
1437 } else {
1438 return null;
1439 }
1440```
1441
1442#### Nullability from Java (existing APIs)
1443
1444Adding `@Nullable` or `@NonNull` annotations to existing APIs to document their
1445existing nullability is OK. This is a source breaking change for Kotlin
1446consumers, and you should ensure that it's noted in the release notes and try to
1447minimize the frequency of these updates in releases.
1448
1449Changing the nullability of an API is a breaking change.
1450
1451#### Extending APIs that expose types without nullability annotations
1452
1453[Platform types](https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types)
1454are exposed by Java types that do not have a `@Nullable` or `@NonNull`
1455annotation. In Kotlin they are indicated with the `!` suffix.
1456
1457When interacting with an Android platform API that exposes APIs with unknown
1458nullability follow these rules:
1459
14601. If wrapping the type in a new API, define and handle `@Nullable` or
1461 `@NonNull` in the library. Treat types with unknown nullability passed into
1462 or return from Android as `@Nullable` in the library.
14632. If extending an existing API (e.g. `@Override`), pass through the existing
1464 types with unknown nullability and annotate each with
1465 `@SuppressLint("UnknownNullness")`
1466
1467In Kotlin, a type with unknown nullability is exposed as a "platform type"
1468(indicated with a `!` suffix) which has unknown nullability in the type checker,
1469and may bypass type checking leading to runtime errors. When possible, do not
1470directly expose types with unknown nullability in new public APIs.
1471
1472#### Extending `@RecentlyNonNull` and `@RecentlyNullable` APIs
1473
1474Platform APIs are annotated in the platform SDK artifacts with fake annotations
1475`@RecentlyNonNull` and `@RecentlyNullable` to avoid breaking builds when we
1476annotated platform APIs with nullability. These annotations cause warnings
1477instead of build failures. The `RecentlyNonNull` and `RecentlyNullable`
1478annotations are added by Metalava and do not appear in platform code.
1479
1480When extending an API that is annotated `@RecentlyNonNull`, you should annotate
1481the override with `@NonNull`, and the same for `@RecentlyNullable` and
1482`@Nullable`.
1483
1484For example `SpannableStringBuilder.append` is annotated `RecentlyNonNull` and
1485an override should look like:
1486
1487```java
1488 @NonNull
1489 @Override
1490 public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text) {
1491 super.append(text);
1492 return this;
1493 }
1494```
1495
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001496#### Data classes {#kotlin-data}
1497
1498Kotlin `data` classes provide a convenient way to define simple container
1499objects, where Kotlin will generate `equals()` and `hashCode()` for you.
1500However, they are not designed to preserve API/binary compatibility when members
1501are added. This is due to other methods which are generated for you -
1502[destructuring declarations](https://kotlinlang.org/docs/reference/multi-declarations.html),
1503and [copying](https://kotlinlang.org/docs/reference/data-classes.html#copying).
1504
1505Example data class as tracked by metalava:
1506
1507<pre>
1508 public final class TargetAnimation {
1509 ctor public TargetAnimation(float target, androidx.animation.AnimationBuilder animation);
1510 <b>method public float component1();</b>
1511 <b>method public androidx.animation.AnimationBuilder component2();</b>
1512 <b>method public androidx.animation.TargetAnimation copy(float target, androidx.animation.AnimationBuilder animation);</b>
1513 method public androidx.animation.AnimationBuilder getAnimation();
1514 method public float getTarget();
1515 }
1516</pre>
1517
1518Because members are exposed as numbered components for destructuring, you can
1519only safely add members at the end of the member list. As `copy` is generated
1520with every member name in order as well, you'll also have to manually
1521re-implement any old `copy` variants as items are added. If these constraints
1522are acceptable, data classes may still be useful to you.
1523
1524As a result, Kotlin `data` classes are _strongly discouraged_ in library APIs.
1525Instead, follow best-practices for Java data classes including implementing
1526`equals`, `hashCode`, and `toString`.
1527
1528See Jake Wharton's article on
1529[Public API challenges in Kotlin](https://jakewharton.com/public-api-challenges-in-kotlin/)
1530for more details.
1531
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07001532#### Exhaustive `when` and `sealed class`/`enum class` {#exhaustive-when}
1533
1534A key feature of Kotlin's `sealed class` and `enum class` declarations is that
1535they permit the use of **exhaustive `when` expressions.** For example:
1536
1537```kotlin
1538enum class CommandResult { Permitted, DeniedByUser }
1539
1540val message = when (commandResult) {
1541 Permitted -> "the operation was permitted"
1542 DeniedByUser -> "the user said no"
1543}
1544
1545println(message)
1546```
1547
1548This highlights challenges for library API design and compatibility. Consider
1549the following addition to the `CommandResult` possibilities:
1550
1551```kotlin {.bad}
1552enum class CommandResult {
1553 Permitted,
1554 DeniedByUser,
1555 DeniedByAdmin // New in androidx.mylibrary:1.1.0!
1556}
1557```
1558
1559This change is both **source and binary breaking.**
1560
1561It is **source breaking** because the author of the `when` block above will see
1562a compiler error about not handling the new result value.
1563
1564It is **binary breaking** because if the `when` block above was compiled as part
1565of a library `com.example.library:1.0.0` that transitively depends on
1566`androidx.mylibrary:1.0.0`, and an app declares the dependencies:
1567
1568```kotlin
1569implementation("com.example.library:1.0.0")
1570implementation("androidx.mylibrary:1.1.0") // Updated!
1571```
1572
1573`com.example.library:1.0.0` does not handle the new result value, leading to a
1574runtime exception.
1575
1576**Note:** The above example is one where Kotlin's `enum class` is the correct
1577tool and the library should **not** add a new constant! Kotlin turns this
1578semantic API design problem into a compiler or runtime error. This type of
1579library API change could silently cause app logic errors or data corruption
1580without the protection provided by exhaustive `when`. See
1581[When to use exhaustive types](#when-to-use-exhaustive-types).
1582
1583`sealed class` exhibits the same characteristic; adding a new subtype of an
1584existing sealed class is a breaking change for the following code:
1585
1586```kotlin
1587val message = when (command) {
1588 is Command.Migrate -> "migrating to ${command.destination}"
1589 is Command.Quack -> "quack!"
1590}
1591```
1592
1593##### Non-exhaustive alternatives to `enum class`
1594
1595Kotlin's `@JvmInline value class` with a `private constructor` can be used to
1596create type-safe sets of non-exhaustive constants as of Kotlin 1.5. Compose's
1597`BlendMode` uses the following pattern:
1598
1599```kotlin {.good}
1600@JvmInline
1601value class BlendMode private constructor(val value: Int) {
1602 companion object {
1603 /** Drop both the source and destination images, leaving nothing. */
1604 val Clear = BlendMode(0)
1605 /** Drop the destination image, only paint the source image. */
1606 val Src = BlendMode(1)
1607 // ...
1608 }
1609}
1610```
1611
1612**Note:** This recommendation may be temporary. Kotlin may add new annotations
1613or other language features to declare non-exhaustive enum classes in the future.
1614
1615Alternatively, the existing `@IntDef` mechanism used in Java-language androidx
1616libraries may also be used, but type checking of constants will only be
1617performed by lint, and functions overloaded with parameters of different value
1618class types are not supported. Prefer the `@JvmInline value class` solution for
1619new code unless it would break local consistency with other API in the same
1620module that already uses `@IntDef`.
1621
1622##### Non-exhaustive alternatives to `sealed class`
1623
1624Abstract classes with constructors marked as `internal` or `private` can
1625represent the same subclassing restrictions of sealed classes as seen from
1626outside of a library module's own codebase:
1627
1628```kotlin
1629abstract class Command private constructor() {
1630 class Migrate(val destination: String) : Command()
1631 object Quack : Command()
1632}
1633```
1634
1635Using an `internal` constructor will permit non-nested subclasses, but will
1636**not** restrict subclasses to the same package within the module, as sealed
1637classes do.
1638
1639##### When to use exhaustive types
1640
1641Use `enum class` or `sealed class` when the values or subtypes are intended to
1642be exhaustive by design from the API's initial release. Use non-exhaustive
1643alternatives when the set of constants or subtypes might expand in a minor
1644version release.
1645
1646Consider using an **exhaustive** (`enum class` or `sealed class`) type
1647declaration if:
1648
1649* The developer is expected to **accept** values of the type
1650* The developer is expected to **act** on **any and all** values received
1651
1652Consider using a **non-exhaustive** type declaration if:
1653
1654* The developer is expected to **provide** values of the type to APIs exposed
1655 by the same module **only**
1656* The developer is expected to **ignore** unknown values received
1657
1658The `CommandResult` example above is a good example of a type that **should**
1659use the exhaustive `enum class`; `CommandResult`s are **returned** to the
1660developer and the developer cannot implement correct app behavior by ignoring
1661unrecognized result values. Adding a new result value would semantically break
1662existing code regardless of the language facility used to express the type.
1663
1664```kotlin {.good}
1665enum class CommandResult { Permitted, DeniedByUser, DeniedByAdmin }
1666```
1667
1668Compose's `BlendMode` is a good example of a type that **should not** use the
1669exhaustive `enum class`; blending modes are used as arguments to Compose
1670graphics APIs and are not intended for interpretation by app code. Additionally,
1671there is historical precedent from `android.graphics` for new blending modes to
1672be added in the future.
1673
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001674#### Extension and top-level functions {#kotlin-extension-functions}
1675
AndroidX Core Team6fd727f2021-06-01 12:26:34 -07001676If your Kotlin file contains any symbols outside of class-like types
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001677(extension/top-level functions, properties, etc), the file must be annotated
1678with `@JvmName`. This ensures unanticipated use-cases from Java callers don't
1679get stuck using `BlahKt` files.
1680
1681Example:
1682
1683```kotlin {.bad}
1684package androidx.example
1685
1686fun String.foo() = // ...
1687```
1688
1689```kotlin {.good}
1690@file:JvmName("StringUtils")
1691
1692package androidx.example
1693
1694fun String.foo() = // ...
1695```
1696
1697NOTE This guideline may be ignored for libraries that only work in Kotlin (think
1698Compose).
1699
1700## Testing Guidelines
1701
1702### [Do not Mock, AndroidX](do_not_mock.md)
1703
1704## Android Lint Guidelines
1705
1706### Suppression vs Baselines
1707
1708Lint sometimes flags false positives, even though it is safe to ignore these
1709errors (for example WeakerAccess warnings when you are avoiding synthetic
1710access). There may also be lint failures when your library is in the middle of a
1711beta / rc / stable release, and cannot make the breaking changes needed to fix
1712the root cause. There are two ways of ignoring lint errors:
1713
17141. Suppression - using `@SuppressLint` (for Java) or `@Suppress` annotations to
1715 ignore the warning per call site, per method, or per file. *Note
1716 `@SuppressLint` - Requires Android dependency*.
17172. Baselines - allowlisting errors in a lint-baseline.xml file at the root of
1718 the project directory.
1719
1720Where possible, you should use a **suppression annotation at the call site**.
1721This helps ensure that you are only suppressing the *exact* failure, and this
1722also keeps the failure visible so it can be fixed later on. Only use a baseline
1723if you are in a Java library without Android dependencies, or when enabling a
1724new lint check, and it is prohibitively expensive / not possible to fix the
1725errors generated by enabling this lint check.
1726
1727To update a lint baseline (lint-baseline.xml) after you have fixed issues, add
1728`-PupdateLintBaseline` to the end of your lint command. This will delete and
1729then regenerate the baseline file.
1730
1731```shell
1732./gradlew core:lintDebug -PupdateLintBaseline
1733```
1734
1735## Metalava API Lint
1736
1737As well as Android Lint, which runs on all source code, Metalava will also run
1738checks on the public API surface of each library. Similar to with Android Lint,
1739there can sometimes be false positives / intended deviations from the API
1740guidelines that Metalava will lint your API surface against. When this happens,
1741you can suppress Metalava API lint issues using `@SuppressLint` (for Java) or
1742`@Suppress` annotations. In cases where it is not possible, update Metalava's
1743baseline with the `updateApiLintBaseline` task.
1744
1745```shell
1746./gradlew core:updateApiLintBaseline
1747```
1748
1749This will create/amend the `api_lint.ignore` file that lives in a library's
1750`api` directory.
1751
1752## Build Output Guidelines
1753
1754In order to more easily identify the root cause of build failures, we want to
1755keep the amount of output generated by a successful build to a minimum.
1756Consequently, we track build output similarly to the way in which we track Lint
1757warnings.
1758
1759### Invoking build output validation
1760
1761You can add `-Pandroidx.validateNoUnrecognizedMessages` to any other AndroidX
1762gradlew command to enable validation of build output. For example:
1763
1764```shell
1765/gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1766```
1767
1768### Exempting new build output messages
1769
1770Please avoid exempting new build output and instead fix or suppress the warnings
1771themselves, because that will take effect not only on the build server but also
1772in Android Studio, and will also run more quickly.
1773
1774If you cannot prevent the message from being generating and must exempt the
1775message anyway, follow the instructions in the error:
1776
1777```shell
1778$ ./gradlew -Pandroidx.validateNoUnrecognizedMessages :help
1779
1780Error: build_log_simplifier.py found 15 new messages found in /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.
1781
1782Please fix or suppress these new messages in the tool that generates them.
1783If you cannot, then you can exempt them by doing:
1784
1785 1. cp /usr/local/google/workspace/aosp-androidx-git/out/dist/gradle.log.ignore /usr/local/google/workspace/aosp-androidx-git/frameworks/support/development/build_log_simplifier/messages.ignore
1786 2. modify the new lines to be appropriately generalized
1787```
1788
1789Each line in this exemptions file is a regular expressing matching one or more
1790lines of output to be exempted. You may want to make these expressions as
1791specific as possible to ensure that the addition of new, similar messages will
1792also be detected (for example, discovering an existing warning in a new source
1793file).
1794
1795## Behavior changes
1796
1797### Changes that affect API documentation
1798
1799Do not make behavior changes that require altering API documentation in a way
1800that would break existing clients, even if such changes are technically binary
1801compatible. For example, changing the meaning of a method's return value to
1802return true rather than false in a given state would be considered a breaking
1803change. Because this change is binary-compatible, it will not be caught by
1804tooling and is effectively invisible to clients.
1805
1806Instead, add new methods and deprecate the existing ones if necessary, noting
1807behavior changes in the deprecation message.
1808
1809### High-risk behavior changes
1810
1811Behavior changes that conform to documented API contracts but are highly complex
1812and difficult to comprehensively test are considered high-risk and should be
1813implemented using behavior flags. These changes may be flagged on initially, but
1814the original behaviors must be preserved until the library enters release
1815candidate stage and the behavior changes have been appropriately verified by
1816integration testing against public pre-release
1817revisions.
1818
1819It may be necessary to soft-revert a high-risk behavior change with only 24-hour
1820notice, which should be achievable by flipping the behavior flag to off.
1821
1822```java
AndroidX Core Teamee1457a2021-02-25 16:13:10 +00001823// Flag for whether to throw exceptions when the state is known to be bad. This
1824// is expected to be a high-risk change since apps may be working fine even with
1825// a bad state, so we may need to disable this as a hotfix.
1826private static final boolean FLAG_EXCEPTION_ON_BAD_STATE = false;
1827```
1828
1829```java
1830/**
1831 * Allows a developer to toggle throwing exceptions when the state is known to
1832 * be bad. This method is intended to give developers time to update their code.
1833 * It is temporary and will be removed in a future release.
1834 */
1835@TemporaryFeatureFlag
1836public void setExceptionOnBadStateEnabled(boolean enabled);
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001837```
1838
1839Avoid adding multiple high-risk changes during a feature cycle, as verifying the
1840interaction of multiple feature flags leads to unnecessary complexity and
1841exposes clients to high risk even when a single change is flagged off. Instead,
1842wait until one high-risk change has landed in RC before moving on to the next.
1843
1844#### Testing
1845
1846Relevant tests should be run for the behavior change in both the on and off
1847flagged states to prevent regressions.
1848
1849## Sample code in Kotlin modules
1850
1851### Background
1852
1853Public API can (and should!) have small corresponding code snippets that
1854demonstrate functionality and usage of a particular API. These are often exposed
1855inline in the documentation for the function / class - this causes consistency
1856and correctness issues as this code is not compiled against, and the underlying
1857implementation can easily change.
1858
1859KDoc (JavaDoc for Kotlin) supports a `@sample` tag, which allows referencing the
1860body of a function from documentation. This means that code samples can be just
1861written as a normal function, compiled and linted against, and reused from other
1862modules such as tests! This allows for some guarantees on the correctness of a
1863sample, and ensuring that it is always kept up to date.
1864
1865### Enforcement
1866
1867There are still some visibility issues here - it can be hard to tell if a
1868function is a sample, and is used from public documentation - so as a result we
1869have lint checks to ensure sample correctness.
1870
1871Primarily, there are three requirements when using sample links:
1872
18731. All functions linked to from a `@sample` KDoc tag must be annotated with
1874 `@Sampled`
18752. All sample functions annotated with `@Sampled` must be linked to from a
1876 `@sample` KDoc tag
18773. All sample functions must live inside a separate `samples` library
1878 submodule - see the section on module configuration below for more
1879 information.
1880
1881This enforces visibility guarantees, and make it easier to know that a sample is
1882a sample. This also prevents orphaned samples that aren't used, and remain
1883unmaintained and outdated.
1884
1885### Sample usage
1886
1887The follow demonstrates how to reference sample functions from public API. It is
1888also recommended to reuse these samples in unit tests / integration tests / test
1889apps / library demos where possible.
1890
1891**Public API:**
1892
1893```
1894/*
1895 * Fancy prints the given [string]
1896 *
1897 * @sample androidx.printer.samples.fancySample
1898 */
1899fun fancyPrint(str: String) ...
1900```
1901
1902**Sample function:**
1903
1904```
1905package androidx.printer.samples
1906
1907import androidx.printer.fancyPrint
1908
1909@Sampled
1910fun fancySample() {
1911 fancyPrint("Fancy!")
1912}
1913```
1914
1915**Generated documentation visible on d.android.com\***
1916
1917```
1918fun fancyPrint(str: String)
1919
1920Fancy prints the given [string]
1921
1922<code>
1923 import androidx.printer.fancyPrint
1924
1925 fancyPrint("Fancy!")
1926<code>
1927```
1928
1929\**still some improvements to be made to DAC side, such as syntax highlighting*
1930
1931### Module configuration
1932
1933The following module setups should be used for sample functions, and are
1934enforced by lint:
1935
1936**Group-level samples**
1937
1938For library groups with strongly related samples that want to share code.
1939
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001940Gradle project name: `:foo-library:foo-library-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001941
1942```
1943foo-library/
1944 foo-module/
1945 bar-module/
1946 samples/
1947```
1948
1949**Per-module samples**
1950
1951For library groups with complex, relatively independent sub-libraries
1952
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001953Gradle project name: `:foo-library:foo-module:foo-module-samples`
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001954
1955```
1956foo-library/
1957 foo-module/
1958 samples/
1959```
AndroidX Core Team0db91f02021-05-06 22:45:18 +00001960
1961**Samples module configuration**
1962
1963Samples modules are published to GMaven so that they are available to Android
1964Studio, which displays code in @Sample annotations as hover-over pop-ups.
1965
1966To achieve this, samples modules must declare the same MavenGroup and `publish`
1967as the library(s) they are samples for.