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