This lesson teaches you to
Resources
- AppRestrictionSchema sample app
- AppRestrictionEnforcer sample app
If you are developing apps for the enterprise market, you may need to satisfy particular requirements set by a company's policies. Application restrictions allow the enterprise administrator to remotely specify settings for apps. This capability is particularly useful for enterprise-approved apps deployed to a managed profile.
For example, an enterprise might require that approved apps allow the enterprise administrator to:
- Whitelist or blacklist URLs for a web browser
- Configure whether an app is allowed to sync content via cellular, or just by Wi-Fi
- Configure the app's email settings
This guide shows how to implement these configuration settings in your app.
Note: For historical reasons, these configuration settings are known as
restrictions, and are implemented with files and classes that use this
term (such as RestrictionsManager
). However, these
restrictions can actually implement a wide range of configuration options,
not just restrictions on app functionality.
Remote Configuration Overview
Apps define the restrictions and configuration options that can be remotely set by an administrator. These restrictions are arbitrary configuration settings that can be changed by a restrictions provider. If your app is running on an enterprise device's managed profile, the enterprise administrator can change your app's restrictions.
The restrictions provider is another app running on the same device. This app is typically controlled by the enterprise administrator. The enterprise administrator communicates restriction changes to the restrictions provider app. That app, in turn, changes the restrictions on your app.
To provide externally configurable restrictions:
- Declare the restrictions in your app manifest. Doing so allows the enterprise administrator to read the app's restrictions through Google Play APIs.
- Whenever the app resumes, use the
RestrictionsManager
object to check the current restrictions, and change your app's UI and behavior to conform with those restrictions. - Listen for the
ACTION_APPLICATION_RESTRICTIONS_CHANGED
intent. When you receive this broadcast, check theRestrictionsManager
to see what the current restrictions are, and make any necessary changes to your app's behavior.
Define App Restrictions
Your app can support any restrictions you want to define. You declare the app's restrictions in a restrictions file, and declare the restrictions file in the manifest. Creating a restrictions file allows other apps to examine the restrictions your app provides. Enterprise Mobility Management (EMM) partners can read your app's restrictions by using Google Play APIs.
To define your app's remote configuration options, put the following element
in your manifest's
<application>
element:
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions" />
Create a file named app_restrictions.xml
in your app's
res/xml
directory. The structure of that file is described in
the reference for RestrictionsManager
. The file has a
single top-level <restrictions>
element, which contains
one <restriction>
child element for every configuration
option the app has.
Note: Do not create localized versions of the restrictions file. Your app is only allowed to have a single restrictions file, so restrictions will be consistent for your app in all locales.
In an enterprise environment, an EMM will typically use the restrictions schema to generate a remote console for IT administrators, so the administrators can remotely configure your application.
For example, suppose your app can be remotely configured to allow or forbid
it to download data over a cellular connection. Your app could have a
<restriction>
element like this:
<?xml version="1.0" encoding="utf-8"?> <restrictions xmlns:android="http://schemas.android.com/apk/res/android" > <restriction android:key="downloadOnCellular" android:title="App is allowed to download data via cellular" android:restrictionType="bool" android:description="If 'false', app can only download data via Wi-Fi" android:defaultValue="true" /> </restrictions>
The supported types for the android:restrictionType
element are
documented in the reference for RestrictionsManager
.
You use each restriction's android:key
attribute to read its
value from a restrictions bundle. For this reason, each restriction must have
a unique key string, and the string cannot be localized. It must be
specified with a string literal.
Note: In a production app, android:title
and
android:description
should be drawn from a localized resource
file, as described in Localizing with
Resources.
The restrictions provider can query the app to find details on the app's available restrictions, including their description text. Restrictions providers and enterprise administrators can change your app's restrictions at any time, even when the app is not running.
Check App Restrictions
Your app is not automatically notified when other apps change its restriction settings. Instead, you need to check what the restrictions are when your app starts or resumes, and listen for a system intent to find out if the restrictions change while your app is running.
To find out the current restriction settings, your app uses a RestrictionsManager
object. Your app should check for the
current restrictions at the following times:
- When the app starts or resumes, in its
onResume()
method - When the app is notified of a restriction change, as described in Listen for Device Configuration Changes
To get a RestrictionsManager
object, get the current
activity with getActivity()
, then
call that activity's Activity.getSystemService()
method:
RestrictionsManager myRestrictionsMgr = (RestrictionsManager) getActivity() .getSystemService(Context.RESTRICTIONS_SERVICE);
Once you have a RestrictionsManager
, you can get the current restrictions
settings by calling its
getApplicationRestrictions()
method:
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
Note: For convenience, you can also fetch the current
restrictions with a UserManager
, by calling UserManager.getApplicationRestrictions()
. This method behaves exactly the
same as RestrictionsManager.getApplicationRestrictions()
.
The getApplicationRestrictions()
method requires reading from data storage, so
it should be done sparingly. Do not call this method every time you need to
know the current restrictions. Instead, you should call it once when your app
starts or resumes, and cache the fetched restrictions bundle. Then listen for
the ACTION_APPLICATION_RESTRICTIONS_CHANGED
intent to find out if restrictions
change while your app is active, as described in Listen for
Device Configuration Changes.
Reading and applying restrictions
The getApplicationRestrictions()
method returns a Bundle
containing a key-value pair for each restriction that has been set. The
values are all of type Boolean
, int
,
String
, and String[]
. Once you have the
restrictions Bundle
, you can check the current
restrictions settings with the standard Bundle
methods for
those data types, such as getBoolean()
or
getString()
.
Note: The restrictions Bundle
contains
one item for every restriction that has been explicitly set by a restrictions
provider. However, you cannot assume that a restriction will be
present in the bundle just because you defined a default value in the
restrictions XML file.
It is up to your app to take appropriate action based on the current
restrictions settings. For example, if your app has a restriction specifying
whether it can download data over a cellular connection, and you find that
the restriction is set to false
, you would have to disable data
download except when the device has a Wi-Fi connection, as shown in the
following example code:
boolean appCanUseCellular; if appRestrictions.containsKey("downloadOnCellular") { appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular"); } else { // here, cellularDefault is a boolean set with the restriction's // default value appCanUseCellular = cellularDefault; } if (!appCanUseCellular) { // ...turn off app's cellular-download functionality // ...show appropriate notices to user }
Listen for App Restriction Changes
Whenever an app's restrictions are changed, the system fires the
ACTION_APPLICATION_RESTRICTIONS_CHANGED
intent. Your app has to listen for
this intent so you can change the app's behavior when the restriction settings
change.
Note: The ACTION_APPLICATION_RESTRICTIONS_CHANGED
intent is sent only to listeners
that are dynamically registered, not to listeners that are declared
in the app manifest.
The following code shows how to dynamically register a broadcast receiver for this intent:
IntentFilter restrictionsFilter =
new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// Get the current restrictions bundle
Bundle appRestrictions
=
myRestrictionsMgr.getApplicationRestrictions();
// Check current restrictions settings, change your app's UI and
// functionality as necessary.
}
};
registerReceiver(restrictionsReceiver, restrictionsFilter);
Note: Ordinarily, your app does not need to be notified about restriction changes when it is paused. Instead, you should unregister your broadcast receiver when the app is paused. When the app resumes, you first check for the current restrictions (as discussed in Check Device Restrictions), then register your broadcast receiver to make sure you're notified about restriction changes that happen while the app is active.