DEV Community

Cover image for About roles
Thomas Künneth
Thomas Künneth

Posted on

About roles

Sometimes it’s quite a task to stay updated in Androidverse. When Feb 10 brought a bunch of Jetpack news I stumbled upon Core-Role Version 1.0.0 which I had not on my agenda so far. I was even more surprised realizing roles were a topic in api level 29 😎

Time for a short piece.

The release notes say:

Added RoleManagerCompat containing the name and
documentation for roles that might be available in the
system.

Let's see what this RoleManagerCompat has up its sleeve. First a look at the docs:

This class contains the name and documentation for
roles that might be available in the system.

Yes, we knew that already.

The list of available roles might change with a system
app update, so apps should not make assumption about the
availability of roles. Instead, they should always check
if the role is available using
RoleManager.isRoleAvailable(String) before trying
to do anything with it.

Frankly, that did not enlighten me, either. Let's investigate. The source code starts like this:

RoleManagerCompat source code snippet

As it turns out, the whole class consists of constants representing a role, accompanied by a description of what an app must do in order to qualify for this role. Consider ROLE_BROWSER (the following screenshot is taken from the current docs):

Definition of ROLE_BROWSER

Now that we know what we need to do to be eligable holding this role - how do we acquire it? Please recall that when there is a XyzCompat class there is (almost) always a Xyz class. So, we do have android.app.role.RoleManager. It's available since api level 29. The docs say:

This class provides information about and manages roles.
A role is a unique name within the system associated with
certain privileges. The list of available roles might
change with a system app update, so apps should not make
assumption about the availability of roles. Instead, they
should always query if the role is available using
isRoleAvailable(java.lang.String) before trying to do
anything with it. Some predefined role names are available
as constants in this class, and a list of possibly
available roles can be found in the AndroidX Role library.

I know, you are tempted to say I knew that already.

There can be multiple applications qualifying for a role,
but only a subset of them can become role holders. To
qualify for a role, an application must meet certain
requirements, including defining certain components in its
manifest. These requirements can be found in the AndroidX
Libraries. Then the application will need user consent to
become a role holder, which can be requested using
Activity.startActivityForResult(Intent, int) with the
Intent obtained from
createRequestRoleIntent(java.lang.String).

Let's translate this into code:

package com.thomaskuenneth.roledemo

import android.app.role.RoleManager
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.role.RoleManagerCompat

private const val REQUEST_ROLE_BROWSER = 123

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    getSystemService(RoleManager::class.java)?.run {
      if (isRoleAvailable(RoleManagerCompat.ROLE_BROWSER)) {
        if (!isRoleHeld(RoleManagerCompat.ROLE_BROWSER)) {
          val intent = createRequestRoleIntent(RoleManagerCompat.ROLE_BROWSER)
          startActivityForResult(intent, REQUEST_ROLE_BROWSER)
        } else
          toast(R.string.has_role)
      } else toast(R.string.role_not_available)
    }
  }

  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_ROLE_BROWSER && resultCode == RESULT_OK) {
      toast(R.string.role_acquired)
    }
  }

  private fun toast(resId: Int) {
    Toast.makeText(baseContext, resId, Toast.LENGTH_SHORT).show()
  }
}
Enter fullscreen mode Exit fullscreen mode

So we get an instance of android.app.role.RoleManager by invoking getSystemService(). if isRoleHeld() returns true we are already in - we hold that role. If not, we need to knock at the door (ask the user) by calling createRequestRoleIntent() and startActivityForResult(). If the preconditions for acquiring a role are met the user will see something like this:

The app RoleDemo

Please recall to always invoke isRoleAvailable() and check if the systems offers the rol your app wants to acquire. To conclude this short piece, here is another important quote from the docs:

Upon becoming a role holder, the application may be granted
certain privileges that are role specific. When the
application loses its role, these privileges will also be
revoked.

This bears an interesting question: can the app ask the system to revoke a role? So far I have not spotted a corresponding function/method. Did you? What are your thoughts about roles? I'd love to hear opinion in the comments


source code

Top comments (0)