Home | History | Annotate | Download | only in enterprise
      1 page.title=Ensuring Compatibility with Managed Profiles
      2 page.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
     28 profiles</a>. A managed profile is controlled by an administrator, and the
     29 functionality available to it is set separately from the functionality of the
     30 user's primary profile. This approach lets enterprises control the environment
     31 where company-specific apps and data are running on a user's device, while still
     32 letting users use their personal apps and profiles.</p>
     33 
     34 <p>This lesson shows you how to modify your application so it functions
     35 reliably on a device with managed profiles. You don't need to do anything
     36 besides the ordinary app-development best practices. However, some of these best
     37 practices become especially important on devices with managed profiles. This
     38 document 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
     43 situation can present enterprises with a dilemma. If the user can use their own
     44 device, the enterprise has to worry that confidential information (like employee
     45 emails 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
     48 set up <i>managed profiles</i>. If a device has a managed profile, the profile's
     49 settings are under the control of the enterprise administrator. The
     50 administrator can choose which apps are allowed for that profile, and can
     51 control 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
     54 running 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
     59 app running on profile fires an intent, there is no handler for the intent on
     60 that profile, and the intent is not allowed to cross to the other profile
     61 due to profile restrictions, the request fails and the app may shut down
     62 unexpectedly.</li>
     63 <li>The profile administrator can limit which system apps are available on the
     64 managed profile. This restriction can also result in there being no handler for
     65 some common intents on the managed profile.</li>
     66 <li>Since the managed and unmanaged profiles have separate storage areas, a
     67 file URI that is valid on one profile is not valid on the other. Any
     68 intent fired on one profile might be handled on the other (depending on profile
     69 settings), 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
     76 can cross from one profile to another.  In most cases, when an intent is fired
     77 off, it is handled on the same profile where it is fired. If there is no handler
     78 for the intent <em>on that profile</em>, the intent is not handled and the app
     79 that fired it may shut down unexpectedly&mdash;even if there's a handler for the
     80 intent on the other profile.</p>
     81 
     82 <p>The profile administrator can choose which intents are
     83 allowed to cross from one profile to another. Since the administrator makes
     84 this decision, there's no way for you
     85 to know in advance <em>which</em> intents are allowed to cross this boundary. The
     86 administrator 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
     89 suitable resolution. You
     90 can verify  that there is an acceptable resolution by calling {@link
     91 android.content.Intent#resolveActivity Intent.resolveActivity()}. If there is no
     92 way to resolve the intent, the method returns
     93 <code>null</code>. If the method returns non-null, there is at least one way to
     94 resolve the intent, and it is safe to fire off the intent. In this case, the
     95 intent could be resolvable either
     96 because there is a handler on the current profile, or because the intent is
     97 allowed to cross to a handler on the other profile. (For more information about
     98 resolving intents, see <a
     99 href="{@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
    102 there's a valid handler for the {@link
    103 android.provider.AlarmClock#ACTION_SET_TIMER} intent. If the app cannot resolve
    104 the intent, it should take an appropriate action (such as showing an error
    105 message).</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.
    132 For example, an image gallery app might want to share its images with image
    133 editors. There are two ways you would ordinarily share a file: with a <em>file
    134 URI</em> or a <em>content URI</em>.</p>
    135 
    136 <p>A file URI begins with the <code>file:</code> prefix, followed by the
    137 absolute path of the file on the device's storage. However, because the
    138 managed profile and the personal profile use separate storage areas, a file URI
    139 that is valid on one profile is not valid on the other. This situation
    140 means that if you
    141 attach a file URI to an intent, and the intent is handled on the other profile,
    142 the handler is not able to access the file.</p>
    143 
    144 <p>Instead, you should share files with <em>content URIs</em>. Content URIs
    145 identify the file in a more secure, shareable fashion. The content URI contains
    146 the file path, but also the authority that provides the file, and an ID number
    147 identifying 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
    149 ID with other apps (even on the other profile). The recipient can use the
    150 content 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
    153 URI:</p>
    154 
    155 <pre>// Open File object from its file URI
    156 File fileToShare = new File(<em>fileUriToShare</em>);
    157 
    158 Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
    159         <em>"com.example.myapp.fileprovider"</em>, fileToShare);</pre>
    160 
    161 <p>When you call the {@link
    162 android.support.v4.content.FileProvider#getUriForFile getUriForFile()} method,
    163 you 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>
    166 element of your app manifest.
    167 For more information about sharing files with content URIs, see
    168 <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing
    169 Files</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
    174 catch problems that would cause your app to fail on a device with
    175 managed profiles. In particular, testing on a managed-profile device is a good
    176 way to make sure that your app handles intents properly: not firing intents that
    177 can't be handled, not attaching URIs that don't work cross-profile, and so
    178 on.</p>
    179 
    180 <p>We have provided a sample app, <a
    181 href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>,
    182 which you can use to set up a managed profile on an Android device that runs
    183 Android 5.0 (API level 21) and higher. This app offers you a simple way to test
    184 your app in a managed-profile environment. You can also use this app to
    185 configure 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
    198 managed profile, the app is installed on both the managed and the unmanaged
    199 profile. Once you have installed the app, you can test the app under the
    200 following 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
    209 enabling and disabling that   intent's permission to cross from one profile to
    210 another. Verify that the app behaves properly under both circumstances. If the
    211 intent is not allowed to cross between profiles, verify the app's behavior both
    212 when there is a suitable handler on the app's profile, and when there is not.
    213 For example, if your app fires a map-related intent, try each of the following
    214 scenarios:
    215 
    216     <ul>
    217 
    218 <li>The device allows map intents to cross from one profile to the other, and
    219 there is a suitable handler on the other profile (the profile the app is not
    220 running on)</li>
    221 
    222 <li>The device does not allow map intents to cross between profiles, but there
    223 is 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
    226 is 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
    232 both when it is handled on the app's profile, and when it crosses between
    233 profiles.</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
    240 managed-profile device.</p>
    241 
    242 <ul>
    243 
    244 <li>As noted,  when you side-load an app on a managed profile device, it is
    245 installed on both profiles. If you wish, you can delete the app from one profile
    246 and leave it on the other.</li>
    247 
    248 <li>Most of the activity manager commands available in the <a
    249 href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> (adb) shell
    250 support the <code>--user</code> flag, which lets you specify which user to run
    251 as. By specifying a user, you can choose whether to run as the unmanaged or
    252 managed profile. For
    253 more information, see <a href="{@docRoot}tools/help/shell.html#am">ADB
    254 Shell 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
    258 user ID, which you can use with the <code>--user</code> flag.  For more
    259 information, see <a href="{@docRoot}tools/help/shell.html#pm">ADB Shell
    260 Commands</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>
    267 UserInfo{0:Drew:13} running
    268 UserInfo{10:Work profile:30} running</pre>
    269 
    270 <p>In this case, the unmanaged profile ("Drew") has the user ID 0, and the
    271 managed profile has the user  ID 10. To run an app in the work profile, you
    272 would 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