1page.title=Implementing App Restrictions
2page.metaDescription=Learn how to implement app restrictions and configuration settings that can be changed by other apps on the same device.
3@jd:body
4
5<div id="tb-wrapper">
6<div id="tb">
7
8<h2>This lesson teaches you to</h2>
9<ol>
10 <li><a href="#define_restrictions">Define App Restrictions</a></li>
11 <li><a href="#check_restrictions">Check App Restrictions</a></li>
12 <li><a href="#listen">Listen for App Restriction Changes</a></li>
13</ol>
14
15<!-- related docs (NOT javadocs) -->
16<h2>Resources</h2>
17<ul>
18  <li><a href="{@docRoot}samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a>
19    sample app</li>
20  <li><a href="{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
21    sample app</li>
22</ul>
23
24</div>
25</div>
26
27<p>If you are developing apps for the enterprise market, you may need to satisfy
28particular requirements set by a company's policies. Application restrictions
29allow the enterprise administrator to remotely specify settings for apps.
30This capability is particularly useful for enterprise-approved apps deployed to
31a managed profile.</p>
32
33<p>For example, an enterprise might require that approved apps allow the
34enterprise administrator to:</p>
35
36<ul>
37  <li>Whitelist or blacklist URLs for a web browser</li>
38  <li>Configure whether an app is allowed to sync content via cellular, or just
39    by Wi-Fi</li>
40  <li>Configure the app's email settings</li>
41</ul>
42
43<p>
44  This guide shows how to implement these configuration settings in your app.
45</p>
46
47<p class="note">
48  <strong>Note:</strong> For historical reasons, these configuration settings are known as
49  <em>restrictions,</em> and are implemented with files and classes that use this
50  term (such as {@link android.content.RestrictionsManager}). However, these
51  restrictions can actually implement a wide range of configuration options,
52  not just restrictions on app functionality.
53</p>
54
55<h2 id="overview">
56  Remote Configuration Overview
57</h2>
58
59<p>
60  Apps define the restrictions and configuration options that can be remotely
61  set by an administrator. These restrictions are
62  arbitrary configuration settings that can be changed by a restrictions
63  provider. If your app is running on an enterprise device's managed
64  profile, the enterprise administrator can change your app's restrictions.
65</p>
66
67<p>
68  The restrictions provider is another app running on the same device.
69  This app is typically controlled by the enterprise administrator. The
70  enterprise administrator communicates restriction changes to the restrictions
71  provider app. That app, in turn, changes the restrictions on your app.
72</p>
73
74<p>
75  To provide externally configurable restrictions:
76</p>
77
78<ul>
79  <li>Declare the restrictions in your app manifest. Doing so allows the
80  enterprise administrator to read the app's restrictions through Google
81  Play APIs.
82  </li>
83
84  <li>Whenever the app resumes, use the {@link
85    android.content.RestrictionsManager} object to check the current
86    restrictions, and change your app's UI and behavior to conform with those
87    restrictions.
88  </li>
89
90  <li>Listen for the
91  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
92  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
93  broadcast, check the {@link android.content.RestrictionsManager} to see what
94  the current restrictions are, and make any necessary changes to your app's
95  behavior.
96  </li>
97</ul>
98
99<h2 id="define_restrictions">
100  Define App Restrictions
101</h2>
102
103<p>
104  Your app can support any restrictions you want to define. You declare the
105  app's restrictions in a <em>restrictions file</em>, and declare the
106  restrictions file in the manifest. Creating a restrictions file allows other
107  apps to examine the restrictions your app provides. Enterprise Mobility
108  Management (EMM) partners can read your app's restrictions by using Google
109  Play APIs.
110</p>
111
112<p>
113  To define your app's remote configuration options, put the following element
114  in your manifest's
115  <a href="{@docRoot}guide/topics/manifest/application-element.html">
116  <code>&lt;application&gt;</code></a> element:
117</p>
118
119<pre>&lt;meta-data android:name="android.content.APP_RESTRICTIONS"
120    android:resource="@xml/app_restrictions" /&gt;
121</pre>
122
123<p>
124  Create a file named <code>app_restrictions.xml</code> in your app's
125  <code>res/xml</code> directory. The structure of that file is described in
126  the reference for {@link android.content.RestrictionsManager}. The file has a
127  single top-level <code>&lt;restrictions&gt;</code> element, which contains
128  one <code>&lt;restriction&gt;</code> child element for every configuration
129  option the app has.
130</p>
131
132<p class="note">
133  <strong>Note:</strong> Do not create localized versions of the restrictions
134  file. Your app is only allowed to have a single restrictions file,
135  so restrictions will be consistent for your app in all locales.
136</p>
137
138<p>
139  In an enterprise environment, an EMM will typically use the restrictions
140  schema to generate a remote console for IT administrators, so the
141  administrators can remotely configure your application.
142</p>
143
144<p>
145  For example, suppose your app can be remotely configured to allow or forbid
146  it to download data over a cellular connection. Your app could have a
147  <code>&lt;restriction&gt;</code> element like this:
148</p>
149
150<pre>
151&lt;?xml version="1.0" encoding="utf-8"?&gt;
152&lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android" &gt;
153
154  &lt;restriction
155    android:key="downloadOnCellular"
156    android:title="App is allowed to download data via cellular"
157    android:restrictionType="bool"
158    android:description="If 'false', app can only download data via Wi-Fi"
159    android:defaultValue="true" /&gt;
160
161&lt;/restrictions&gt;
162</pre>
163
164<p>
165  The supported types for the <code>android:restrictionType</code> element are
166  documented in the reference for {@link android.content.RestrictionsManager}.
167</p>
168
169<p>
170  You use each restriction's <code>android:key</code> attribute to read its
171  value from a restrictions bundle. For this reason, each restriction must have
172  a unique key string, and the string <em>cannot</em> be localized. It must be
173  specified with a string literal.
174</p>
175
176<p class="note">
177  <strong>Note:</strong> In a production app, <code>android:title</code> and
178  <code>android:description</code> should be drawn from a localized resource
179  file, as described in <a href=
180  "{@docRoot}guide/topics/resources/localization.html">Localizing with
181  Resources</a>.
182</p>
183
184<p>
185  The restrictions provider can query the app to find details on the app's
186  available restrictions, including their description text. Restrictions
187  providers and enterprise administrators can change your app's restrictions at
188  any time, even when the app is not running.
189</p>
190
191<h2 id="check_restrictions">
192  Check App Restrictions
193</h2>
194
195<p>
196  Your app is not automatically notified when other apps change its restriction
197  settings. Instead, you need to check what the restrictions are when your app
198  starts or resumes, and listen for a system intent to find out if the
199  restrictions change while your app is running.
200</p>
201
202<p>
203  To find out the current restriction settings, your app uses a {@link
204  android.content.RestrictionsManager} object. Your app should check for the
205  current restrictions at the following times:
206</p>
207
208<ul>
209  <li>When the app starts or resumes, in its
210  {@link android.app.Activity#onResume onResume()} method
211  </li>
212
213  <li>When the app is notified of a restriction change, as described in
214    <a href="#listen">Listen for Device Configuration
215    Changes</a>
216  </li>
217</ul>
218
219<p>
220  To get a {@link android.content.RestrictionsManager} object, get the current
221  activity with {@link android.app.Fragment#getActivity getActivity()}, then
222  call that activity's {@link android.app.Activity#getSystemService
223  Activity.getSystemService()} method:
224</p>
225
226<pre>RestrictionsManager myRestrictionsMgr =
227    (RestrictionsManager) getActivity()
228        .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
229
230<p>
231  Once you have a {@link android.content.RestrictionsManager}, you can get the current restrictions
232  settings by calling its
233  {@link android.content.RestrictionsManager#getApplicationRestrictions
234  getApplicationRestrictions()} method:
235</p>
236
237<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
238
239<p class="note">
240  <strong>Note:</strong> For convenience, you can also fetch the current
241  restrictions with a {@link android.os.UserManager}, by calling {@link
242  android.os.UserManager#getApplicationRestrictions
243  UserManager.getApplicationRestrictions()}. This method behaves exactly the
244  same as {@link android.content.RestrictionsManager#getApplicationRestrictions
245  RestrictionsManager.getApplicationRestrictions()}.
246</p>
247
248<p>
249  The {@link android.content.RestrictionsManager#getApplicationRestrictions
250  getApplicationRestrictions()} method requires reading from data storage, so
251  it should be done sparingly. Do not call this method every time you need to
252  know the current restrictions. Instead, you should call it once when your app
253  starts or resumes, and cache the fetched restrictions bundle. Then listen for
254  the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
255  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
256  change while your app is active, as described in <a href="#listen">Listen for
257  Device Configuration Changes</a>.
258</p>
259
260<h3 id="read_restrictions">
261  Reading and applying restrictions
262</h3>
263
264<p>
265  The {@link android.content.RestrictionsManager#getApplicationRestrictions
266  getApplicationRestrictions()} method returns a {@link android.os.Bundle}
267  containing a key-value pair for each restriction that has been set. The
268  values are all of type <code>Boolean</code>, <code>int</code>,
269  <code>String</code>, and <code>String[]</code>. Once you have the
270  restrictions {@link android.os.Bundle}, you can check the current
271  restrictions settings with the standard {@link android.os.Bundle} methods for
272  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
273  or
274  {@link android.os.Bundle#getString getString()}.
275</p>
276
277<p class="note">
278  <strong>Note:</strong> The restrictions {@link android.os.Bundle} contains
279  one item for every restriction that has been explicitly set by a restrictions
280  provider. However, you <em>cannot</em> assume that a restriction will be
281  present in the bundle just because you defined a default value in the
282  restrictions XML file.
283</p>
284
285<p>
286  It is up to your app to take appropriate action based on the current
287  restrictions settings. For example, if your app has a restriction specifying
288  whether it can download data over a cellular connection, and you find that
289  the restriction is set to <code>false</code>, you would have to disable data
290  download except when the device has a Wi-Fi connection, as shown in the
291  following example code:
292</p>
293
294<pre>
295boolean appCanUseCellular;
296
297if appRestrictions.containsKey("downloadOnCellular") {
298    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
299} else {
300    // here, cellularDefault is a boolean set with the restriction's
301    // default value
302    appCanUseCellular = cellularDefault;
303}
304
305if (!appCanUseCellular) {
306    // ...turn off app's cellular-download functionality
307    // ...show appropriate notices to user
308}</pre>
309
310<h2 id="listen">
311  Listen for App Restriction Changes
312</h2>
313
314<p>
315  Whenever an app's restrictions are changed, the system fires the
316  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
317  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
318  this intent so you can change the app's behavior when the restriction settings
319  change.</p>
320
321<p class="note">
322  <strong>Note:</strong> The {@link
323  android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
324  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent is sent only to listeners
325  that are dynamically registered, <em>not</em> to listeners that are declared
326  in the app manifest.
327</p>
328<p>
329  The following code shows how to dynamically register a broadcast receiver for
330  this intent:
331</p>
332
333<pre>IntentFilter restrictionsFilter =
334    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
335
336BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
337  &#64;Override public void onReceive(Context context, Intent intent) {
338
339    // Get the current restrictions bundle
340    Bundle <code>appRestrictions</code> =
341
342    myRestrictionsMgr.getApplicationRestrictions();
343
344    // Check current restrictions settings, change your app's UI and
345    // functionality as necessary.
346
347  }
348
349};
350
351registerReceiver(restrictionsReceiver, restrictionsFilter);
352</pre>
353<p class="note">
354  <strong>Note:</strong> Ordinarily, your app does not need to be notified
355  about restriction changes when it is paused. Instead, you should unregister
356  your broadcast receiver when the app is paused. When the app resumes, you
357  first check for the current restrictions (as discussed in <a href=
358  "#check_restrictions">Check Device Restrictions</a>), then register your
359  broadcast receiver to make sure you're notified about restriction changes
360  that happen while the app is active.
361</p>
362