Update News

***TOP NEWS * How to delete google search? Give the offer GOOGLE

Monday 16 March 2015

Building Apps for Work

Ensuring Compatibility with Managed Profiles


The Android platform allows devices to have managed profiles. 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.
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.

Overview


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.
To address this situation, Android 5.0 (API level 21) allows enterprises to set up managed profiles. 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.
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:
  • 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.
  • 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.
  • 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.

Prevent Failed Intents


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 on that profile, 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.
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 which intents are allowed to cross this boundary. The administrator sets this policy, and is free to change it at any time.
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 Intent.resolveActivity(). If there is no way to resolve the intent, the method returns null. 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 Common Intents.)
For example, if your app needs to set timers, it would need to check that there's a valid handler for theACTION_SET_TIMER intent. If the app cannot resolve the intent, it should take an appropriate action (such as showing an error message).
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
    if (timerIntent.resolveActivity(getPackageManager()) == null) {

        // 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);

    }
}

Share Files Across Profiles


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 afile URI or a content URI.
A file URI begins with the file: 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.
Instead, you should share files with content URIs. 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 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.
For example, here's how you would get the content URI for a specific file URI:
// Open File object from its file URI
File fileToShare = new File(fileUriToShare);
Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
        "com.example.myapp.fileprovider", fileToShare);
When you call the getUriForFile() method, you must include the file provider's authority (in this example,"com.example.myapp.fileprovider"), which is specified in the <provider> element of your app manifest. For more information about sharing files with content URIs, see Sharing Files.

Test your App for Compatibility with Managed Profiles


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.
We have provided a sample app, BasicManagedProfile, 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:
  • Specify which default apps are available on the managed profile
  • Configure which intents are allowed to cross from one profile to the other
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:
  • 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.
  • 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:
    • 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)
    • The device does not allow map intents to cross between profiles, but there is a suitable handler on the app's profile
    • 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
  • 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.

Testing on managed profiles: Tips and tricks

There are a few tricks that you may find helpful in testing on a managed-profile device.
  • 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.
  • Most of the activity manager commands available in the Android Debug Bridge (adb) shell support the --userflag, 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 Android Debug Bridge: Using activity manager (am).
  • To find the active users on a device, use the adb package manager's list users command. The first number in the output string is the user ID, which you can use with the --user flag. For more information, see Android Debug Bridge: Using package manager (pm).
For example, to find the users on a device, you would run this command:
$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running
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:
$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER

Implementing App Restrictions

If you are developing apps for the enterprise market, you may need to satisfy particular requirements set by a company's policies. Application restrictions allow the enterprise administrator to remotely specify settings for apps. This capability is particularly useful for enterprise-approved apps deployed to a managed profile.
For example, an enterprise might require that approved apps allow the enterprise administrator to:
  • Whitelist or blacklist URLs for a web browser
  • Configure whether an app is allowed to sync content via cellular, or just by Wi-Fi
  • Configure the app's email settings
This guide shows how to implement these configuration settings in your app.
Note: For historical reasons, these configuration settings are known as restrictions, and are implemented with files and classes that use this term (such as RestrictionsManager). However, these restrictions can actually implement a wide range of configuration options, not just restrictions on app functionality.

Remote Configuration Overview


Apps define the restrictions and configuration options that can be remotely set by an administrator. These restrictions are arbitrary configuration settings that can be changed by a restrictions provider. If your app is running on an enterprise device's managed profile, the enterprise administrator can change your app's restrictions.
The restrictions provider is another app running on the same device. This app is typically controlled by the enterprise administrator. The enterprise administrator communicates restriction changes to the restrictions provider app. That app, in turn, changes the restrictions on your app.
To provide externally configurable restrictions:
  • Declare the restrictions in your app manifest. Doing so allows the enterprise administrator to read the app's restrictions through Google Play APIs.
  • Whenever the app resumes, use the RestrictionsManager object to check the current restrictions, and change your app's UI and behavior to conform with those restrictions.
  • Listen for the ACTION_APPLICATION_RESTRICTIONS_CHANGED intent. When you receive this broadcast, check theRestrictionsManager to see what the current restrictions are, and make any necessary changes to your app's behavior.

Define App Restrictions


Your app can support any restrictions you want to define. You declare the app's restrictions in a restrictions file, and declare the restrictions file in the manifest. Creating a restrictions file allows other apps to examine the restrictions your app provides. Enterprise Mobility Management (EMM) partners can read your app's restrictions by using Google Play APIs.
To define your app's remote configuration options, put the following element in your manifest's <application>element:
<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />
Create a file named app_restrictions.xml in your app's res/xml directory. The structure of that file is described in the reference for RestrictionsManager. The file has a single top-level <restrictions> element, which contains one <restriction> child element for every configuration option the app has.
Note: Do not create localized versions of the restrictions file. Your app is only allowed to have a single restrictions file, so restrictions will be consistent for your app in all locales.
In an enterprise environment, an EMM will typically use the restrictions schema to generate a remote console for IT administrators, so the administrators can remotely configure your application.
For example, suppose your app can be remotely configured to allow or forbid it to download data over a cellular connection. Your app could have a <restriction> element like this:
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >

  <restriction
    android:key="downloadOnCellular"
    android:title="App is allowed to download data via cellular"
    android:restrictionType="bool"
    android:description="If 'false', app can only download data via Wi-Fi"
    android:defaultValue="true" />
</restrictions>
The supported types for the android:restrictionType element are documented in the reference forRestrictionsManager.
You use each restriction's android:key attribute to read its value from a restrictions bundle. For this reason, each restriction must have a unique key string, and the string cannot be localized. It must be specified with a string literal.
Note: In a production app, android:title and android:description should be drawn from a localized resource file, as described in Localizing with Resources.
The restrictions provider can query the app to find details on the app's available restrictions, including their description text. Restrictions providers and enterprise administrators can change your app's restrictions at any time, even when the app is not running.

Check App Restrictions


Your app is not automatically notified when other apps change its restriction settings. Instead, you need to check what the restrictions are when your app starts or resumes, and listen for a system intent to find out if the restrictions change while your app is running.
To find out the current restriction settings, your app uses a RestrictionsManager object. Your app should check for the current restrictions at the following times:
To get a RestrictionsManager object, get the current activity with getActivity(), then call that activity'sActivity.getSystemService() method:
RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);
Once you have a RestrictionsManager, you can get the current restrictions settings by calling itsgetApplicationRestrictions() method:
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
Note: For convenience, you can also fetch the current restrictions with a UserManager, by callingUserManager.getApplicationRestrictions(). This method behaves exactly the same asRestrictionsManager.getApplicationRestrictions().
The getApplicationRestrictions() method requires reading from data storage, so it should be done sparingly. Do not call this method every time you need to know the current restrictions. Instead, you should call it once when your app starts or resumes, and cache the fetched restrictions bundle. Then listen for theACTION_APPLICATION_RESTRICTIONS_CHANGED intent to find out if restrictions change while your app is active, as described in Listen for Device Configuration Changes.

Reading and applying restrictions

The getApplicationRestrictions() method returns a Bundle containing a key-value pair for each restriction that has been set. The values are all of type BooleanintString, and String[]. Once you have the restrictionsBundle, you can check the current restrictions settings with the standard Bundle methods for those data types, such as getBoolean() or getString().
Note: The restrictions Bundle contains one item for every restriction that has been explicitly set by a restrictions provider. However, you cannot assume that a restriction will be present in the bundle just because you defined a default value in the restrictions XML file.
It is up to your app to take appropriate action based on the current restrictions settings. For example, if your app has a restriction specifying whether it can download data over a cellular connection, and you find that the restriction is set to false, you would have to disable data download except when the device has a Wi-Fi connection, as shown in the following example code:
boolean appCanUseCellular;
if appRestrictions.containsKey("downloadOnCellular") {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // here, cellularDefault is a boolean set with the restriction's
    // default value
    appCanUseCellular = cellularDefault;
}
if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Listen for App Restriction Changes


Whenever an app's restrictions are changed, the system fires the ACTION_APPLICATION_RESTRICTIONS_CHANGEDintent. Your app has to listen for this intent so you can change the app's behavior when the restriction settings change. The following code shows how to dynamically register a broadcast receiver for this intent:
IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current restrictions bundle
    Bundle appRestrictions =

    myRestrictionsMgr.getApplicationRestrictions();

    // Check current restrictions settings, change your app's UI and
    // functionality as necessary.

  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);
Note: Ordinarily, your app does not need to be notified about restriction changes when it is paused. Instead, you should unregister your broadcast receiver when the app is paused. When the app resumes, you first check for the current restrictions (as discussed in Check Device Restrictions), then register your broadcast receiver to make sure you're notified about restriction changes that happen while the app is active.

Building a Work Policy Controller

In an Android for Work deployment, an enterprise needs to maintain control over certain aspects of the employees' devices. The enterprise needs to ensure that work-related information is encrypted and is kept separate from employees' personal data. The enterprise may also need to limit device capabilities, such as whether the device is allowed to use its camera. And the enterprise may require that approved apps provide app restrictions, so the enterprise can turn app capability on or off as needed.
To handle these tasks, an enterprise develops and deploys a Work Policy Controller app. This app is installed on each employee's device. The controller app installed on each employee's device and creates a work user profile, which accesses enterprise apps and data separately from the user's personal account. The controller app also acts as the bridge between the enterprise's management software and the device; the enterprise tells the controller app when it needs to make configuration changes, and the controller app makes the appropriate settings changes for the device and for other apps.
This lesson describes how to develop a Work Policy Controller app for devices in an Android for Work deployment. The lesson describes how to create a work user profile, how to set device policies, and how to apply restrictions to other apps running on the managed profile.
Note: This lesson does not cover the situation where the only profile on the device is the managed profile, under the enterprise's control.

Device Administration Overview


In an Android for Work deployment, the enterprise administrator can set policies to control the behavior of employees' devices and apps. The enterprise administrator sets these policies with software provided by their Enterprise Mobility Management (EMM) provider. The EMM software communicates with a Work Policy Controller on each device. The Work Policy Controller, in turn, manages the settings and behavior of the work user profile on each individual’s device.
Note: A Work Policy Controller is built on the existing model used for device administration applications, as described in Device Administration. In particular, your app needs to create a subclass of DeviceAdminReceiver, as described in that document.

Managed profiles

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.
To address this situation, Android 5.0 (API level 21) allows enterprises to set up a special work user profile using the Managed Profile API. This user profile is called a managed profile, or a work profile in the Android for Work program. If a device has a managed profile for work, 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.

Create a Managed Profile


To create a managed profile on a device that already has a personal profile, first check that the device can support a managed profile, by seeing if the device supports the FEATURE_MANAGED_USERS system feature:
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {

    // This device does not support native managed profiles!
}
If the device supports managed profiles, create one by sending an intent with anACTION_PROVISION_MANAGED_PROFILE action. Include the device admin package name as an extra.
Activity provisioningActivity = getActivity();
// You'll need the package name for the WPC app.
String myWPCPackageName = "com.example.myWPCApp";
// Set up the provisioning intent
Intent provisioningIntent =
        new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
intent.putExtra(myWPCPackageName,
        provisioningActivity.getApplicationContext().getPackageName());
if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
         == null) {

    // No handler for intent! Can't provision this device.
    // Show an error message and cancel.
} else {

    // REQUEST_PROVISION_MANAGED_PROFILE is defined
    // to be a suitable request code
    startActivityForResult(provisioningIntent,
            REQUEST_PROVISION_MANAGED_PROFILE);
    provisioningActivity.finish();
}
The system responds to this intent by doing the following:
  • Verifies that the device is encrypted. If it is not, the system prompts the user to encrypt the device before proceeding.
  • Creates a managed profile.
  • Removes non-required applications from the managed profile.
  • Copies the Work Policy Controller application into the managed profile and sets it as the profile owner.
Override onActivityResult() to see whether the provisioning was successful, as shown in the following example code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    // Check if this is the result of the provisioning activity
    if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {

        // If provisioning was successful, the result code is 
        // Activity.RESULT_OK
        if (resultCode == Activity.RESULT_OK) {
            // Hurray! Managed profile created and provisioned!
        } else {
            // Boo! Provisioning failed!
        }
        return;

    } else {
        // This is the result of some other activity, call the superclass
        super.onActivityResult(requestCode, resultCode, data);
    }
}

After Creating the Managed Profile

When the profile has been provisioned, the system calls the Work Policy Controller app'sDeviceAdminReceiver.onProfileProvisioningComplete() method. Override this callback method to finish enabling the managed profile.
Typically, your DeviceAdminReceiver.onProfileProvisioningComplete() callback implementation would perform these tasks:
  • Verify that the device is complying with the EMM's device policies, as described in Set Up Device Policies
  • Enable any system applications that the administrator chooses to make available within the managed profile, using DevicePolicyManager.enableSystemApp()
  • If the device uses Google Play for Work, add the Google account to the managed profile withAccountManager.addAccount(), so administrators can install applications to the device
Once you have completed these tasks, call the device policy manager's setProfileEnabled() method to activate the managed profile:
// Get the device policy manager
DevicePolicyManager myDevicePolicyMgr =
        (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
// Set the name for the newly created managed profile.
myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
// ...and enable the profile
manager.setProfileEnabled(componentName);

Set Up Device Policies


The Work Policy Controller app is responsible for applying the enterprise's device policies. For example, a particular enterprise might require that all devices become locked after a certain number of failed attempts to enter the device password. The controller app queries the EMM to find out what the current policies are, then uses the Device Administration API to apply those policies.
For information on how to apply device policies, see the Device Administration guide.

Apply App Restrictions


Enterprise environments may require that approved apps implement apps implement security or feature restrictions. App developers must implement these restrictions and declare them for use by enterprise administrators, as described in Implementing App Restrictions. The Work Policy Controller receives restriction changes from the enterprise administrator, and forwards those restriction changes to the apps.
For example, a particular news app might have a restriction setting that controls whether the app is allowed to download videos over a cellular network. When the EMM wants to disable cellular downloads, it sends a notification to the controller app. The controller app, in turn, notifies the news app that the restriction setting has changed.
Note: This document covers how the Work Policy Controller app changes the restriction settings for the other apps on the managed profile. Details on how the Work Policy Controller app communicates with the EMM are out of scope for this document.
To change an app's restrictions, call the DevicePolicyManager.setApplicationRestrictions() method. This method is passed three parameters: the controller app's DeviceAdminReceiver, the package name of the app whose restrictions are being changed, and a Bundle that contains the restrictions you want to set.
For example, suppose there's an app on the managed profile with the package name"com.example.newsfetcher". This app has a single boolean restriction that can be configured, with the key"downloadByCellular". If this restriction is set to false, the newsfetcher app is not allowed to download data through a cellular network; it must use a Wi-Fi network instead.
If your Work Policy Controller app needs to turn off cellular downloads, it would first fetch the device policy service object, as described above. It then assembles a restrictions bundle and passes this bundle tosetApplicationRestrictions():
// Fetch the DevicePolicyManager
DevicePolicyManager myDevicePolicyMgr =
        (DevicePolicyManager) thisActivity
                .getSystemService(Context.DEVICE_POLICY_SERVICE);
// Set up the restrictions bundle
bundle restrictionsBundle = new Bundle();
restrictionsBundle.putBoolean("downloadByCellular", false);
// Pass the restrictions to the policy manager. Assume the WPC app
// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
myDevicePolicyMgr.setApplicationRestrictions(
        myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);
Note: The device policy service conveys the restrictions change to the app you name. However, it is up to that app to actually implement the restriction. For example, in this case, the app would be responsible for disabling its ability to use cellular networks for video downloads. Setting the restriction does not cause the system to enforce this restriction on the app. For more information, see Implementing App Restrictions.

Ensuring Compatibility with Managed Profiles

The Android platform allows devices to have managed profiles. 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.
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.

Overview


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.
To address this situation, Android 5.0 (API level 21) allows enterprises to set up managed profiles. 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.
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:
  • 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.
  • 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.
  • 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.

Prevent Failed Intents


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 on that profile, 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.
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 which intents are allowed to cross this boundary. The administrator sets this policy, and is free to change it at any time.
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 Intent.resolveActivity(). If there is no way to resolve the intent, the method returns null. 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 Common Intents.)
For example, if your app needs to set timers, it would need to check that there's a valid handler for theACTION_SET_TIMER intent. If the app cannot resolve the intent, it should take an appropriate action (such as showing an error message).
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
    if (timerIntent.resolveActivity(getPackageManager()) == null) {

        // 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);

    }
}

Share Files Across Profiles


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 afile URI or a content URI.
A file URI begins with the file: 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.
Instead, you should share files with content URIs. 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 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.
For example, here's how you would get the content URI for a specific file URI:
// Open File object from its file URI
File fileToShare = new File(fileUriToShare);
Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
        "com.example.myapp.fileprovider", fileToShare);
When you call the getUriForFile() method, you must include the file provider's authority (in this example,"com.example.myapp.fileprovider"), which is specified in the <provider> element of your app manifest. For more information about sharing files with content URIs, see Sharing Files.

Test your App for Compatibility with Managed Profiles


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.
We have provided a sample app, BasicManagedProfile, 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:
  • Specify which default apps are available on the managed profile
  • Configure which intents are allowed to cross from one profile to the other
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:
  • 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.
  • 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:
    • 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)
    • The device does not allow map intents to cross between profiles, but there is a suitable handler on the app's profile
    • 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
  • 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.

Testing on managed profiles: Tips and tricks

There are a few tricks that you may find helpful in testing on a managed-profile device.
  • 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.
  • Most of the activity manager commands available in the Android Debug Bridge (adb) shell support the --userflag, 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 Android Debug Bridge: Using activity manager (am).
  • To find the active users on a device, use the adb package manager's list users command. The first number in the output string is the user ID, which you can use with the --user flag. For more information, see Android Debug Bridge: Using package manager (pm).
For example, to find the users on a device, you would run this command:
$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running
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:
$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER

Implementing App Restrictions

If you are developing apps for the enterprise market, you may need to satisfy particular requirements set by a company's policies. Application restrictions allow the enterprise administrator to remotely specify settings for apps. This capability is particularly useful for enterprise-approved apps deployed to a managed profile.
For example, an enterprise might require that approved apps allow the enterprise administrator to:
  • Whitelist or blacklist URLs for a web browser
  • Configure whether an app is allowed to sync content via cellular, or just by Wi-Fi
  • Configure the app's email settings
This guide shows how to implement these configuration settings in your app.
Note: For historical reasons, these configuration settings are known as restrictions, and are implemented with files and classes that use this term (such as RestrictionsManager). However, these restrictions can actually implement a wide range of configuration options, not just restrictions on app functionality.

Remote Configuration Overview


Apps define the restrictions and configuration options that can be remotely set by an administrator. These restrictions are arbitrary configuration settings that can be changed by a restrictions provider. If your app is running on an enterprise device's managed profile, the enterprise administrator can change your app's restrictions.
The restrictions provider is another app running on the same device. This app is typically controlled by the enterprise administrator. The enterprise administrator communicates restriction changes to the restrictions provider app. That app, in turn, changes the restrictions on your app.
To provide externally configurable restrictions:
  • Declare the restrictions in your app manifest. Doing so allows the enterprise administrator to read the app's restrictions through Google Play APIs.
  • Whenever the app resumes, use the RestrictionsManager object to check the current restrictions, and change your app's UI and behavior to conform with those restrictions.
  • Listen for the ACTION_APPLICATION_RESTRICTIONS_CHANGED intent. When you receive this broadcast, check theRestrictionsManager to see what the current restrictions are, and make any necessary changes to your app's behavior.

Define App Restrictions


Your app can support any restrictions you want to define. You declare the app's restrictions in a restrictions file, and declare the restrictions file in the manifest. Creating a restrictions file allows other apps to examine the restrictions your app provides. Enterprise Mobility Management (EMM) partners can read your app's restrictions by using Google Play APIs.
To define your app's remote configuration options, put the following element in your manifest's <application>element:
<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />
Create a file named app_restrictions.xml in your app's res/xml directory. The structure of that file is described in the reference for RestrictionsManager. The file has a single top-level <restrictions> element, which contains one <restriction> child element for every configuration option the app has.
Note: Do not create localized versions of the restrictions file. Your app is only allowed to have a single restrictions file, so restrictions will be consistent for your app in all locales.
In an enterprise environment, an EMM will typically use the restrictions schema to generate a remote console for IT administrators, so the administrators can remotely configure your application.
For example, suppose your app can be remotely configured to allow or forbid it to download data over a cellular connection. Your app could have a <restriction> element like this:
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >

  <restriction
    android:key="downloadOnCellular"
    android:title="App is allowed to download data via cellular"
    android:restrictionType="bool"
    android:description="If 'false', app can only download data via Wi-Fi"
    android:defaultValue="true" />
</restrictions>
The supported types for the android:restrictionType element are documented in the reference forRestrictionsManager.
You use each restriction's android:key attribute to read its value from a restrictions bundle. For this reason, each restriction must have a unique key string, and the string cannot be localized. It must be specified with a string literal.
Note: In a production app, android:title and android:description should be drawn from a localized resource file, as described in Localizing with Resources.
The restrictions provider can query the app to find details on the app's available restrictions, including their description text. Restrictions providers and enterprise administrators can change your app's restrictions at any time, even when the app is not running.

Check App Restrictions


Your app is not automatically notified when other apps change its restriction settings. Instead, you need to check what the restrictions are when your app starts or resumes, and listen for a system intent to find out if the restrictions change while your app is running.
To find out the current restriction settings, your app uses a RestrictionsManager object. Your app should check for the current restrictions at the following times:
To get a RestrictionsManager object, get the current activity with getActivity(), then call that activity'sActivity.getSystemService() method:
RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);
Once you have a RestrictionsManager, you can get the current restrictions settings by calling itsgetApplicationRestrictions() method:
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
Note: For convenience, you can also fetch the current restrictions with a UserManager, by callingUserManager.getApplicationRestrictions(). This method behaves exactly the same asRestrictionsManager.getApplicationRestrictions().
The getApplicationRestrictions() method requires reading from data storage, so it should be done sparingly. Do not call this method every time you need to know the current restrictions. Instead, you should call it once when your app starts or resumes, and cache the fetched restrictions bundle. Then listen for theACTION_APPLICATION_RESTRICTIONS_CHANGED intent to find out if restrictions change while your app is active, as described in Listen for Device Configuration Changes.

Reading and applying restrictions

The getApplicationRestrictions() method returns a Bundle containing a key-value pair for each restriction that has been set. The values are all of type BooleanintString, and String[]. Once you have the restrictionsBundle, you can check the current restrictions settings with the standard Bundle methods for those data types, such as getBoolean() or getString().
Note: The restrictions Bundle contains one item for every restriction that has been explicitly set by a restrictions provider. However, you cannot assume that a restriction will be present in the bundle just because you defined a default value in the restrictions XML file.
It is up to your app to take appropriate action based on the current restrictions settings. For example, if your app has a restriction specifying whether it can download data over a cellular connection, and you find that the restriction is set to false, you would have to disable data download except when the device has a Wi-Fi connection, as shown in the following example code:
boolean appCanUseCellular;
if appRestrictions.containsKey("downloadOnCellular") {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // here, cellularDefault is a boolean set with the restriction's
    // default value
    appCanUseCellular = cellularDefault;
}
if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Listen for App Restriction Changes


Whenever an app's restrictions are changed, the system fires the ACTION_APPLICATION_RESTRICTIONS_CHANGEDintent. Your app has to listen for this intent so you can change the app's behavior when the restriction settings change. The following code shows how to dynamically register a broadcast receiver for this intent:
IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current restrictions bundle
    Bundle appRestrictions =

    myRestrictionsMgr.getApplicationRestrictions();

    // Check current restrictions settings, change your app's UI and
    // functionality as necessary.

  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);
Note: Ordinarily, your app does not need to be notified about restriction changes when it is paused. Instead, you should unregister your broadcast receiver when the app is paused. When the app resumes, you first check for the current restrictions (as discussed in Check Device Restrictions), then register your broadcast receiver to make sure you're notified about restriction changes that happen while the app is active.

Building a Work Policy Controller

In an Android for Work deployment, an enterprise needs to maintain control over certain aspects of the employees' devices. The enterprise needs to ensure that work-related information is encrypted and is kept separate from employees' personal data. The enterprise may also need to limit device capabilities, such as whether the device is allowed to use its camera. And the enterprise may require that approved apps provide app restrictions, so the enterprise can turn app capability on or off as needed.
To handle these tasks, an enterprise develops and deploys a Work Policy Controller app. This app is installed on each employee's device. The controller app installed on each employee's device and creates a work user profile, which accesses enterprise apps and data separately from the user's personal account. The controller app also acts as the bridge between the enterprise's management software and the device; the enterprise tells the controller app when it needs to make configuration changes, and the controller app makes the appropriate settings changes for the device and for other apps.
This lesson describes how to develop a Work Policy Controller app for devices in an Android for Work deployment. The lesson describes how to create a work user profile, how to set device policies, and how to apply restrictions to other apps running on the managed profile.
Note: This lesson does not cover the situation where the only profile on the device is the managed profile, under the enterprise's control.

Device Administration Overview


In an Android for Work deployment, the enterprise administrator can set policies to control the behavior of employees' devices and apps. The enterprise administrator sets these policies with software provided by their Enterprise Mobility Management (EMM) provider. The EMM software communicates with a Work Policy Controller on each device. The Work Policy Controller, in turn, manages the settings and behavior of the work user profile on each individual’s device.
Note: A Work Policy Controller is built on the existing model used for device administration applications, as described in Device Administration. In particular, your app needs to create a subclass of DeviceAdminReceiver, as described in that document.

Managed profiles

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.
To address this situation, Android 5.0 (API level 21) allows enterprises to set up a special work user profile using the Managed Profile API. This user profile is called a managed profile, or a work profile in the Android for Work program. If a device has a managed profile for work, 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.

Create a Managed Profile


To create a managed profile on a device that already has a personal profile, first check that the device can support a managed profile, by seeing if the device supports the FEATURE_MANAGED_USERS system feature:
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {

    // This device does not support native managed profiles!
}
If the device supports managed profiles, create one by sending an intent with anACTION_PROVISION_MANAGED_PROFILE action. Include the device admin package name as an extra.
Activity provisioningActivity = getActivity();
// You'll need the package name for the WPC app.
String myWPCPackageName = "com.example.myWPCApp";
// Set up the provisioning intent
Intent provisioningIntent =
        new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
intent.putExtra(myWPCPackageName,
        provisioningActivity.getApplicationContext().getPackageName());
if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
         == null) {

    // No handler for intent! Can't provision this device.
    // Show an error message and cancel.
} else {

    // REQUEST_PROVISION_MANAGED_PROFILE is defined
    // to be a suitable request code
    startActivityForResult(provisioningIntent,
            REQUEST_PROVISION_MANAGED_PROFILE);
    provisioningActivity.finish();
}
The system responds to this intent by doing the following:
  • Verifies that the device is encrypted. If it is not, the system prompts the user to encrypt the device before proceeding.
  • Creates a managed profile.
  • Removes non-required applications from the managed profile.
  • Copies the Work Policy Controller application into the managed profile and sets it as the profile owner.
Override onActivityResult() to see whether the provisioning was successful, as shown in the following example code:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    // Check if this is the result of the provisioning activity
    if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {

        // If provisioning was successful, the result code is 
        // Activity.RESULT_OK
        if (resultCode == Activity.RESULT_OK) {
            // Hurray! Managed profile created and provisioned!
        } else {
            // Boo! Provisioning failed!
        }
        return;

    } else {
        // This is the result of some other activity, call the superclass
        super.onActivityResult(requestCode, resultCode, data);
    }
}

After Creating the Managed Profile

When the profile has been provisioned, the system calls the Work Policy Controller app'sDeviceAdminReceiver.onProfileProvisioningComplete() method. Override this callback method to finish enabling the managed profile.
Typically, your DeviceAdminReceiver.onProfileProvisioningComplete() callback implementation would perform these tasks:
  • Verify that the device is complying with the EMM's device policies, as described in Set Up Device Policies
  • Enable any system applications that the administrator chooses to make available within the managed profile, using DevicePolicyManager.enableSystemApp()
  • If the device uses Google Play for Work, add the Google account to the managed profile withAccountManager.addAccount(), so administrators can install applications to the device
Once you have completed these tasks, call the device policy manager's setProfileEnabled() method to activate the managed profile:
// Get the device policy manager
DevicePolicyManager myDevicePolicyMgr =
        (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
// Set the name for the newly created managed profile.
myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
// ...and enable the profile
manager.setProfileEnabled(componentName);

Set Up Device Policies


The Work Policy Controller app is responsible for applying the enterprise's device policies. For example, a particular enterprise might require that all devices become locked after a certain number of failed attempts to enter the device password. The controller app queries the EMM to find out what the current policies are, then uses the Device Administration API to apply those policies.
For information on how to apply device policies, see the Device Administration guide.

Apply App Restrictions


Enterprise environments may require that approved apps implement apps implement security or feature restrictions. App developers must implement these restrictions and declare them for use by enterprise administrators, as described in Implementing App Restrictions. The Work Policy Controller receives restriction changes from the enterprise administrator, and forwards those restriction changes to the apps.
For example, a particular news app might have a restriction setting that controls whether the app is allowed to download videos over a cellular network. When the EMM wants to disable cellular downloads, it sends a notification to the controller app. The controller app, in turn, notifies the news app that the restriction setting has changed.
Note: This document covers how the Work Policy Controller app changes the restriction settings for the other apps on the managed profile. Details on how the Work Policy Controller app communicates with the EMM are out of scope for this document.
To change an app's restrictions, call the DevicePolicyManager.setApplicationRestrictions() method. This method is passed three parameters: the controller app's DeviceAdminReceiver, the package name of the app whose restrictions are being changed, and a Bundle that contains the restrictions you want to set.
For example, suppose there's an app on the managed profile with the package name"com.example.newsfetcher". This app has a single boolean restriction that can be configured, with the key"downloadByCellular". If this restriction is set to false, the newsfetcher app is not allowed to download data through a cellular network; it must use a Wi-Fi network instead.
If your Work Policy Controller app needs to turn off cellular downloads, it would first fetch the device policy service object, as described above. It then assembles a restrictions bundle and passes this bundle tosetApplicationRestrictions():
// Fetch the DevicePolicyManager
DevicePolicyManager myDevicePolicyMgr =
        (DevicePolicyManager) thisActivity
                .getSystemService(Context.DEVICE_POLICY_SERVICE);
// Set up the restrictions bundle
bundle restrictionsBundle = new Bundle();
restrictionsBundle.putBoolean("downloadByCellular", false);
// Pass the restrictions to the policy manager. Assume the WPC app
// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
myDevicePolicyMgr.setApplicationRestrictions(
        myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);
Note: The device policy service conveys the restrictions change to the app you name. However, it is up to that app to actually implement the restriction. For example, in this case, the app would be responsible for disabling its ability to use cellular networks for video downloads. Setting the restriction does not cause the system to enforce this restriction on the app. For more information, see Implementing App Restrictions.

Designing Effective Navigation

DEPENDENCIES AND PREREQUISITES

This class is not specific to any particular version of the Android platform. It is also primarily design-focused and does not require knowledge of the Android SDK. That said, you should have experience using an Android device for a better understanding of the context in which Android applications run.
You should also have basic familiarity with the Action Bar (pattern docs at Android Design), used across most applications in devices running Android 3.0 and later.
One of the very first steps to designing and developing an Android application is to determine what users are able to see and do with the app. Once you know what kinds of data users are interacting with in the app, the next step is to design the interactions that allow users to navigate across, into, and back out from the different pieces of content within the app.
This class shows you how to plan out the high-level screen hierarchy for your application and then choose appropriate forms of navigation to allow users to effectively and intuitively traverse your content. Each lesson covers various stages in the interaction design process for navigation in Android applications, in roughly chronological order. After going through the lessons in this class, you should be able to apply the methodology and navigation paradigms outlined here to your own applications, providing a coherent navigation experience for your users.

Lessons


Planning Screens and Their Relationships
Learn how to choose which screens your application should contain. Also learn how to choose which screens should be directly reachable from others. This lesson introduces a hypothetical news application to serve as an example for later lessons.
Planning for Multiple Touchscreen Sizes
Learn how to group related screens together on larger-screen devices to optimize use of available screen space.
Providing Descendant and Lateral Navigation
Learn about techniques for allowing users to navigate deep into, as well as across, your content hierarchy. Also learn about pros and cons of, and best practices for, specific navigational UI elements for various situations.
Providing Ancestral and Temporal Navigation
Learn how to allow users to navigate upwards in the content hierarchy. Also learn about best practices for the Back button and temporal navigation, or navigation to previous screens that may not be hierarchically related.
Putting it All Together: Wireframing the Example App
Learn how to create screen wireframes (low-fidelity graphic mockups) representing the screens in a news application based on the desired information model. These wireframes utilize navigational elements discussed in previous lessons to demonstrate intuitive and efficient navigation.

No comments:

Post a Comment