Auto-grant background execution and data access

Companion apps can declare they want background access and
background execution exceptions via dedicated permissions
in their manifest. If such a permission is requested we
auto-grant the corresponding exception after the user has
chosen a device from the companion UI. These permissions
are appop ones allowing us to use the app ops for gauging
whether the user has made a change after we auto-granted
the permission since we would like to revoke these special
privileges when the app disassociates itself from the
companion device if the user did not make an excplicit
choice otherwise.

While at this auto-grant fixed location permission to the
companion device discovery service.

Test: manual

Change-Id: I46ee4291e5e5a8f7613f0dd75eb61d6b9341f306
diff --git a/Android.mk b/Android.mk
index 28adbca..7a8b1b7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -295,9 +295,9 @@
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
 	core/java/android/companion/ICompanionDeviceManager.aidl \
-	core/java/android/companion/ICompanionDeviceManagerService.aidl \
-	core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl \
-	core/java/android/companion/IOnAssociateCallback.aidl \
+	core/java/android/companion/ICompanionDeviceDiscoveryService.aidl \
+	core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl \
+	core/java/android/companion/IFindDeviceCallback.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
diff --git a/api/current.txt b/api/current.txt
index a03ef38..c500508 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -121,6 +121,7 @@
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
+    field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -139,6 +140,7 @@
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+    field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND";
     field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
     field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
diff --git a/api/system-current.txt b/api/system-current.txt
index 406d51c..54de0c6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -211,6 +211,7 @@
     field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
+    field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND";
     field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
@@ -248,6 +249,7 @@
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
+    field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND";
     field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
     field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
diff --git a/api/test-current.txt b/api/test-current.txt
index 1be19ed..b9cf94d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -121,6 +121,7 @@
     field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
+    field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
     field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -139,6 +140,7 @@
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+    field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND";
     field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
     field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fb927e9..6dd31a8 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -357,7 +357,8 @@
     public static final String OPSTR_INSTANT_APP_START_FOREGROUND
             = "android:instant_app_start_foreground";
 
-    private static final int[] RUNTIME_PERMISSIONS_OPS = {
+    private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
+            // RUNTIME PERMISSIONS
             // Contacts
             OP_READ_CONTACTS,
             OP_WRITE_CONTACTS,
@@ -392,7 +393,13 @@
             // Camera
             OP_CAMERA,
             // Body sensors
-            OP_BODY_SENSORS
+            OP_BODY_SENSORS,
+
+            // APPOP PERMISSIONS
+            OP_ACCESS_NOTIFICATIONS,
+            OP_SYSTEM_ALERT_WINDOW,
+            OP_WRITE_SETTINGS,
+            OP_REQUEST_INSTALL_PACKAGES,
     };
 
     /**
@@ -926,9 +933,9 @@
             AppOpsManager.MODE_ALLOWED,  // OP_RUN_IN_BACKGROUND
             AppOpsManager.MODE_ALLOWED,  // OP_AUDIO_ACCESSIBILITY_VOLUME
             AppOpsManager.MODE_ALLOWED,
-            AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
+            AppOpsManager.MODE_DEFAULT,  // OP_REQUEST_INSTALL_PACKAGES
             AppOpsManager.MODE_ALLOWED,  // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
-            AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
+            AppOpsManager.MODE_DEFAULT,  // OP_INSTANT_APP_START_FOREGROUND
     };
 
     /**
@@ -1018,7 +1025,7 @@
     /**
      * Mapping from a permission to the corresponding app op.
      */
-    private static HashMap<String, Integer> sRuntimePermToOp = new HashMap<>();
+    private static HashMap<String, Integer> sPermToOp = new HashMap<>();
 
     static {
         if (sOpToSwitch.length != _NUM_OP) {
@@ -1058,9 +1065,9 @@
                 sOpStrToOp.put(sOpToString[i], i);
             }
         }
-        for (int op : RUNTIME_PERMISSIONS_OPS) {
+        for (int op : RUNTIME_AND_APPOP_PERMISSIONS_OPS) {
             if (sOpPerms[op] != null) {
-                sRuntimePermToOp.put(sOpPerms[op], op);
+                sPermToOp.put(sOpPerms[op], op);
             }
         }
     }
@@ -1112,12 +1119,12 @@
 
     /**
      * Retrieve the app op code for a permission, or null if there is not one.
-     * This API is intended to be used for mapping runtime permissions to the
-     * corresponding app op.
+     * This API is intended to be used for mapping runtime or appop permissions
+     * to the corresponding app op.
      * @hide
      */
     public static int permissionToOpCode(String permission) {
-        Integer boxedOpCode = sRuntimePermToOp.get(permission);
+        Integer boxedOpCode = sPermToOp.get(permission);
         return boxedOpCode != null ? boxedOpCode : OP_NONE;
     }
 
@@ -1462,7 +1469,7 @@
      * @return The app op associated with the permission or null.
      */
     public static String permissionToOp(String permission) {
-        final Integer opCode = sRuntimePermToOp.get(permission);
+        final Integer opCode = sPermToOp.get(permission);
         if (opCode == null) {
             return null;
         }
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index b379c7c..c0c1a4d 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -29,12 +29,10 @@
 /**
  * System level service for managing companion devices
  *
- * Usage:
- * To obtain an instance call
- * {@link Context#getSystemService}({@link Context#COMPANION_DEVICE_SERVICE})
- *
- * Then, call {@link #associate} to initiate the flow of associating current package
- * with a device selected by user
+ * <p>To obtain an instance call {@link Context#getSystemService}({@link
+ * Context#COMPANION_DEVICE_SERVICE}) Then, call {@link #associate(AssociationRequest,
+ * Callback, Handler)} to initiate the flow of associating current package with a
+ * device selected by user.</p>
  *
  * @see AssociationRequest
  */
@@ -47,6 +45,14 @@
     public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
 
     /**
+     * The package name of the companion device discovery component.
+     *
+     * @hide
+     */
+    public static final String COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME =
+            "com.android.companiondevicemanager";
+
+    /**
      * A callback to receive once at least one suitable device is found, or the search failed
      * (e.g. timed out)
      */
@@ -81,13 +87,20 @@
     /**
      * Associate this app with a companion device, selected by user
      *
-     * Once at least one appropriate device is found, {@code callback} will be called with a
+     * <p>Once at least one appropriate device is found, {@code callback} will be called with a
      * {@link PendingIntent} that can be used to show the list of available devices for the user
      * to select.
      * It should be started for result (i.e. using
      * {@link android.app.Activity#startIntentSenderForResult}), as the resulting
      * {@link android.content.Intent} will contain extra {@link #EXTRA_DEVICE}, with the selected
-     * device. (e.g. {@link android.bluetooth.BluetoothDevice})
+     * device. (e.g. {@link android.bluetooth.BluetoothDevice})</p>
+     *
+     * <p>If your app needs to be excluded from battery optimizations (run in the background)
+     * or to have unrestricted data access (use data in the background) you can declare that
+     * you use the {@link android.Manifest.permission#RUN_IN_BACKGROUND} and {@link
+     * android.Manifest.permission#USE_DATA_IN_BACKGROUND} respectively. Note that these
+     * special capabilities have a negative effect on the device's battery and user's data
+     * usage, therefore you should requested them when absolutely necessary.</p>
      *
      * @param request specific details about this request
      * @param callback will be called once there's at least one device found for user to choose from
@@ -106,17 +119,16 @@
         try {
             mService.associate(
                     request,
-                    new IOnAssociateCallback.Stub() {
-
+                    new IFindDeviceCallback.Stub() {
                         @Override
-                        public void onSuccess(PendingIntent launcher) throws RemoteException {
+                        public void onSuccess(PendingIntent launcher) {
                             finalHandler.post(() -> {
                                 callback.onDeviceFound(launcher.getIntentSender());
                             });
                         }
 
                         @Override
-                        public void onFailure(CharSequence reason) throws RemoteException {
+                        public void onFailure(CharSequence reason) {
                             finalHandler.post(() -> callback.onFailure(reason));
                         }
                     },
diff --git a/core/java/android/companion/ICompanionDeviceManagerService.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
similarity index 71%
rename from core/java/android/companion/ICompanionDeviceManagerService.aidl
rename to core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
index ff2a7eb..4d77963 100644
--- a/core/java/android/companion/ICompanionDeviceManagerService.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
@@ -17,13 +17,14 @@
 package android.companion;
 
 import android.companion.AssociationRequest;
-import android.companion.IOnAssociateCallback;
-
+import android.companion.ICompanionDeviceDiscoveryServiceCallback;
+import android.companion.IFindDeviceCallback;
 
 /** @hide */
-interface ICompanionDeviceManagerService {
+interface ICompanionDeviceDiscoveryService {
     void startDiscovery(
         in AssociationRequest request,
-        in IOnAssociateCallback callback,
-        in String callingPackage);
+        in String callingPackage,
+        in IFindDeviceCallback findCallback,
+        in ICompanionDeviceDiscoveryServiceCallback serviceCallback);
 }
diff --git a/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
similarity index 81%
rename from core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
rename to core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
index c9dd345..7af708e 100644
--- a/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
@@ -16,9 +16,7 @@
 
 package android.companion;
 
-import android.bluetooth.BluetoothDevice;
-
 /** @hide */
-interface ICompanionDeviceManagerServiceCallback {
-    void onDeviceSelected(in BluetoothDevice device);
+interface ICompanionDeviceDiscoveryServiceCallback {
+    void onDeviceSelected(String packageName, int userId);
 }
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 065e31b..1d30ada 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -16,7 +16,7 @@
 
 package android.companion;
 
-import android.companion.IOnAssociateCallback;
+import android.companion.IFindDeviceCallback;
 import android.companion.AssociationRequest;
 
 /**
@@ -26,8 +26,8 @@
  */
 interface ICompanionDeviceManager {
     void associate(in AssociationRequest request,
-        in IOnAssociateCallback callback,
-        in String callingPackage); //TODO int userId?
+        in IFindDeviceCallback callback,
+        in String callingPackage);
 
     //TODO add these
 //    boolean haveNotificationAccess(String packageName);
diff --git a/core/java/android/companion/IOnAssociateCallback.aidl b/core/java/android/companion/IFindDeviceCallback.aidl
similarity index 95%
rename from core/java/android/companion/IOnAssociateCallback.aidl
rename to core/java/android/companion/IFindDeviceCallback.aidl
index 4867eadd..919e1519 100644
--- a/core/java/android/companion/IOnAssociateCallback.aidl
+++ b/core/java/android/companion/IFindDeviceCallback.aidl
@@ -19,7 +19,7 @@
 import android.app.PendingIntent;
 
 /** @hide */
-interface IOnAssociateCallback {
+interface IFindDeviceCallback {
     void onSuccess(in PendingIntent launcher);
     void onFailure(in CharSequence reason);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cd02fbb..97fbfa5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1813,6 +1813,22 @@
         android:description="@string/permdesc_systemAlertWindow"
         android:protectionLevel="signature|preinstalled|appop|pre23|development" />
 
+    <!-- Allows an app to run in the background.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.RUN_IN_BACKGROUND"
+        android:label="@string/permlab_runInBackground"
+        android:description="@string/permdesc_runInBackground"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an app to use data in the background.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.USE_DATA_IN_BACKGROUND"
+        android:label="@string/permlab_useDataInBackground"
+        android:description="@string/permdesc_useDataInBackground"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
     <!-- ================================== -->
@@ -2996,7 +3012,7 @@
          any metadata and intents attached.
          @hide -->
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged|appop" />
 
     <!-- Marker permission for applications that wish to access notification policy.
          <p>Protection level: normal
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2309866..8faa76c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -816,6 +816,16 @@
     <string name="permdesc_systemAlertWindow">This app can appear on top of other apps or other parts of the screen. This may interfere with normal app usage and change the way that other apps appear.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_runInBackground">run in the background</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_runInBackground">This app can run in the background. This may drain battery faster.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_useDataInBackground">use data in the background</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_useDataInBackground">This app can use data in the background. This may increase data usage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_persistentActivity">make app always run</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the tablet.</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 8a970da..25127ef 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -33,7 +33,6 @@
 import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 public class DeviceChooserActivity extends Activity {
 
@@ -129,12 +128,9 @@
     }
 
     protected void onPairTapped(BluetoothDevice selectedDevice) {
+        getService().onDeviceSelected();
         setResult(RESULT_OK,
                 new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice));
         finish();
     }
-
-    private void toast(String msg) {
-        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
-    }
 }
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index ccbee2a..11c722d 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -32,16 +32,15 @@
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
 import android.companion.AssociationRequest;
-import android.companion.BluetoothDeviceFilterUtils;
 import android.companion.BluetoothLEDeviceFilter;
-import android.companion.ICompanionDeviceManagerService;
-import android.companion.IOnAssociateCallback;
+import android.companion.ICompanionDeviceDiscoveryService;
+import android.companion.ICompanionDeviceDiscoveryServiceCallback;
+import android.companion.IFindDeviceCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Color;
-import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -70,21 +69,25 @@
     List<BluetoothDevice> mDevicesFound;
     BluetoothDevice mSelectedDevice;
     DevicesAdapter mDevicesAdapter;
-    IOnAssociateCallback mCallback;
+    IFindDeviceCallback mFindCallback;
+    ICompanionDeviceDiscoveryServiceCallback mServiceCallback;
     String mCallingPackage;
 
-    private final ICompanionDeviceManagerService mBinder =
-            new ICompanionDeviceManagerService.Stub() {
+    private final ICompanionDeviceDiscoveryService mBinder =
+            new ICompanionDeviceDiscoveryService.Stub() {
         @Override
         public void startDiscovery(AssociationRequest request,
-                IOnAssociateCallback callback,
-                String callingPackage) throws RemoteException {
+                String callingPackage,
+                IFindDeviceCallback findCallback,
+                ICompanionDeviceDiscoveryServiceCallback serviceCallback) {
             if (DEBUG) {
                 Log.i(LOG_TAG,
-                        "startDiscovery() called with: filter = [" + request + "], callback = ["
-                                + callback + "]");
+                        "startDiscovery() called with: filter = [" + request
+                                + "], findCallback = [" + findCallback + "]"
+                                + "], serviceCallback = [" + serviceCallback + "]");
             }
-            mCallback = callback;
+            mFindCallback = findCallback;
+            mServiceCallback = serviceCallback;
             mCallingPackage = callingPackage;
             DeviceDiscoveryService.this.startDiscovery(request);
         }
@@ -171,6 +174,14 @@
         return super.onUnbind(intent);
     }
 
+    public void onDeviceSelected() {
+        try {
+            mServiceCallback.onDeviceSelected(mCallingPackage, getUserId());
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Error reporting selected device");
+        }
+    }
+
     private void stopScan() {
         if (DEBUG) Log.i(LOG_TAG, "stopScan() called");
         mBluetoothAdapter.cancelDiscovery();
@@ -205,7 +216,7 @@
     //TODO also, on timeout -> call onFailure
     private void onReadyToShowUI() {
         try {
-            mCallback.onSuccess(PendingIntent.getActivity(
+            mFindCallback.onSuccess(PendingIntent.getActivity(
                     this, 0,
                     new Intent(this, DeviceChooserActivity.class),
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 9da94b3..06b6f66 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.app.DownloadManager;
 import android.app.admin.DevicePolicyManager;
+import android.companion.CompanionDeviceManager;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -673,6 +674,16 @@
                     && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
                 grantRuntimePermissionsLPw(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
             }
+
+            // Companion devices
+            PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackageLPr(
+                    CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
+            if (companionDeviceDiscoveryPackage != null
+                    && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
+                grantRuntimePermissionsLPw(companionDeviceDiscoveryPackage,
+                        LOCATION_PERMISSIONS, true, userId);
+            }
+
             mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
index 9824c1d..9ac8295 100644
--- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
+++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
@@ -19,20 +19,28 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.app.PendingIntent;
+import android.Manifest;
 import android.companion.AssociationRequest;
+import android.companion.CompanionDeviceManager;
+import android.companion.ICompanionDeviceDiscoveryService;
+import android.companion.ICompanionDeviceDiscoveryServiceCallback;
 import android.companion.ICompanionDeviceManager;
-import android.companion.ICompanionDeviceManagerService;
-import android.companion.IOnAssociateCallback;
+import android.companion.IFindDeviceCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.NetworkPolicyManager;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.IDeviceIdleController;
 import android.os.RemoteException;
-import android.util.Log;
+import android.os.ServiceManager;
+import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemService;
 
 //TODO move to own package!
@@ -40,7 +48,8 @@
 public class CompanionDeviceManagerService extends SystemService {
 
     private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
-            "com.android.companiondevicemanager", ".DeviceDiscoveryService");
+            CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
+            ".DeviceDiscoveryService");
 
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "CompanionDeviceManagerService";
@@ -58,14 +67,13 @@
     }
 
     class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
-
         @Override
         public void associate(
                 AssociationRequest request,
-                IOnAssociateCallback callback,
-                String callingPackage) throws RemoteException {
+                IFindDeviceCallback callback,
+                String callingPackage) {
             if (DEBUG) {
-                Log.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
+                Slog.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
                         + ", callingPackage = " + callingPackage + ")");
             }
             checkNotNull(request);
@@ -85,23 +93,24 @@
 
     private ServiceConnection getServiceConnection(
             final AssociationRequest<?> request,
-            final IOnAssociateCallback callback,
+            final IFindDeviceCallback findDeviceCallback,
             final String callingPackage) {
         return new ServiceConnection() {
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 if (DEBUG) {
-                    Log.i(LOG_TAG,
+                    Slog.i(LOG_TAG,
                             "onServiceConnected(name = " + name + ", service = "
                                     + service + ")");
                 }
                 try {
-                    ICompanionDeviceManagerService.Stub
+                    ICompanionDeviceDiscoveryService.Stub
                             .asInterface(service)
                             .startDiscovery(
                                     request,
-                                    getCallback(callingPackage, callback),
-                                    callingPackage);
+                                    callingPackage,
+                                    findDeviceCallback,
+                                    getServiceCallback());
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
@@ -109,39 +118,50 @@
 
             @Override
             public void onServiceDisconnected(ComponentName name) {
-                if (DEBUG) Log.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")");
+                if (DEBUG) Slog.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")");
             }
         };
     }
 
-    private IOnAssociateCallback.Stub getCallback(
-            String callingPackage,
-            IOnAssociateCallback propagateTo) {
-        return new IOnAssociateCallback.Stub() {
-
+    private ICompanionDeviceDiscoveryServiceCallback.Stub getServiceCallback() {
+        return new ICompanionDeviceDiscoveryServiceCallback.Stub() {
             @Override
-            public void onSuccess(PendingIntent launcher)
-                    throws RemoteException {
-                if (DEBUG) Log.i(LOG_TAG, "onSuccess(launcher = " + launcher + ")");
-                recordSpecialPriviledgesForPackage(callingPackage);
-                propagateTo.onSuccess(launcher);
-            }
-
-            @Override
-            public void onFailure(CharSequence reason) throws RemoteException {
-                if (DEBUG) Log.i(LOG_TAG, "onFailure()");
-                propagateTo.onFailure(reason);
+            public void onDeviceSelected(String packageName, int userId) {
+                grantSpecialAccessPermissionsIfNeeded(packageName, userId);
             }
         };
     }
 
-    void recordSpecialPriviledgesForPackage(String priviledgedPackage) {
-        //TODO Show dialog before recording notification access
-//        final SettingStringHelper setting =
-//                new SettingStringHelper(
-//                        getContext().getContentResolver(),
-//                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-//                        Binder.getCallingUid());
-//        setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage));
+    private void grantSpecialAccessPermissionsIfNeeded(String packageName, int userId) {
+        final long identity = Binder.clearCallingIdentity();
+        final PackageInfo packageInfo;
+        try {
+            packageInfo = getContext().getPackageManager().getPackageInfoAsUser(
+                    packageName, PackageManager.GET_PERMISSIONS, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.e(LOG_TAG, "Error granting special access permissions to package:"
+                    + packageName, e);
+            return;
+        }
+        try {
+            if (ArrayUtils.contains(packageInfo.requestedPermissions,
+                    Manifest.permission.RUN_IN_BACKGROUND)) {
+                IDeviceIdleController idleController = IDeviceIdleController.Stub.asInterface(
+                        ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
+                try {
+                    idleController.addPowerSaveWhitelistApp(packageName);
+                } catch (RemoteException e) {
+                    /* ignore - local call */
+                }
+            }
+            if (ArrayUtils.contains(packageInfo.requestedPermissions,
+                    Manifest.permission.USE_DATA_IN_BACKGROUND)) {
+                NetworkPolicyManager.from(getContext()).addUidPolicy(
+                        packageInfo.applicationInfo.uid,
+                        NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 }