1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package android.companion; 19 20 import android.annotation.MainThread; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.Service; 24 import android.content.Intent; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.util.Log; 28 29 import com.android.internal.util.function.pooled.PooledLambda; 30 31 import java.util.Objects; 32 33 /** 34 * Service to be implemented by apps that manage a companion device. 35 * 36 * System will keep this service bound whenever an associated device is nearby, 37 * ensuring app stays alive. 38 * 39 * An app must be {@link CompanionDeviceManager#associate associated} with at leas one device, 40 * before it can take advantage of this service. 41 * 42 * You must declare this service in your manifest with an 43 * intent-filter action of {@link #SERVICE_INTERFACE} and 44 * permission of {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE} 45 */ 46 public abstract class CompanionDeviceService extends Service { 47 48 private static final String LOG_TAG = "CompanionDeviceService"; 49 50 /** 51 * An intent action for a service to be bound whenever this app's companion device(s) 52 * are nearby. 53 * 54 * <p>The app will be kept alive for as long as the device is nearby. 55 * If the app is not running at the time device gets connected, the app will be woken up.</p> 56 * 57 * <p>Shortly after the device goes out of range, the service will be unbound, and the 58 * app will be eligible for cleanup, unless any other user-visible components are running.</p> 59 * 60 * <p>An app shouldn't declare more than one of these services. 61 * If running in background is not essential for the devices that this app can manage, 62 * app should avoid declaring this service.</p> 63 * 64 * <p>The service must also require permission 65 * {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}</p> 66 */ 67 public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService"; 68 69 private final Stub mRemote = new Stub(); 70 71 /** 72 * Called by system whenever a device associated with this app is available. 73 * 74 * @param address the MAC address of the device 75 */ 76 @MainThread onDeviceAppeared(@onNull String address)77 public abstract void onDeviceAppeared(@NonNull String address); 78 79 /** 80 * Called by system whenever a device associated with this app stops being available. 81 * 82 * Usually this means the device goes out of range or is turned off. 83 * 84 * @param address the MAC address of the device 85 */ 86 @MainThread onDeviceDisappeared(@onNull String address)87 public abstract void onDeviceDisappeared(@NonNull String address); 88 89 @Nullable 90 @Override onBind(@onNull Intent intent)91 public final IBinder onBind(@NonNull Intent intent) { 92 if (Objects.equals(intent.getAction(), SERVICE_INTERFACE)) { 93 return mRemote; 94 } 95 Log.w(LOG_TAG, 96 "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + "): " + intent); 97 return null; 98 } 99 100 class Stub extends ICompanionDeviceService.Stub { 101 102 @Override onDeviceAppeared(String address)103 public void onDeviceAppeared(String address) { 104 Handler.getMain().sendMessage(PooledLambda.obtainMessage( 105 CompanionDeviceService::onDeviceAppeared, 106 CompanionDeviceService.this, address)); 107 } 108 109 @Override onDeviceDisappeared(String address)110 public void onDeviceDisappeared(String address) { 111 Handler.getMain().sendMessage(PooledLambda.obtainMessage( 112 CompanionDeviceService::onDeviceDisappeared, 113 CompanionDeviceService.this, address)); 114 } 115 } 116 } 117