1page.title=Ensuring Compatibility with Managed Profiles
2page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices.
3
4@jd:body
5
6<div id="tb-wrapper">
7<div id="tb">
8
9<h2>This lesson teaches you to</h2>
10<ol>
11 <li><a href="#prevent_failed_intents">Prevent Failed Intents</a></li>
12 <li><a href="#sharing_files">Share Files Across Profiles</a></li>
13 <li><a href="#testing_apps">Test your App for Compatibility with Managed
14    Profiles</a></li>
15</ol>
16
17<!-- related docs (NOT javadocs) -->
18<h2>Resources</h2>
19<ul>
20  <li><a href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a></li>
21</ul>
22
23</div>
24</div>
25
26<p>The Android platform allows devices to have
27<a href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed
28profiles</a>. A managed profile is controlled by an administrator, and the
29functionality available to it is set separately from the functionality of the
30user's primary profile. This approach lets enterprises control the environment
31where company-specific apps and data are running on a user's device, while still
32letting users use their personal apps and profiles.</p>
33
34<p>This lesson shows you how to modify your application so it functions
35reliably on a device with managed profiles. You don't need to do anything
36besides the ordinary app-development best practices. However, some of these best
37practices become especially important on devices with managed profiles. This
38document highlights the issues you need to be aware of.</p>
39
40<h2 id="overview">Overview</h2>
41
42<p>Users often want to use their personal devices in an enterprise setting. This
43situation can present enterprises with a dilemma. If the user can use their own
44device, the enterprise has to worry that confidential information (like employee
45emails and contacts) are on a device the enterprise does not control. </p>
46
47<p>To address this situation, Android 5.0 (API level 21) allows enterprises to
48set up <i>managed profiles</i>. If a device has a managed profile, the profile's
49settings are under the control of the enterprise administrator. The
50administrator can choose which apps are allowed for that profile, and can
51control just what device features are available to the profile.</p>
52
53<p>If a device has a managed profile, there are implications for apps
54running on the device, no matter which profile the app is running under:</p>
55
56<ul>
57
58<li>By default, most intents do not cross from one profile to the other. If an
59app running on profile fires an intent, there is no handler for the intent on
60that profile, and the intent is not allowed to cross to the other profile
61due to profile restrictions, the request fails and the app may shut down
62unexpectedly.</li>
63<li>The profile administrator can limit which system apps are available on the
64managed profile. This restriction can also result in there being no handler for
65some common intents on the managed profile.</li>
66<li>Since the managed and unmanaged profiles have separate storage areas, a
67file URI that is valid on one profile is not valid on the other. Any
68intent fired on one profile might be handled on the other (depending on profile
69settings), so it is not safe to attach file URIs to intents.</li>
70
71</ul>
72
73<h2 id="prevent_failed_intents">Prevent Failed Intents</h2>
74
75<p>On a device with a managed profile, there are restrictions on whether intents
76can cross from one profile to another.  In most cases, when an intent is fired
77off, it is handled on the same profile where it is fired. If there is no handler
78for the intent <em>on that profile</em>, the intent is not handled and the app
79that fired it may shut down unexpectedly&mdash;even if there's a handler for the
80intent on the other profile.</p>
81
82<p>The profile administrator can choose which intents are
83allowed to cross from one profile to another. Since the administrator makes
84this decision, there's no way for you
85to know in advance <em>which</em> intents are allowed to cross this boundary. The
86administrator sets this policy, and is free to change it at any time.</p>
87
88<p>Before your app starts an activity, you should verify that there is a
89suitable resolution. You
90can verify  that there is an acceptable resolution by calling {@link
91android.content.Intent#resolveActivity Intent.resolveActivity()}. If there is no
92way to resolve the intent, the method returns
93<code>null</code>. If the method returns non-null, there is at least one way to
94resolve the intent, and it is safe to fire off the intent. In this case, the
95intent could be resolvable either
96because there is a handler on the current profile, or because the intent is
97allowed to cross to a handler on the other profile. (For more information about
98resolving intents, see <a
99href="{@docRoot}guide/components/intents-common.html">Common Intents</a>.)</p>
100
101<p>For example, if your app needs to set timers,  it would need to check that
102there's a valid handler for the {@link
103android.provider.AlarmClock#ACTION_SET_TIMER} intent. If the app cannot resolve
104the intent, it should take an appropriate action (such as showing an error
105message).</p>
106
107<pre>public void startTimer(String message, int seconds) {
108
109    // Build the "set timer" intent
110    Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER)
111            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
112            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
113            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
114
115    // Check if there's a handler for the intent
116    <strong>if (timerIntent.resolveActivity(getPackageManager()) == null)</strong> {
117
118        // Can't resolve the intent! Fail this operation cleanly
119        // (perhaps by showing an error message)
120
121    } else {
122        // Intent resolves, it's safe to fire it off
123        startActivity(timerIntent);
124
125    }
126}
127</pre>
128
129<h2 id="sharing_files">Share Files Across Profiles</h2>
130
131<p>Sometimes an app needs to provide other apps with access to its own files.
132For example, an image gallery app might want to share its images with image
133editors. There are two ways you would ordinarily share a file: with a <em>file
134URI</em> or a <em>content URI</em>.</p>
135
136<p>A file URI begins with the <code>file:</code> prefix, followed by the
137absolute path of the file on the device's storage. However, because the
138managed profile and the personal profile use separate storage areas, a file URI
139that is valid on one profile is not valid on the other. This situation
140means that if you
141attach a file URI to an intent, and the intent is handled on the other profile,
142the handler is not able to access the file.</p>
143
144<p>Instead, you should share files with <em>content URIs</em>. Content URIs
145identify the file in a more secure, shareable fashion. The content URI contains
146the file path, but also the authority that provides the file, and an ID number
147identifying the file. You can generate a content ID for any file by using a
148{@link android.support.v4.content.FileProvider}. You can then share that content
149ID with other apps (even on the other profile). The recipient can use the
150content ID to get access to the actual file.</p>
151
152<p>For example, here's how you would get the content URI for a specific file
153URI:</p>
154
155<pre>// Open File object from its file URI
156File fileToShare = new File(<em>fileUriToShare</em>);
157
158Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
159        <em>"com.example.myapp.fileprovider"</em>, fileToShare);</pre>
160
161<p>When you call the {@link
162android.support.v4.content.FileProvider#getUriForFile getUriForFile()} method,
163you must include the file provider's authority (in this example,
164<code>"com.example.myapp.fileprovider"</code>), which is specified in the
165<a href="{@docRoot}guide/topics/manifest/provider-element.html"><code>&lt;provider&gt;</code></a>
166element of your app manifest.
167For more information about sharing files with content URIs, see
168<a href="{@docRoot}training/secure-file-sharing/index.html">Sharing
169Files</a>.</p>
170
171<h2 id="testing_apps">Test your App for Compatibility with Managed Profiles</h2>
172
173<p>You should test your app in a managed-profile environment to
174catch problems that would cause your app to fail on a device with
175managed profiles. In particular, testing on a managed-profile device is a good
176way to make sure that your app handles intents properly: not firing intents that
177can't be handled, not attaching URIs that don't work cross-profile, and so
178on.</p>
179
180<p>We have provided a sample app, <a
181href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>,
182which you can use to set up a managed profile on an Android device that runs
183Android 5.0 (API level 21) and higher. This app offers you a simple way to test
184your app in a managed-profile environment. You can also use this app to
185configure the managed profile as follows:</p>
186
187<ul>
188
189  <li>Specify which default apps are available on the managed
190    profile</li>
191
192  <li>Configure which intents are allowed to cross from one profile to
193    the other</li>
194
195</ul>
196
197<p>If you manually install an app over a USB cable to a device which has a
198managed profile, the app is installed on both the managed and the unmanaged
199profile. Once you have installed the app, you can test the app under the
200following conditions:</p>
201
202<ul>
203
204  <li>If an intent would ordinarily be handled by a default app (for example,
205    the camera app), try disabling that default app on the managed profile, and
206    verify that the app handles this appropriately.</li>
207
208  <li>If you fire an intent expecting it to be handled by some other app, try
209enabling and disabling that   intent's permission to cross from one profile to
210another. Verify that the app behaves properly under both circumstances. If the
211intent is not allowed to cross between profiles, verify the app's behavior both
212when there is a suitable handler on the app's profile, and when there is not.
213For example, if your app fires a map-related intent, try each of the following
214scenarios:
215
216    <ul>
217
218<li>The device allows map intents to cross from one profile to the other, and
219there is a suitable handler on the other profile (the profile the app is not
220running on)</li>
221
222<li>The device does not allow map intents to cross between profiles, but there
223is a suitable handler on the app's profile</li>
224
225<li>The device does not allow map intents to cross between profiles, and there
226is no suitable handler for map intents on the device's profile</li>
227
228    </ul>
229  </li>
230
231<li>If you attach content to an intent, verify that the intent behaves properly
232both when it is handled on the app's profile, and when it crosses between
233profiles.</li>
234
235</ul>
236
237<h3 id="testing_tips">Testing on managed profiles: Tips and tricks</h3>
238
239<p>There are a few tricks that you may find helpful in testing on a
240managed-profile device.</p>
241
242<ul>
243
244<li>As noted,  when you side-load an app on a managed profile device, it is
245installed on both profiles. If you wish, you can delete the app from one profile
246and leave it on the other.</li>
247
248<li>Most of the activity manager commands available in the <a
249href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> (adb) shell
250support the <code>--user</code> flag, which lets you specify which user to run
251as. By specifying a user, you can choose whether to run as the unmanaged or
252managed profile. For
253more information, see <a href="{@docRoot}tools/help/shell.html#am">ADB
254Shell Commands</a>.</li>
255
256<li>To find the active users on a device, use the adb package manager's
257<code>list users</code> command. The first number in the output string is the
258user ID, which you can use with the <code>--user</code> flag.  For more
259information, see <a href="{@docRoot}tools/help/shell.html#pm">ADB Shell
260Commands</a>.</li>
261
262</ul>
263
264<p>For example, to find the users on a device, you would run this command:</p>
265
266<pre class="no-pretty-print">$ <strong>adb shell pm list users</strong>
267UserInfo{0:Drew:13} running
268UserInfo{10:Work profile:30} running</pre>
269
270<p>In this case, the unmanaged profile ("Drew") has the user ID 0, and the
271managed profile has the user  ID 10. To run an app in the work profile, you
272would use a command like this:</p>
273
274<pre class="no-pretty-print">$ adb shell am start --user 10 \
275-n "<em>com.example.myapp/com.example.myapp.testactivity</em>" \
276-a android.intent.action.MAIN -c android.intent.category.LAUNCHER</pre>
277