| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 1 | page.title=Set up Managed Configurations |
| 2 | page.metaDescription=Learn how to implement managed configurations that can be changed by other apps on the same device. |
| 3 | page.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 |
| 28 | enterprise 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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 38 | 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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 42 | </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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 77 | so allows the enterprise administrator to read the app's |
| 78 | configurations through Google Play APIs. |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 79 | </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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 88 | {@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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 93 | </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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 102 | 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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 107 | </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><application></code></a> element: |
| 114 | </p> |
| 115 | |
| 116 | <pre><meta-data android:name="android.content.APP_RESTRICTIONS" |
| 117 | android:resource="@xml/app_restrictions" /> |
| 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><restrictions></code> element, which contains |
| 125 | one <code><restriction></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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 144 | 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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 152 | 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><restriction></code> element like this: |
| 155 | </p> |
| 156 | |
| 157 | <pre> |
| 158 | <?xml version="1.0" encoding="utf-8"?> |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 159 | <restrictions xmlns:android="http://schemas.android.com/apk/res/android"> |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 160 | |
| 161 | <restriction |
| 162 | android:key="downloadOnCellular" |
| Billy Lamberta | d6aa41d | 2016-07-07 10:54:30 -0700 | [diff] [blame] | 163 | android:title="@string/download_on_cell_title" |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 164 | android:restrictionType="bool" |
| Billy Lamberta | d6aa41d | 2016-07-07 10:54:30 -0700 | [diff] [blame] | 165 | android:description="@string/download_on_cell_description" |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 166 | android:defaultValue="true" /> |
| 167 | |
| 168 | </restrictions> |
| 169 | </pre> |
| 170 | |
| 171 | <p> |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 172 | 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 Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 181 | file, as described in |
| 182 | <a href="{@docRoot}guide/topics/resources/localization.html" |
| 183 | >Localizing with Resources</a>. |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 184 | </p> |
| 185 | |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 186 | <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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 194 | </p> |
| 195 | |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 196 | <pre> |
| 197 | <?xml version="1.0" encoding="utf-8"?> |
| 198 | <restrictions xmlns:android="http://schemas.android.com/apk/res/android" > |
| 199 | |
| 200 | <restriction |
| 201 | android:key="vpn_configuration_list" |
| 202 | android:restrictionType="bundle_array"> |
| 203 | <restriction |
| 204 | android:key="vpn_configuration" |
| 205 | android:restrictionType="bundle"> |
| 206 | <restriction |
| 207 | android:key="vpn_server" |
| 208 | android:restrictionType="string"/> |
| 209 | <restriction |
| 210 | android:key="vpn_username" |
| 211 | android:restrictionType="string"/> |
| 212 | <restriction |
| 213 | android:key="vpn_password" |
| 214 | android:restrictionType="string"/> |
| 215 | </restriction> |
| 216 | </restriction> |
| 217 | |
| 218 | </restrictions> |
| 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 Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 320 | <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 Waite | 7c70fed | 2016-09-21 15:47:30 -0700 | [diff] [blame] | 352 | call that activity's {@link android.app.Activity#getSystemService |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 353 | 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 Waite | 7c70fed | 2016-09-21 15:47:30 -0700 | [diff] [blame] | 402 | those data types, such as {@link android.os.Bundle#getBoolean getBoolean()} |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 403 | or |
| Elliot Waite | 7c70fed | 2016-09-21 15:47:30 -0700 | [diff] [blame] | 404 | {@link android.os.Bundle#getString getString()}. |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 405 | </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> |
| 425 | boolean appCanUseCellular; |
| 426 | |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 427 | if (appRestrictions.containsKey("downloadOnCellular")) { |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 428 | appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular"); |
| 429 | } else { |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 430 | // cellularDefault is a boolean using the restriction's default value |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 431 | appCanUseCellular = cellularDefault; |
| 432 | } |
| 433 | |
| 434 | if (!appCanUseCellular) { |
| 435 | // ...turn off app's cellular-download functionality |
| 436 | // ...show appropriate notices to user |
| 437 | }</pre> |
| 438 | |
| Billy Lamberta | ef57498 | 2016-07-11 13:13:56 -0700 | [diff] [blame] | 439 | <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 |
| 449 | List<VpnConfig> vpnConfigs = new ArrayList<>(); |
| 450 | |
| 451 | Parcelable[] parcelables = |
| 452 | appRestrictions.getParcelableArray("vpn_configuration_list"); |
| 453 | |
| 454 | if (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 | |
| 466 | if (!vpnConfigs.isEmpty()) { |
| 467 | // ...choose a VPN configuration or prompt user to select from list |
| 468 | }</pre> |
| 469 | |
| Billy Lamberta | 9fec73a | 2016-05-19 14:27:49 -0700 | [diff] [blame] | 470 | <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 | |
| 496 | BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() { |
| 497 | @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 | |
| 507 | registerReceiver(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> |