| page.title=Set up Managed Profiles |
| page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices. |
| page.image=images/work/cards/briefcase_600px.png |
| |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#prevent_failed_intents">Prevent Failed Intents</a></li> |
| <li><a href="#sharing_files">Share Files Across Profiles</a></li> |
| <li><a href="#testing_apps"> |
| Test your App for Compatibility with Managed Profiles</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p>The Android platform allows devices to have |
| <a href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed |
| profiles</a>. A managed profile is controlled by an administrator, and the |
| functionality available to it is set separately from the functionality of the |
| user's primary profile. This approach lets enterprises control the environment |
| where company-specific apps and data are running on a user's device, while still |
| letting users use their personal apps and profiles.</p> |
| |
| <p>This lesson shows you how to modify your application so it functions |
| reliably on a device with managed profiles. You don't need to do anything |
| besides the ordinary app-development best practices. However, some of these best |
| practices become especially important on devices with managed profiles. This |
| document highlights the issues you need to be aware of.</p> |
| |
| <h2 id="overview">Overview</h2> |
| |
| <p>Users often want to use their personal devices in an enterprise setting. This |
| situation can present enterprises with a dilemma. If the user can use their own |
| device, the enterprise has to worry that confidential information (like employee |
| emails and contacts) are on a device the enterprise does not control. </p> |
| |
| <p>To address this situation, Android 5.0 (API level 21) allows enterprises to |
| set up <i>managed profiles</i>. If a device has a managed profile, the profile's |
| settings are under the control of the enterprise administrator. The |
| administrator can choose which apps are allowed for that profile, and can |
| control just what device features are available to the profile.</p> |
| |
| <p>If a device has a managed profile, there are implications for apps |
| running on the device, no matter which profile the app is running under:</p> |
| |
| <ul> |
| |
| <li>By default, most intents do not cross from one profile to the other. If an |
| app running on profile fires an intent, there is no handler for the intent on |
| that profile, and the intent is not allowed to cross to the other profile |
| due to profile restrictions, the request fails and the app may shut down |
| unexpectedly.</li> |
| <li>The profile administrator can limit which system apps are available on the |
| managed profile. This restriction can also result in there being no handler for |
| some common intents on the managed profile.</li> |
| <li>Since the managed and unmanaged profiles have separate storage areas, a |
| file URI that is valid on one profile is not valid on the other. Any |
| intent fired on one profile might be handled on the other (depending on profile |
| settings), so it is not safe to attach file URIs to intents.</li> |
| |
| </ul> |
| |
| <h2 id="prevent_failed_intents">Prevent Failed Intents</h2> |
| |
| <p>On a device with a managed profile, there are restrictions on whether intents |
| can cross from one profile to another. In most cases, when an intent is fired |
| off, it is handled on the same profile where it is fired. If there is no handler |
| for the intent <em>on that profile</em>, the intent is not handled and the app |
| that fired it may shut down unexpectedly—even if there's a handler for the |
| intent on the other profile.</p> |
| |
| <p>The profile administrator can choose which intents are |
| allowed to cross from one profile to another. Since the administrator makes |
| this decision, there's no way for you |
| to know in advance <em>which</em> intents are allowed to cross this boundary. The |
| administrator sets this policy, and is free to change it at any time.</p> |
| |
| <p>Before your app starts an activity, you should verify that there is a |
| suitable resolution. You |
| can verify that there is an acceptable resolution by calling {@link |
| android.content.Intent#resolveActivity Intent.resolveActivity()}. If there is no |
| way to resolve the intent, the method returns |
| <code>null</code>. If the method returns non-null, there is at least one way to |
| resolve the intent, and it is safe to fire off the intent. In this case, the |
| intent could be resolvable either |
| because there is a handler on the current profile, or because the intent is |
| allowed to cross to a handler on the other profile. (For more information about |
| resolving intents, see <a |
| href="{@docRoot}guide/components/intents-common.html">Common Intents</a>.)</p> |
| |
| <p>For example, if your app needs to set timers, it would need to check that |
| there's a valid handler for the {@link |
| android.provider.AlarmClock#ACTION_SET_TIMER} intent. If the app cannot resolve |
| the intent, it should take an appropriate action (such as showing an error |
| message).</p> |
| |
| <pre>public void startTimer(String message, int seconds) { |
| |
| // Build the "set timer" intent |
| Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER) |
| .putExtra(AlarmClock.EXTRA_MESSAGE, message) |
| .putExtra(AlarmClock.EXTRA_LENGTH, seconds) |
| .putExtra(AlarmClock.EXTRA_SKIP_UI, true); |
| |
| // Check if there's a handler for the intent |
| <strong>if (timerIntent.resolveActivity(getPackageManager()) == null)</strong> { |
| |
| // Can't resolve the intent! Fail this operation cleanly |
| // (perhaps by showing an error message) |
| |
| } else { |
| // Intent resolves, it's safe to fire it off |
| startActivity(timerIntent); |
| |
| } |
| } |
| </pre> |
| |
| <h2 id="sharing_files">Share Files Across Profiles</h2> |
| |
| <p>Sometimes an app needs to provide other apps with access to its own files. |
| For example, an image gallery app might want to share its images with image |
| editors. There are two ways you would ordinarily share a file: with a <em>file |
| URI</em> or a <em>content URI</em>.</p> |
| |
| <p>A file URI begins with the <code>file:</code> prefix, followed by the |
| absolute path of the file on the device's storage. However, because the |
| managed profile and the personal profile use separate storage areas, a file URI |
| that is valid on one profile is not valid on the other. This situation |
| means that if you |
| attach a file URI to an intent, and the intent is handled on the other profile, |
| the handler is not able to access the file.</p> |
| |
| <p>Instead, you should share files with <em>content URIs</em>. Content URIs |
| identify the file in a more secure, shareable fashion. The content URI contains |
| the file path, but also the authority that provides the file, and an ID number |
| identifying the file. You can generate a content ID for any file by using a |
| {@link android.support.v4.content.FileProvider}. You can then share that content |
| ID with other apps (even on the other profile). The recipient can use the |
| content ID to get access to the actual file.</p> |
| |
| <p>For example, here's how you would get the content URI for a specific file |
| URI:</p> |
| |
| <pre>// Open File object from its file URI |
| File fileToShare = new File(<em>fileUriToShare</em>); |
| |
| Uri contentUriToShare = FileProvider.getUriForFile(getContext(), |
| <em>"com.example.myapp.fileprovider"</em>, fileToShare);</pre> |
| |
| <p>When you call the {@link |
| android.support.v4.content.FileProvider#getUriForFile getUriForFile()} method, |
| you must include the file provider's authority (in this example, |
| <code>"com.example.myapp.fileprovider"</code>), which is specified in the |
| <a href="{@docRoot}guide/topics/manifest/provider-element.html"><code><provider></code></a> |
| element of your app manifest. |
| For more information about sharing files with content URIs, see |
| <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing |
| Files</a>.</p> |
| |
| <h2 id="testing_apps">Test your App for Compatibility with Managed Profiles</h2> |
| |
| <p>You should test your app in a managed-profile environment to |
| catch problems that would cause your app to fail on a device with |
| managed profiles. In particular, testing on a managed-profile device is a good |
| way to make sure that your app handles intents properly: not firing intents that |
| can't be handled, not attaching URIs that don't work cross-profile, and so |
| on.</p> |
| |
| <p>We have provided a sample app, <a |
| href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>, |
| which you can use to set up a managed profile on an Android device that runs |
| Android 5.0 (API level 21) and higher. This app offers you a simple way to test |
| your app in a managed-profile environment. You can also use this app to |
| configure the managed profile as follows:</p> |
| |
| <ul> |
| |
| <li>Specify which default apps are available on the managed |
| profile</li> |
| |
| <li>Configure which intents are allowed to cross from one profile to |
| the other</li> |
| |
| </ul> |
| |
| <p>If you manually install an app over a USB cable to a device which has a |
| managed profile, the app is installed on both the managed and the unmanaged |
| profile. Once you have installed the app, you can test the app under the |
| following conditions:</p> |
| |
| <ul> |
| |
| <li>If an intent would ordinarily be handled by a default app (for example, |
| the camera app), try disabling that default app on the managed profile, and |
| verify that the app handles this appropriately.</li> |
| |
| <li>If you fire an intent expecting it to be handled by some other app, try |
| enabling and disabling that intent's permission to cross from one profile to |
| another. Verify that the app behaves properly under both circumstances. If the |
| intent is not allowed to cross between profiles, verify the app's behavior both |
| when there is a suitable handler on the app's profile, and when there is not. |
| For example, if your app fires a map-related intent, try each of the following |
| scenarios: |
| |
| <ul> |
| |
| <li>The device allows map intents to cross from one profile to the other, and |
| there is a suitable handler on the other profile (the profile the app is not |
| running on)</li> |
| |
| <li>The device does not allow map intents to cross between profiles, but there |
| is a suitable handler on the app's profile</li> |
| |
| <li>The device does not allow map intents to cross between profiles, and there |
| is no suitable handler for map intents on the device's profile</li> |
| |
| </ul> |
| </li> |
| |
| <li>If you attach content to an intent, verify that the intent behaves properly |
| both when it is handled on the app's profile, and when it crosses between |
| profiles.</li> |
| |
| </ul> |
| |
| <h3 id="testing_tips">Testing on managed profiles: Tips and tricks</h3> |
| |
| <p>There are a few tricks that you may find helpful in testing on a |
| managed-profile device.</p> |
| |
| <ul> |
| |
| <li>As noted, when you side-load an app on a managed profile device, it is |
| installed on both profiles. If you wish, you can delete the app from one profile |
| and leave it on the other.</li> |
| |
| <li>Most of the activity manager commands available in the <a |
| href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> (adb) shell |
| support the <code>--user</code> flag, which lets you specify which user to run |
| as. By specifying a user, you can choose whether to run as the unmanaged or |
| managed profile. For |
| more information, see <a href="{@docRoot}tools/help/shell.html#am">ADB |
| Shell Commands</a>.</li> |
| |
| <li>To find the active users on a device, use the adb package manager's |
| <code>list users</code> command. The first number in the output string is the |
| user ID, which you can use with the <code>--user</code> flag. For more |
| information, see <a href="{@docRoot}tools/help/shell.html#pm">ADB Shell |
| Commands</a>.</li> |
| |
| </ul> |
| |
| <p>For example, to find the users on a device, you would run this command:</p> |
| |
| <pre class="no-pretty-print">$ <strong>adb shell pm list users</strong> |
| UserInfo{0:Drew:13} running |
| UserInfo{10:Work profile:30} running</pre> |
| |
| <p>In this case, the unmanaged profile ("Drew") has the user ID 0, and the |
| managed profile has the user ID 10. To run an app in the work profile, you |
| would use a command like this:</p> |
| |
| <pre class="no-pretty-print">$ adb shell am start --user 10 \ |
| -n "<em>com.example.myapp/com.example.myapp.testactivity</em>" \ |
| -a android.intent.action.MAIN -c android.intent.category.LAUNCHER</pre> |