In this codelab, you'll learn how build applications for corporate-owned, single-use (COSU) devices for use cases such as digital signage, point of sale, and inventory management, by using task lock and device management APIs available in Android.

What you'll learn

What you'll need

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with building Android apps?

Novice Intermediate Proficient

You can either download all the sample code to your computer,

Download Zip

or clone the GitHub repository from the command line:

$ git clone https://github.com/googlecodelabs/cosu.git

In the sample below, you'll build an app that takes a picture and locks it to the screen of an Android device. We will start by running the finished sample app. First, you will need to add a device owner application to the device and open the completed sample app in Android Studio.

  1. Launch Android Studio
  2. Choose the "open an existing Android Studio Project" option and select the cosu_codelab_managed directory from the sample code folder
  3. Download the latest available version of TestDPC
  4. Remove all accounts from the Device
  5. Enable USB debugging on your Android device.
  6. Install TestDPC on the device and set it as device owner using the following adb commands:
adb install path/to/TestDPC.apk
adb shell dpm set-device-owner com.afwsamples.testdpc/.DeviceAdminReceiver
  1. Plug in your Android device and click the Run button. You should see the COSU App home screen appear after a few seconds.
  2. Leave the COSU app and Launch TestDPC. Scroll down to "Manage lock task list" and tap it. Enable "CosuCodelab" and tap "OK"
  3. Navigate back to COSUCodelab. Tap the "Take Picture" Button and take a picture. Feel free to take a silly selfie. Once you have a picture, tap the "Start Lock Task Mode" button. Verify that the Home and Recents buttons disappear, and that you cannot leave the COSU app, until you tap the "Stop Lock Task Mode" button.

Frequently Asked Questions

Now that you've seen COSU Mode in action, it's time to start building our own COSU app.

  1. Select the cosu_codelab_init directory from your sample code download (File > Open... >cosu_codelab_init).
  2. Click the Run button.

You should see the COSU Codelab app appear after a few seconds. Take a picture to see it appear on the screen in the app. The steps below will allow you to lock this app to the screen, displaying the picture you've taken.

We will now add task lock capabilities to our app.

We will start by adding a button to MainActivity. This button will send an Intent to LockedActivity, where we will start lock task mode.

Add Lock Button to Layout

Start by adding a button to the activity_main.xml layout in the main_button_layout as below. Note that the new button is disabled by default. It will be enabled once the user has taken a picture:

activity_main.xml

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="bottom"
        android:layout_marginRight="16dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:id="@+id/main_button_layout">

        <Button
            android:id="@+id/pic_button"
            android:text="@string/pic_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/start_lock_button"
            android:text="@string/lock_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="false"/>

    </LinearLayout>

Remember to add the lock_button string to strings.xml

strings.xml

<string name="lock_button">Start lock task mode</string>

Set Lock Button to start Lock Activity

Once you have added the button to the layout, you should update MainActivity.java to launch LockedActivity when this button is pressed.

  1. Add the button, and a DevicePolicyManager to MainActivity.java's member variables, and the String EXTRA_FILEPATH as a static member variable. The DevicePolicyManager will be used to verify whether your app is whitelisted to start lock task mode.

MainActivity.java

public class MainActivity extends Activity {

    private Button takePicButton;
    private Button lockTaskButton;
    private ImageView imageView;
    private String mCurrentPhotoPath;
    private int permissionCheck;
    public DevicePolicyManager mDevicePolicyManager;

    public static final String EXTRA_FILEPATH = 
            "com.google.codelabs.cosu.EXTRA_FILEPATH";

  1. Add the following code in the onCreate(...) method of MainActivity.java, just below takePicButton.setOnClickListener(...) This code initializes the device policy manager, and implements the button which will start lock task mode. When the button is tapped, as long as the app is whitelisted correctly, it will start the lock task mode activity.

MainActivity.java

mDevicePolicyManager = (DevicePolicyManager)
    getSystemService(Context.DEVICE_POLICY_SERVICE);

lockTaskButton = (Button) findViewById(R.id.start_lock_button);
lockTaskButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if ( mDevicePolicyManager.isLockTaskPermitted(
                getApplicationContext().getPackageName())) {
            Intent lockIntent = new Intent(getApplicationContext(),
                    LockedActivity.class);
            lockIntent.putExtra(EXTRA_FILEPATH, mCurrentPhotoPath);
            startActivity(lockIntent);
            finish();
        } else {
            Toast.makeText(getApplicationContext(),
                    R.string.not_lock_whitelisted,Toast.LENGTH_SHORT)
                    .show();
        }
    }
});
  1. Add the following in the setImageToView() method, just below imageView.setImageBitmap(...). This will enable the start lock task mode button once the user has taken a picture.

MainActivity.java

lockTaskButton.setEnabled(true);

Now we will build the Activity that will start lock task mode. Once it receives the intent from MainActivity, it will display the image the user has taken and then start lock task mode.

Create Activity Layout and add locking functionality

  1. Replace the text in activity_locked.xml with the following:

activity_locked.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.google.codelabs.cosu.LockedActivity">

    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/linearLayout"
        android:layout_above="@+id/lock_button_layout"
        android:layout_alignParentEnd="true"
        android:layout_alignParentTop="true"
        android:layout_alignStart="@+id/lock_button_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/lock_imageView"
            android:contentDescription="@string/lock_image_description"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="bottom"
        android:layout_marginRight="16dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:id="@+id/lock_button_layout">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/stop_lock_button"
            android:id="@+id/stop_lock_button"/>

    </LinearLayout>

</RelativeLayout>
  1. Add the following member variables to LockedActivity.java

LockedActivity.java

public class LockedActivity extends Activity {

    private ImageView imageView;
    private Button stopLockButton;
    private String mCurrentPhotoPath;
    private DevicePolicyManager mDevicePolicyManager;

    private static final String PREFS_FILE_NAME = "MyPrefsFile";
    private static final String PHOTO_PATH = "Photo Path";
  1. Replace the onCreate(...) method for LockedActivity.java with the code below:

LockedActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_locked);

    mDevicePolicyManager = (DevicePolicyManager)
            getSystemService(Context.DEVICE_POLICY_SERVICE);

    // Setup stop lock task button
    stopLockButton = (Button) findViewById(R.id.stop_lock_button);
    stopLockButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ActivityManager am = (ActivityManager) getSystemService(
                    Context.ACTIVITY_SERVICE);
            if (am.getLockTaskModeState() ==
                    ActivityManager.LOCK_TASK_MODE_LOCKED) {
                stopLockTask();
            }
            Intent intent = new Intent(
                    getApplicationContext(), MainActivity.class);
            startActivity(intent);
            finish();
        }
    });

    // Set image to View
    setImageToView();
}
  1. You also need to implement the LockedActivity.setImageToView() method used in onCreate(...). It is similar to the MainActivity.setImageToView() method, Add the code below to LockedActivity.

LockedActivity.java

private void setImageToView(){

    // Restore preferences
    SharedPreferences settings = getSharedPreferences(PREFS_FILE_NAME, 0);
    String savedPhotoPath = settings.getString(PHOTO_PATH, null);

    //Initialize the image view and display the picture if one exists
    imageView = (ImageView) findViewById(R.id.lock_imageView);
    Intent intent = getIntent();

    String passedPhotoPath = intent.getStringExtra(
            MainActivity.EXTRA_FILEPATH);
    if (passedPhotoPath != null) {
        mCurrentPhotoPath = passedPhotoPath;
    } else {
        mCurrentPhotoPath = savedPhotoPath;
    }

    if (mCurrentPhotoPath != null) {
        int targetH = imageView.getMaxHeight();
        int targetW = imageView.getMaxWidth();

        // Get the dimensions of the bitmap
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        int photoH = bmOptions.outHeight;
        int photoW = bmOptions.outWidth;

        // Determine how much to scale down image
        int scaleFactor = Math.min(photoW/targetW, photoH/targetH);


        // Decode the image file into a Bitmap sized to fill the View
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;

        Bitmap imageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath,
                bmOptions);
        imageView.setImageBitmap(imageBitmap);
    }
}
  1. Add the following onStart() method to LockedActivity.java, which will lock LockedActivity to the user's screen.

LockedActivity.java

@Override
protected void onStart() {
    super.onStart();

    // Start lock task mode if its not already active
    if(mDevicePolicyManager.isLockTaskPermitted(this.getPackageName())){
        ActivityManager am = (ActivityManager) getSystemService(
                Context.ACTIVITY_SERVICE);
        if (am.getLockTaskModeState() ==
                ActivityManager.LOCK_TASK_MODE_NONE) {
            startLockTask();
        }
    }
}
  1. Lastly, save the photo being used in SharedPreferences by adding the following onStop() method to LockedActivity.java

LockedActivity.java

@Override
protected void onStop(){
    super.onStop();

    // Get editor object and make preference changes to save photo filepath
    SharedPreferences settings = getSharedPreferences(PREFS_FILE_NAME, 0);
    SharedPreferences.Editor editor = settings.edit();
    editor.putString(PHOTO_PATH, mCurrentPhotoPath);
    editor.commit();
}

Test your application. You'll need to use a sample Device Owner application to whitelist your app for lock task mode before testing. If you have already installed TestDPC onto the device and set it as device owner, you can skip steps 1-3.

  1. Download the latest available version of TestDPC
  2. Enable USB debugging on your Android device.
  3. Install TestDPC on the device and set it as device owner using the following adb commands:
adb install path/to/TestDPC.apk
adb shell dpm set-device-owner com.afwsamples.testdpc/.DeviceAdminReceiver
  1. Plug in your Android device and click the Run button. You should see the COSU App home screen appear after a few seconds.
  2. Leave the COSU app and Launch TestDPC. Scroll down to "Manage lock task list" and tap it. Enable "CosuCodelab" and tap "OK"
  3. Navigate back to COSUCodelab. Tap the "Take Picture" Button and take a picture. Feel free to take a silly selfie. Once you have a picture, tap the "Start Lock Task Mode" button. Verify that the Home and Recents buttons disappear, and that you cannot leave the COSU app, until you tap the "Stop Lock Task Mode" button.

Your app can now lock itself to the screen! Note that you can add the management functionality included in TestDPC, and make your app a device owner as well in order to avoid the need for a separate management app.

What we've covered

Next Steps

Learn More