blob: 6de4d8ba758941ff0231ba46bf14c51a7eec630a [file] [log] [blame]
Billy Lamberta9fec73a2016-05-19 14:27:49 -07001page.title=Set up Managed Configurations
2page.metaDescription=Learn how to implement managed configurations that can be changed by other apps on the same device.
3page.image=images/work/cards/briefcase_600px.png
4
5@jd:body
6
7<div id="qv-wrapper">
8 <div id="qv">
9 <h2>In this document</h2>
10 <ol>
11 <li><a href="#define-configuration">Define Managed Configurations</a></li>
12 <li><a href="#check-configuration">Check Managed Configurations</a></li>
13 <li><a href="#listen-configuration">Listen for Managed Configuration Changes</a></li>
14 </ol>
15 </div>
16</div>
17
18<p>
19 If you are developing apps for the enterprise market, you may need
20 to satisfy particular requirements set by a company's policies.
21 Managed configurations, previously known as <em>application restrictions</em>,
22 allow the enterprise administrator to remotely specify settings for
23 apps. This capability is particularly useful for enterprise-approved
24 apps deployed to a managed profile.
25</p>
26
27<p>For example, an enterprise might require that approved apps allow the
28enterprise administrator to:</p>
29
30<ul>
31 <li>Whitelist or blacklist URLs for a web browser</li>
32 <li>Configure whether an app is allowed to sync content via cellular, or just
33 by Wi-Fi</li>
34 <li>Configure the app's email settings</li>
35</ul>
36
37<p>
Billy Lambertaef574982016-07-11 13:13:56 -070038 This guide shows how to implement managed configuration settings in
39 your app. If you're an EMM developer, refer to the
40 <a href="https://developers.google.com/android/work/build-dpc"
41 >Build a Device Policy Controller</a> guide.
Billy Lamberta9fec73a2016-05-19 14:27:49 -070042</p>
43
44<p class="note">
45 <strong>Note:</strong> For historical reasons, these configuration settings are known as
46 <em>restrictions,</em> and are implemented with files and classes that use this
47 term (such as {@link android.content.RestrictionsManager}). However, these
48 restrictions can actually implement a wide range of configuration options,
49 not just restrictions on app functionality.
50</p>
51
52<h2 id="overview">
53 Remote Configuration Overview
54</h2>
55
56<p>
57 Apps define the managed configuration options that can be remotely
58 set by an administrator. These are arbitrary settings that can be
59 changed by a managed configuration provider. If your app is running on an
60 enterprise device's managed profile, the enterprise administrator
61 can change your app's managed configuration.
62</p>
63
64<p>
65 The managed configurations provider is another app running on the same device.
66 This app is typically controlled by the enterprise administrator. The
67 enterprise administrator communicates configuration changes to the managed
68 configuration provider app. That app, in turn, changes the configurations on your app.
69</p>
70
71<p>
72 To provide externally managed configurations:
73</p>
74
75<ul>
76 <li>Declare the managed configurations in your app manifest. Doing
Billy Lambertaef574982016-07-11 13:13:56 -070077 so allows the enterprise administrator to read the app's
78 configurations through Google Play APIs.
Billy Lamberta9fec73a2016-05-19 14:27:49 -070079 </li>
80
81 <li>Whenever the app resumes, use the {@link
82 android.content.RestrictionsManager} object to check the current
83 managed configurations, and change your app's UI and behavior to
84 conform with those configurations.
85 </li>
86
87 <li>Listen for the
Billy Lambertaef574982016-07-11 13:13:56 -070088 {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
89 ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
90 broadcast, check the {@link android.content.RestrictionsManager} to see what
91 the current managed configurations are, and make any necessary changes to your
92 app's behavior.
Billy Lamberta9fec73a2016-05-19 14:27:49 -070093 </li>
94</ul>
95
96<h2 id="define-configuration">
97 Define Managed Configurations
98</h2>
99
100<p>
101 Your app can support any managed configuration you want to define. You declare the
Billy Lambertaef574982016-07-11 13:13:56 -0700102 app's managed configurations in a <em>managed configurations file</em>, and declare
103 the configurations file in the manifest. Creating a configurations file allows
104 other apps to examine the managed configurations your app provides. Enterprise
105 Mobility Management (EMM) partners can read your app's configurations by using
106 Google Play APIs.
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700107</p>
108
109<p>
110 To define your app's remote configuration options, put the following element
111 in your manifest's
112 <a href="{@docRoot}guide/topics/manifest/application-element.html">
113 <code>&lt;application&gt;</code></a> element:
114</p>
115
116<pre>&lt;meta-data android:name="android.content.APP_RESTRICTIONS"
117 android:resource="@xml/app_restrictions" /&gt;
118</pre>
119
120<p>
121 Create a file named <code>app_restrictions.xml</code> in your app's
122 <code>res/xml</code> directory. The structure of that file is described in
123 the reference for {@link android.content.RestrictionsManager}. The file has a
124 single top-level <code>&lt;restrictions&gt;</code> element, which contains
125 one <code>&lt;restriction&gt;</code> child element for every configuration
126 option the app has.
127</p>
128
129<p class="note">
130 <strong>Note:</strong> Do not create localized versions of the
131 managed configuration file. Your app is only allowed to have a
132 single managed configurations file, so configurations will be
133 consistent for your app in all locales.
134</p>
135
136<p>
137 In an enterprise environment, an EMM will typically use the managed
138 configuration schema to generate a remote console for IT
139 administrators, so the administrators can remotely configure your
140 application.
141</p>
142
143<p>
Billy Lambertaef574982016-07-11 13:13:56 -0700144 The managed configuration provider can query the app to find details
145 on the app's available configurations, including their description
146 text. The configurations provider and enterprise administrator can
147 change your app's managed configurations at any time, even when the
148 app is not running.
149</p>
150
151<p>
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700152 For example, suppose your app can be remotely configured to allow or forbid
153 it to download data over a cellular connection. Your app could have a
154 <code>&lt;restriction&gt;</code> element like this:
155</p>
156
157<pre>
158&lt;?xml version="1.0" encoding="utf-8"?&gt;
Billy Lambertaef574982016-07-11 13:13:56 -0700159&lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android"&gt;
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700160
161 &lt;restriction
162 android:key="downloadOnCellular"
Billy Lambertad6aa41d2016-07-07 10:54:30 -0700163 android:title="@string/download_on_cell_title"
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700164 android:restrictionType="bool"
Billy Lambertad6aa41d2016-07-07 10:54:30 -0700165 android:description="@string/download_on_cell_description"
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700166 android:defaultValue="true" /&gt;
167
168&lt;/restrictions&gt;
169</pre>
170
171<p>
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700172 You use each configuration's <code>android:key</code> attribute to
173 read its value from a managed configuration bundle. For this reason,
174 each configuration must have a unique key string, and the string
175 <em>cannot</em> be localized. It must be specified with a string literal.
176</p>
177
178<p class="note">
179 <strong>Note:</strong> In a production app, <code>android:title</code> and
180 <code>android:description</code> should be drawn from a localized resource
Billy Lambertaef574982016-07-11 13:13:56 -0700181 file, as described in
182 <a href="{@docRoot}guide/topics/resources/localization.html"
183 >Localizing with Resources</a>.
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700184</p>
185
Billy Lambertaef574982016-07-11 13:13:56 -0700186<p id="nested-restrictions">
187 An app can define one or multiple nested restriction elements using
188 the restriction types
189 {@link android.content.RestrictionEntry#TYPE_BUNDLE bundle} and
190 {@link android.content.RestrictionEntry#TYPE_BUNDLE_ARRAY bundle_array}.
191 For example, an app with multiple VPN connection options could define
192 each VPN server configuration in a bundle, with multiple bundles grouped
193 together in a bundle array:
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700194</p>
195
Billy Lambertaef574982016-07-11 13:13:56 -0700196<pre>
197&lt;?xml version="1.0" encoding="utf-8"?&gt;
198&lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android" &gt;
199
200 &lt;restriction
201 android:key="vpn_configuration_list"
202 android:restrictionType="bundle_array"&gt;
203 &lt;restriction
204 android:key="vpn_configuration"
205 android:restrictionType="bundle"&gt;
206 &lt;restriction
207 android:key="vpn_server"
208 android:restrictionType="string"/&gt;
209 &lt;restriction
210 android:key="vpn_username"
211 android:restrictionType="string"/&gt;
212 &lt;restriction
213 android:key="vpn_password"
214 android:restrictionType="string"/&gt;
215 &lt;/restriction&gt;
216 &lt;/restriction&gt;
217
218&lt;/restrictions&gt;
219</pre>
220
221<p>
222 The supported types for the <code>android:restrictionType</code> element
223 are listed in <a href="#restriction-types">Table 1</a> and documented in
224 the reference for {@link android.content.RestrictionsManager} and
225 {@link android.content.RestrictionEntry}.
226</p>
227
228<p class="table-caption" id="restriction-types">
229 <strong>Table 1.</strong> Restriction entry types and usage.
230</p>
231<table>
232 <tbody>
233 <tr>
234 <th>Type</th>
235 <th>android:restrictionType</th>
236 <th>Typical usage</th>
237 </tr>
238 <tr>
239 <td>
240 {@link android.content.RestrictionEntry#TYPE_BOOLEAN TYPE_BOOLEAN}
241 </td>
242 <td><code>"bool"</code></td>
243 <td>
244 A boolean value, true or false.
245 </td>
246 </tr>
247 <tr>
248 <td>
249 {@link android.content.RestrictionEntry#TYPE_STRING TYPE_STRING}
250 </td>
251 <td><code>"string"</code></td>
252 <td>
253 A string value, such as a name.
254 </td>
255 </tr>
256 <tr>
257 <td>
258 {@link android.content.RestrictionEntry#TYPE_INTEGER TYPE_INTEGER}
259 </td>
260 <td><code>"integer"</code></td>
261 <td>
262 An integer with a value from
263 {@link java.lang.Integer#MIN_VALUE MIN_VALUE} to
264 {@link java.lang.Integer#MAX_VALUE MAX_VALUE}.
265 </td>
266 </tr>
267 <tr>
268 <td>
269 {@link android.content.RestrictionEntry#TYPE_CHOICE TYPE_CHOICE}
270 </td>
271 <td><code>"choice"</code></td>
272 <td>
273 A string value, typically presented as a single-select list.
274 </td>
275 </tr>
276 <tr>
277 <td>
278 {@link android.content.RestrictionEntry#TYPE_MULTI_SELECT TYPE_MULTI_SELECT}
279 </td>
280 <td><code>"multi-select"</code></td>
281 <td>
282 Use this for presenting a multi-select list where more than
283 one entry can be selected, such as for choosing specific
284 titles to white-list.
285 </td>
286 </tr>
287 <tr>
288 <td>
289 {@link android.content.RestrictionEntry#TYPE_NULL TYPE_NULL}
290 </td>
291 <td><code>"hidden"</code></td>
292 <td>
293 Hidden restriction type. Use this type for information that
294 needs to be transferred across but shouldn't be presented to
295 the user in the UI. Stores a single string value.
296 </td>
297 </tr>
298 <tr>
299 <td>{@link android.content.RestrictionEntry#TYPE_BUNDLE TYPE_BUNDLE}</td>
300 <td><code>"bundle"</code></td>
301 <td>
302 Use this for storing {@link android.os.Bundle bundles} of
303 restrictions. Available in Android 6.0 (API level 23).
304 </td>
305 </tr>
306 <tr>
307 <td>
308 {@link android.content.RestrictionEntry#TYPE_BUNDLE_ARRAY TYPE_BUNDLE_ARRAY}
309 </td>
310 <td><code>"bundle_array"</code></td>
311 <td>
312 Use this for storing arrays of restriction
313 <a href="{@docRoot}reference/android/os/Bundle.html"
314 >bundles</a>. Available in Android 6.0 (API level 23).
315 </td>
316 </tr>
317 </tbody>
318</table>
319
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700320<h2 id="check-configuration">
321 Check Managed Configurations
322</h2>
323
324<p>
325 Your app is not automatically notified when other apps change its
326 configuration settings. Instead, you need to check what the managed
327 configurations are when your app starts or resumes, and listen for a
328 system intent to find out if the configurations change while your
329 app is running.
330</p>
331
332<p>
333 To find out the current configuration settings, your app uses a
334 {@link android.content.RestrictionsManager} object. Your app should
335 check for the current managed configurations at the following times:
336</p>
337
338<ul>
339 <li>When the app starts or resumes, in its
340 {@link android.app.Activity#onResume onResume()} method
341 </li>
342
343 <li>When the app is notified of a configuration change, as described in
344 <a href="#listen-configuration">Listen for Managed Configuration
345 Changes</a>
346 </li>
347</ul>
348
349<p>
350 To get a {@link android.content.RestrictionsManager} object, get the current
351 activity with {@link android.app.Fragment#getActivity getActivity()}, then
Elliot Waite7c70fed2016-09-21 15:47:30 -0700352 call that activity's {@link android.app.Activity#getSystemService
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700353 Activity.getSystemService()} method:
354</p>
355
356<pre>RestrictionsManager myRestrictionsMgr =
357 (RestrictionsManager) getActivity()
358 .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
359
360<p>
361 Once you have a {@link android.content.RestrictionsManager}, you can get the
362 current configuration settings by calling its
363 {@link android.content.RestrictionsManager#getApplicationRestrictions
364 getApplicationRestrictions()} method:
365</p>
366
367<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
368
369<p class="note">
370 <strong>Note:</strong> For convenience, you can also fetch the current
371 configurations with a {@link android.os.UserManager}, by calling
372 {@link android.os.UserManager#getApplicationRestrictions
373 UserManager.getApplicationRestrictions()}. This method behaves exactly the
374 same as {@link android.content.RestrictionsManager#getApplicationRestrictions
375 RestrictionsManager.getApplicationRestrictions()}.
376</p>
377
378<p>
379 The {@link android.content.RestrictionsManager#getApplicationRestrictions
380 getApplicationRestrictions()} method requires reading from data storage, so
381 it should be done sparingly. Do not call this method every time you need to
382 know the current configuration. Instead, you should call it once when your app
383 starts or resumes, and cache the fetched managed configurations bundle. Then listen
384 for the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
385 ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if the configuration
386 change while your app is active, as described in
387 <a href="#listen-configuration">Listen for Managed Configuration Changes</a>.
388</p>
389
390<h3 id="read-configurations">
391 Reading and applying managed configurations
392</h3>
393
394<p>
395 The {@link android.content.RestrictionsManager#getApplicationRestrictions
396 getApplicationRestrictions()} method returns a {@link android.os.Bundle}
397 containing a key-value pair for each configuration that has been set. The
398 values are all of type <code>Boolean</code>, <code>int</code>,
399 <code>String</code>, and <code>String[]</code>. Once you have the
400 managed configurations {@link android.os.Bundle}, you can check the current
401 configuration settings with the standard {@link android.os.Bundle} methods for
Elliot Waite7c70fed2016-09-21 15:47:30 -0700402 those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700403 or
Elliot Waite7c70fed2016-09-21 15:47:30 -0700404 {@link android.os.Bundle#getString getString()}.
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700405</p>
406
407<p class="note">
408 <strong>Note:</strong> The managed configurations {@link android.os.Bundle}
409 contains one item for every configuration that has been explicitly set by a
410 managed configurations provider. However, you <em>cannot</em> assume that a
411 configuration will be present in the bundle just because you defined a default
412 value in the managed configurations XML file.
413</p>
414
415<p>
416 It is up to your app to take appropriate action based on the current
417 managed configuration settings. For example, if your app has a
418 configuration specifying whether it can download data over a
419 cellular connection, and you find that the configuration is set to
420 <code>false</code>, you would have to disable data download except when
421 the device has a Wi-Fi connection, as shown in the following example code:
422</p>
423
424<pre>
425boolean appCanUseCellular;
426
Billy Lambertaef574982016-07-11 13:13:56 -0700427if (appRestrictions.containsKey("downloadOnCellular")) {
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700428 appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
429} else {
Billy Lambertaef574982016-07-11 13:13:56 -0700430 // cellularDefault is a boolean using the restriction's default value
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700431 appCanUseCellular = cellularDefault;
432}
433
434if (!appCanUseCellular) {
435 // ...turn off app's cellular-download functionality
436 // ...show appropriate notices to user
437}</pre>
438
Billy Lambertaef574982016-07-11 13:13:56 -0700439<p>
440 To apply multiple <a href="#nested-restrictions">nested restrictions</a>, read
441 the {@link android.content.RestrictionEntry#TYPE_BUNDLE_ARRAY bundle_array}
442 restriction entry as a collection of {@link android.os.Parcelable} objects
443 and cast as a {@link android.os.Bundle}. In this example, each VPN's configuration
444 data is parsed and used to build a list of server connection choices:
445</p>
446
447<pre>
448// VpnConfig is a sample class used store config data, not defined
449List&lt;VpnConfig&gt; vpnConfigs = new ArrayList&lt;&gt;();
450
451Parcelable[] parcelables =
452 appRestrictions.getParcelableArray("vpn_configuration_list");
453
454if (parcelables != null && parcelables.length > 0) {
455 // iterate parcelables and cast as bundle
456 for (int i = 0; i < parcelables.length; i++) {
457 Bundle vpnConfigBundle = (Bundle) parcelables[i];
458 // parse bundle data and store in VpnConfig array
459 vpnConfigs.add(new VpnConfig()
460 .setServer(vpnConfigBundle.getString("vpn_server"))
461 .setUsername(vpnConfigBundle.getString("vpn_username"))
462 .setPassword(vpnConfigBundle.getString("vpn_password")));
463 }
464}
465
466if (!vpnConfigs.isEmpty()) {
467 // ...choose a VPN configuration or prompt user to select from list
468}</pre>
469
Billy Lamberta9fec73a2016-05-19 14:27:49 -0700470<h2 id="listen-configuration">
471 Listen for Managed Configuration Changes
472</h2>
473
474<p>
475 Whenever an app's managed configurations are changed, the system fires the
476 {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
477 ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
478 this intent so you can change the app's behavior when the configuration settings
479 change.</p>
480
481<p class="note">
482 <strong>Note:</strong> The {@link
483 android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
484 ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent is sent only to listeners
485 that are dynamically registered, <em>not</em> to listeners that are declared
486 in the app manifest.
487</p>
488<p>
489 The following code shows how to dynamically register a broadcast receiver for
490 this intent:
491</p>
492
493<pre>IntentFilter restrictionsFilter =
494 new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
495
496BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
497 &#64;Override public void onReceive(Context context, Intent intent) {
498
499 // Get the current configuration bundle
500 Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
501
502 // Check current configuration settings, change your app's UI and
503 // functionality as necessary.
504 }
505};
506
507registerReceiver(restrictionsReceiver, restrictionsFilter);
508</pre>
509<p class="note">
510 <strong>Note:</strong> Ordinarily, your app does not need to be notified
511 about configuration changes when it is paused. Instead, you should unregister
512 your broadcast receiver when the app is paused. When the app resumes, you
513 first check for the current managed configurations (as discussed in
514 <a href="#check-configuration">Check Managed Configurations</a>), then register
515 your broadcast receiver to make sure you're notified about configuration changes
516 that happen while the app is active.
517</p>