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