Basic sample

This section shows you how to create a cross-profile hello world call within your app. This will give you familiarity with the SDK and an initial implementation to build on top of. You are recommended to actively follow along by developing in your app.

Set up a test device with a work profile

Google builds the Test DPC app to help you simulate and test a managed environment on your own device. It will set up a work profile and provide you with controls to enable or disable certain features on the device.

  • Install the Test DPC app

    Open the Google Play Store and download the Test DPC app.

  • Set up a work profile

    One the app is installed, you should see two icons appear on the device, a setup icon and the Test DPC app icon. Tap the setup icon and follow the steps.

Now you have two separate profiles, one for personal apps and one for work apps. You can switch between them through the tabs at the top of the app list.

personal/work
profile

When installing your app, it will normally automatically install in both profiles. If you ever need to install it explicitly into the work profile, you can use the --user argument with adb install.

  $ 
adb  
install  
--user  
 [ 
id  
number  
of  
profile ] 
  
 [ 
path  
of  
apk  
file ] 
 

For more details about setting up a test device, visit this link.

Ensure your application is configured appropriately

Enable java 8 support and ensure your minSdk is at least 19.

Add gradle dependencies

  dependencies 
  
 { 
  
 annotationProcessor 
 ' 
 com 
 . 
 google 
 . 
 android 
 . 
 enterprise 
 . 
 connectedapps 
 : 
 connectedapps 
 - 
 processor 
 : 
 1.1.2 
 ' 
  
 implementation 
 ' 
 com 
 . 
 google 
 . 
 android 
 . 
 enterprise 
 . 
 connectedapps 
 : 
 connectedapps 
 : 
 1.1.2 
 ' 
  
 implementation 
 ' 
 com 
 . 
 google 
 . 
 android 
 . 
 enterprise 
 . 
 connectedapps 
 : 
 connectedapps 
 - 
 annotations 
 : 
 1.1.2 
 ' 
 } 
 

We use Guava in this example. This is not a requirement of using the SDK, but to follow along with the hello world you should also add api("com.google.guava:guava:29.0-android") .

Create a new class that will contain your test cross-profile call

To make this more useful later, you should put it in the same package that you would like your real cross-profile calls to go in.

  public 
  
 class 
 HelloWorld 
  
 { 
  
 @CrossProfile 
  
 public 
  
 ListenableFuture<String> 
  
 helloWorld 
 () 
  
 { 
  
 return 
  
 Futures 
 . 
 immediateFuture 
 ( 
 "Hello world" 
 ); 
  
 } 
 } 
 

If you can't depend on Guava for Futures support, just follow along for now and then see the final step which tells you which changes to make.

Make a cross-profile call

You could do this in a class that will need to make real cross-profile calls later.

  // TODO: inject/pass these into the class later instead. 
 CrossProfileConnector 
  
 crossProfileConnector 
  
 = 
  
 CrossProfileConnector 
 . 
 builder 
 ( 
 this 
 ). 
 build 
 (); 
 ProfileHelloWorld 
  
 profileHelloWorld 
  
 = 
  
 ProfileHelloWorld 
 . 
 create 
 ( 
 crossProfileConnector 
 ); 
 ListenableFuture<Map<Profile 
 , 
  
 String 
>>  
 resultsFuture 
  
 = 
  
 profileHelloWorld 
 . 
 both 
 (). 
 helloWorld 
 (); 
 FluentFuture 
 . 
 from 
 ( 
 resultsFuture 
 ) 
  
 . 
 addCallback 
 ( 
 new 
  
 FutureCallback<Map<Profile 
 , 
  
 String 
>> () 
  
 { 
  
 @Override 
  
 public 
  
 void 
  
 onSuccess 
 ( 
 Map<Profile 
 , 
  
 String 
>  
 results 
 ) 
  
 { 
  
 for 
  
 ( 
 Profile 
  
 profile 
  
 : 
  
 results 
 . 
 keySet 
 ()) 
  
 { 
  
 Log 
 . 
 w 
 ( 
 "tag" 
 , 
  
 "CROSS_PROFILE profile: " 
  
 + 
  
 profile 
 . 
 asInt 
 () 
  
 + 
  
 "; result: " 
  
 + 
  
 results 
 . 
 get 
 ( 
 profile 
 )); 
  
 } 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onFailure 
 ( 
 Throwable 
  
 t 
 ) 
  
 { 
  
 Log 
 . 
 e 
 ( 
 TAG 
 , 
  
 "Failed to say hello world on both profiles" 
 , 
  
 t 
 ); 
  
 } 
  
 }, 
  
 directExecutor 
 ()); 
 

Provide the instance to the SDK

Of course, the helloWorld method call mentioned earlier is on a generated class and not the real one. Often, your real classes are singletons or other complex classes dependent on dependency injection frameworks such as Dagger. To allow the logic to be called on the real class on the other profile, each custom @CrossProfile class must have a corresponding provider method in a @CrossProfileProvider class. Create this class.

  public 
  
 class 
 HelloWorldProvider 
  
 { 
  
 @CrossProfileProvider 
  
 public 
  
 HelloWorld 
  
 getHelloWorld 
 () 
  
 { 
  
 return 
  
 new 
  
 HelloWorld 
 (); 
  
 } 
 } 
 

Additional wiring

The code generation required to support custom classes and methods requires a small amount of additional wiring. This is to handle the complexities of having many build targets and visibility requirements at scale.

Firstly, annotate an existing or new high-level class with @CrossProfileConfiguration , pointing to your provider classes.

  @CrossProfileConfiguration 
 ( 
 providers 
  
 = 
  
 HelloWorldProvider 
 . 
 class 
 ) 
 abstract 
  
 class 
 HelloWorldConfiguration 
  
 {} 
 

Secondly, add the automatically-generated service to your manifest, inside the <application> tag . This may not resolve until you build your project.

 < service 
 android 
 : 
 name 
 = 
 "com.google.android.enterprise.connectedapps.CrossProfileConnector_Service" 
 android 
 : 
 exported 
 = 
 "false" 
 / 
> 

Finally, for development purposes, give yourself the INTERACT_ACROSS_USERS permission. If you don't have it already, you won't be able to keep this in production, but it's the easiest way to get started. Firstly, add it to your manifest as follows:

 < uses 
 - 
 permission 
  
 android 
 : 
 name 
 = 
 "android.permission.INTERACT_ACROSS_USERS" 
  
 tools 
 : 
 ignore 
 = 
 "ProtectedPermissions" 
 / 
> 

Then, you can grant yourself the permission from the command line with adb as follows (if your app does not already have it):

  adb shell pm grant <your package> android.permission.INTERACT_ACROSS_USERS 
 

If you were not able to depend on Guava for Futures, you will need to make a few changes. Firstly, return the "Hello World" string directly and print the results of the cross-profile call out. Secondly, since these calls are now synchronous, you should place your cross-profile call and printing of results inside the connection listener.

When you run the code listed under ''make a cross-profile cal'' you should see two logs for ''Hello World'', one from each profile. If you only get one log, make sure you've installed your app in both profiles and have granted the permission.

Design a Mobile Site
View Site in Mobile | Classic
Share by: