Package org.opencabstandard.provider

This package contains the Java interface files that define the contracts for OpenCab providers, the data types communicated to and from those providers, as well as abstract implementations that reduce the boilerplate code needed for an implementation.

You can propose changes or improvements to this documentation using GitHub.

1. Overview

An OpenCab provider is a mechanism for communicating between two Android apps running on the same device. One app will act as the OpenCab provider app and will contain an Android ContentProvider that implements the appropriate Contract class. The second app acts as the OpenCab consumer app and will make calls to the ContentProvider supplied by the provider app.

The Contract and Abstract classes can be found in source code for this package. You should add these relevant classes to your Android project.

For example, an app that will be an OpenCab Identity provider will contain a ContentProvider that implements the IdentityContract. The OpenCab consumer app will make calls to the ContentProvider supplied by the OpenCab provider app. In this example the consumer app may use the results from ContentProvider to SSO into the consumer app with credentials from the provider app.

To aid in implementing the ContentProvider, we have created abstract implementations that handle much of the work for you. For the Identity provider, you may extend the AbstractIdentityProvider class as follows:

 
     public class MyIdentityProvider extends AbstractIdentityProvider {
          @Override
          public IdentityContract.LoginCredentials getLoginCredentials(String version) {
              // Your logic goes here
          }

          @Override
          public ArrayList<IdentityContract.Driver> getActiveDrivers(String version) {
              // Your logic goes here
          }
     }
 
 

An example sequence might be like the following:

sequenceDiagram participant A as OpenCab Consumer participant B as OpenCab Provider participant C as Consumer Auth Service A->>+B: provider.call(METHOD_GET_LOGIN_CREDENTIALS, version: "0.2") B->>A: KEY_VERSION="0.2"
KEY_LOGIN_CREDENTIALS=LoginCredentials{ authority="example" token="kf40m1fpl…d28zckhuf6" … } A->>C: Authentication request with token C->>A: Authentication response

2. Package visibility

Note: Provider declaration has been updated from previous versions of the specification to support multiple provider apps installed at once. See Section 6.2 "Compatibility with providers which predate Android enforcement of unique authority names" for details about how to support providers using the older approach.

In order to allow provider and consumer apps to communicate with each other on modern Android versions, participating apps must include certain declarations in AndroidManifest.xml. The specific declarations needed for providers and consumers are discussed in detail below.

3. Providers

3.1. Base requirements

Providers MUST declare an exported Android Service that handles the Intent action org.opencabstandard.PROVIDER:

 
   <service android:name=".OpenCabProviderService" android:exported="true">
     <intent-filter>
       <action android:name="org.opencabstandard.PROVIDER" />
     </intent-filter>
   </service>
  

The implementation of OpenCabProviderService SHOULD be empty:

 
 public class OpenCabProviderService extends IntentService {
   public OpenCabProviderService() { super("OpenCabProviderService"); }

   @Override protected void onHandleIntent(Intent intent) { // No-op }
 }
  

This service allows consumer implementations to declare their dependency on the provider app to Android, which then permits the consumer apps to see and interact with the provider package.

3.2. Manifest requirements for each implemented contract

For each contract, providers MUST declare their content providers using a unique authority formed using the app's package name. The format for this authority is {app package name}.{OpenCab authority}. For example, for the app com.example.app implementing the vehicle information provider contract, the following AndroidManifest.xml section would be necessary:

 
 <provider android:authorities="com.example.app.org.opencabstandard.vehicleinformation"
           android:exported="true"
           android:label="VehicleInformation"
           android:name="com.example.app.opencab.VehicleInformationProvider">
 </provider>
  

The package name prefix makes the authority unique among other providers installed on the same device, and the standard suffix makes the authority discoverable by potential consumer apps.

Providers MUST NOT declare an android:authorities attribute containing any of the org.opencabstandard.* authority strings . This is a change from previous versions of the specification—for details, see "Backwards compatibility with older versions."

3.3. Manifest requirements for broadcast intents

Providers that implement a contract (such as IdentityProvider) including broadcast intents MUST declare their desire to publish these events to Android using a queries block in AndroidManifest.xml:

 
  <queries>
    <intent>
      <action android:name="com.opencabstandard.VEHICLE_INFORMATION_CHANGED" />
    </intent>
  </queries>
  

This block signals to Android's internal package visibility protections that the provider intends to explicitly publish this event to other apps.

This block can be repeated as needed for each broadcast intent.

For an implementation example, see the sample provider app.

3.4. Publishing broadcast intents

When publishing a broadcast intent that is defined as part of a contract, all providers:

  1. MUST enumerate each visible package on the device. For each visible package, the provider MUST enumerate each receiver available on the PackageInfo receivers property and check if the receiver name ends with a period (“.”) followed by the receiver class name. For example, if package com.example defines a receiver called com.example.IdentityChangedReceiver and package net.subtle.foo.bar.IdentityChangedReceiver, a provider implementing the identity contract and broadcasting the ACTION_IDENTITY_INFORMATION_CHANGED event would send intents to both receiver classes.
  2. MUST publish events for each discovered receiver class by calling sendBroadcast with an explicit Intent with its component property set to the package and fully qualified class name of the enumerated receiver class. This ensures that apps which have been terminated, stopped, or updated since last launch will be started by the OS and given an opportunity to handle the event.

3.5. Backwards- and forwards-compatibility

To allow the specification to evolve without upgrading all participating apps in lockstep, both providers and consumers need to implement certain behavior to ensure compatibility when interacting with both older and newer apps.

Providers MUST examine the KEY_VERSION property of calls they receive and apply the following logic:

  1. If the consumer-requested version is lower than (see Versioning below) any supported contract version, the provider MUST return a value for KEY_ERROR.

    For example, if a consumer requests version 0.2 but the provider has only chosen to implement version 0.3 of the contract, the provider would populate KEY_ERROR with an explanatory message.

  2. If the consumer-requested version is one of the contract versions supported by the provider, the provider MUST return only the top-level Bundle keys defined in that version and MUST only return a response composed of the Parcelable data classes defined in that contract version. The provider MUST populate KEY_VERSION with the version of the contract matching the request. Providers MAY support an arbitrary number of older contract versions if desired.

    For example, if a consumer requests version 0.2 from a provider that supports both 0.3 and 0.2, the provider would return a response corresponding to version 0.2 of the contract, and it would set the KEY_VERSION property to be 0.2 to indicate it understood the older request and that the consumer should parse the response according to version 0.2 of the contract. It would be an error for the provider to return Bundle keys or parceled objects from newer versions of the contract than requested, as these are likely to cause errors when the consumer processes the response.

  3. If the consumer-requested version is higher than (see Versioning below) the newest supported contract version, the provider MUST behave as if the latest version it supports was requested instead. This includes setting the KEY_VERSION to match the returned data so that the newer consumer can determine that the provider only supports an older contract version and modify its behavior accordingly.

    For example, if a provider that supports version 0.2 and version 0.3 of a contract receives a request for version 0.5, the provider would return a response corresponding to version 0.3 of the contract, and it would set the KEY_VERSION property to be 0.3 to indicate it did not understand the request for a newer version and that the consumer SHOULD parse the response according to version 0.3 of the contract, or MAY treat the response as an error if the consumer does not wish to implement backwards compatibility.

  4. Versioning was formally introduced with version 0.3 of each contract. If the version parameter of a request made by a consumer is absent, the provider MUST treat the request as if the version were set to “0.2”.

4. Consumers

4.1. Base requirements

All consumer apps MUST indicate their participation in OpenCab with the following block in AndroidManifest.xml:

 <queries>
   <intent>
     <action android:name="org.opencabstandard.PROVIDER" />
   </intent>
 </queries> 

Consumer apps MAY enumerate and select provider(s) based on enumeration (using the Android PackageManager class) or runtime configuration.

4.2. Manifest requirements for broadcast intents

Consumer implementations MAY choose to register Android receivers for one or more broadcast intents. The declared receiver MUST list the names of the action(s) corresponding to the desired events. For example, an app that consumes identity information using the IdentityContract and wishes to receive an explicit broadcast intent upon login or logout might include the following in its AndroidManifest.xml:

 
 <receiver android:name="IdentityChangedReceiver"
           android:enabled="true"
           android:exported="true">
   <intent-filter>
     <action android:name="org.opencabstandard.ACTION_DRIVER_LOGIN" />
     <!-- `com.` is intentional to preserve compatibility with an earlier,
           erroenous version of the specification. -->
     <action android:name="com.opencabstandard.ACTION_DRIVER_LOGOUT" />
   </intent-filter>
 </receiver>
 

For an implementation example, see the sample consumer app.

4.3. Selecting and calling providers

To use or display the information available through a contract, a consumer must first select one or more providers which implement a supported version of that contract. When selecting a provider:

  1. Consumers MUST enumerate each visible package on the device. For each visible package, the provider MUST enumerate each provider available on the PackageInfo providers property and check if the provider authority ends with a period (“.”) followed by the fully-qualified contract name.

    For example, if package com.example defines a provider called com.example.org.opencabstandard.hos and package net.subtle.foo.bar.org.opencabstandard.hos, a consumer wishing to use or display HOS information MAY consider either or both applications as a source of data.

    However, a package biz.nobodyorg defining a provider called biz.nobodyorg.opencabstandard.hos would not be considered as a potential source of information because no period (“.”) is present before the fully-qualified contract name.

  2. Consumers MAY use the contract version set in KEY_VERSION (as distinct from the requested version) after making one or more calls to a provider as a factor in determining whether to continue to use the provider or whether to select an alternative provider instead.

    For example, if a consumer requests version 0.3 identity information but receives version 0.2 contract information in response, the consumer might choose to use another identity provider installed on the same device instead.

4.4. Backwards- and forwards-compatibility

  1. Consumers MUST set the version parameter of each call to match the latest version of the contract they support.
  2. Consumers MUST examine the KEY_VERSION present in the response and treat the response as an error if the version is higher than any version the consumer supports. For example, if a consumer requests version 0.3 but the provider is not compliant with section 3.5 and returns a 0.4 response, the consumer MUST detect this and treat it as an error.
  3. Consumers SHOULD support multiple response versions for backwards compatibility with older providers by examining the returned KEY_VERSION, keeping in mind that it may be lower than the requested version. For example, a provider might request version 0.3, but an older provider implementing the logic from section 3.5 might return a 0.2 response because that is the highest version of the contract it supports. The consumer MAY handle this response according to the version 0.2 definition, or it MAY treat the response as an error if backwards compatibility is not desired.
  4. Versioning was formally introduced with version 0.3 of each contract. If KEY_VERSION is absent from a provider’s response, the consumer MUST treat the response as if the version were set to “0.2”.

5. Security

At this time, limiting the exchange of data with another OpenCab-enabled app for reasons of privacy or security is left up to individual implementations. Providers and consumers MAY use OS-level mechanisms (such as ContentProvider.getCallingPackage()) to limit the exchange of data to packages that have been specifically permitted by an end user or customer.

6. Version compatibility

6.1. Version comparison

For correct behavior, OpenCab version strings must be compared logically, not lexically or numerically.

The comparison algorithm is identical to that defined in Semantic Versioning 2.0.0, Item 11.

6.2. Compatibility with providers which predate Android enforcement of unique authority names

Previous versions of the specification required apps to declare their ContentProvider with a specific android:authorities attribute containing a value such as org.opencabstandard.identity. Specifically, the specification read:

The OpenCab provider app must declare the ContentProviders in the manifest with dual authorities. One authority must match the OpenCab AUTHORITY in the appropriate Contract class and the second should be unique to the provider application. The OpenCab consumer app will identify the ContentProvider based on the OpenCab AUTHORITY, but then will use the second authority to make the call to the ContentProvider.

An example of the ContentProvider declared in the manifest:

 
 <provider android:authorities="org.opencabstandard.identity;com.myexample.identity"
           android:exported="true"
           android:label="identity"
           android:name="com.myexample.IdentityContentProvider"></provider>
  

However, since this configuration only allows one provider app of each type (identity, HOS, etc.) to be installed on a device at once, this style of declaration deprecated and no longer permitted. Provider implementations MUST NOT include one of the org.opencabstandard.* authorities. However, to enable newer consumer implementations to interoperate with older providers that predate this change, consumer implementations SHOULD fall back to enumerating and selecting a provider declaring one of these authorities. Consumer implementations MUST prefer a provider declared using the new, unique authority to one declared using the older format.

Consumer implementations SHOULD continue to include queries declarations in the Android manifest so that apps with an older provider implementation remain visible under the new Android package visibility rules. For example:

 
   <queries>
     <provider android:authorities="org.opencabstandard.hos" />
     <provider android:authorities="org.opencabstandard.identity" />
   </queries>
  

For a complete example, see the AndroidManifest.xml in the OpenCabConsumer sample app.

7. Compliance

This specification uses the phrases MUST, MUST NOT, MAY, SHOULD, and SHOULD NOT as defined in RFC 2119 to refer to functionality that is required for compliance or that is optional, suggested, or recommended.