1 /*
2  * Copyright (C) 2021 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 package com.google.android.tv.btservices.remote;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.content.Context;
21 import com.google.android.tv.btservices.R;
22 import java.util.concurrent.CompletableFuture;
23 import java.util.UUID;
24 
25 public abstract class RemoteProxy {
26 
27     private static final String TAG = "Atv.RemoteProxy";
28     private static final boolean DEBUG = false;
29 
30     public static final int DEFAULT_LOW_BATTERY_LEVEL = 20;
31     public static final int DEFAULT_CRITICAL_BATTERY_LEVEL = 0;
32 
33     // Battery Info Profile
34     public static final UUID UUID_BATTERY_SERVICE =
35             UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
36     public static final UUID UUID_BATTERY_LEVEL_CHARACTERISTIC =
37             UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
38     public static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID =
39             UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
40     // Version info
41     public static final UUID UUID_DEVICE_INFO_SERVICE =
42             UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
43     public static final UUID UUID_VERSION_CHARACTERISTIC =
44             UUID.fromString("00002A28-0000-1000-8000-00805f9b34fb");
45 
46     public static class Result {
47 
48         public static final int SUCCESS = 1;
49         public static final int UNKNOWN_FAILURE = 2;
50         public static final int GATT_DISCONNECTED = 3;
51         public static final int SUCCESS_NEEDS_PAIRING = 4;
52         public static final int NOT_IMPLEMENTED = 5;
53         public static final int DEVICE_BUSY = 6;
54 
55         protected static final Result SUCCESS_INST = new Result(SUCCESS);
56         protected static final Result UNKNOWN_FAILURE_INST = new Result(UNKNOWN_FAILURE);
57         protected static final Result GATT_DISCONNECTED_INST = new Result(GATT_DISCONNECTED);
58         protected static final Result SUCCESS_NEEDS_PAIRING_INST =
59                 new Result(SUCCESS_NEEDS_PAIRING);
60         protected static final Result NOT_IMPLEMENTED_INST =
61                 new Result(NOT_IMPLEMENTED);
62         protected static final Result DEVICE_BUSY_INST = new Result(DEVICE_BUSY);
63 
64         protected int mCode;
65 
Result(int code)66         public Result(int code) {
67             mCode = code;
68         }
69 
Result(Result res)70         protected Result(Result res) {
71             mCode = res.mCode;
72         }
73 
code()74         public int code() {
75             return mCode;
76         }
77     }
78 
79     public static class BatteryResult extends Result {
80 
81         public static final BatteryResult RESULT_FAILURE =
82                 new BatteryResult(Result.UNKNOWN_FAILURE_INST);
83         public static final BatteryResult RESULT_GATT_DISCONNECTED =
84                 new BatteryResult(Result.GATT_DISCONNECTED);
85         public static final BatteryResult RESULT_NOT_IMPLEMENTED =
86                 new BatteryResult(Result.NOT_IMPLEMENTED_INST);
87 
88         private int mBattery;
89 
BatteryResult(int battery)90         public BatteryResult(int battery) {
91             super(Result.SUCCESS);
92             mBattery = battery;
93         }
94 
BatteryResult(Result res)95         private BatteryResult(Result res) {
96             super(res);
97         }
98 
battery()99         public int battery() {
100             return mBattery;
101         }
102     }
103 
104     public static class VersionResult extends Result {
105 
106         public static final VersionResult RESULT_FAILURE =
107                 new VersionResult(Result.UNKNOWN_FAILURE_INST);
108         public static final VersionResult RESULT_GATT_DISCONNECTED =
109                 new VersionResult(Result.GATT_DISCONNECTED_INST);
110 
111         private Version mVersion;
112 
VersionResult(Version version)113         public VersionResult(Version version) {
114             super(Result.SUCCESS);
115             mVersion = version;
116         }
117 
VersionResult(Result res)118         private VersionResult(Result res) {
119             super(res);
120         }
121 
version()122         public Version version() {
123             return mVersion;
124         }
125     }
126 
127     public static class DfuResult extends Result {
128 
129         public static final DfuResult RESULT_FAILURE = new DfuResult(Result.UNKNOWN_FAILURE_INST);
130         public static final DfuResult RESULT_GATT_DISCONNECTED =
131                 new DfuResult(Result.GATT_DISCONNECTED_INST);
132         public static final DfuResult RESULT_DEVICE_BUSY = new DfuResult(Result.DEVICE_BUSY_INST);
133         public static final DfuResult RESULT_SUCCESS = new DfuResult(Result.SUCCESS_INST);
134         public static final DfuResult RESULT_SUCCESS_NEEDS_PAIRING =
135                 new DfuResult(Result.SUCCESS_NEEDS_PAIRING_INST);
136 
137         // Continuing index from fields of Result
138         public static final int IN_PROGRESS = 103;
139 
140         private final double mProgress;
141 
DfuResult(double progress)142         public DfuResult(double progress) {
143             super(IN_PROGRESS);
144             mProgress = progress;
145         }
146 
DfuResult(Result res)147         private DfuResult(Result res) {
148             super(res);
149             mProgress = 0;
150         }
151 
progress()152         public double progress() {
153             return mProgress;
154         }
155     }
156 
157     protected final BluetoothDevice mDevice;
158 
RemoteProxy(Context context, BluetoothDevice device)159     protected RemoteProxy(Context context, BluetoothDevice device) {
160         mDevice = device;
161     }
162 
initialize(Context context)163     public abstract boolean initialize(Context context);
164 
refreshBatteryLevel()165     public abstract CompletableFuture<Boolean> refreshBatteryLevel();
166 
getLastKnownBatteryLevel()167     public abstract BatteryResult getLastKnownBatteryLevel();
168 
169     /**
170      * @param callback The callback which is called by the underlying implementation whenever there
171      *                 is a battery level update.
172      * @return A CompleteableFuture of Boolean that indicates whether the callback has been
173      *         successfully registered.
174      */
registerBatteryLevelCallback(Runnable callback)175     public abstract CompletableFuture<Boolean> registerBatteryLevelCallback(Runnable callback);
176 
lowBatteryLevel()177     public int lowBatteryLevel() {
178         return DEFAULT_LOW_BATTERY_LEVEL;
179     }
180 
mapBatteryLevel(Context context, int level)181     public String mapBatteryLevel(Context context, int level) {
182         return context.getString(R.string.settings_remote_battery_level_percentage_label, level);
183     }
184 
refreshVersion()185     public abstract CompletableFuture<Boolean> refreshVersion();
186 
getLastKnownVersion()187     public abstract Version getLastKnownVersion();
188 
requestDfu( DfuBinary dfu, DfuManager.Listener listener, boolean background)189     public abstract CompletableFuture<DfuResult> requestDfu(
190             DfuBinary dfu, DfuManager.Listener listener, boolean background);
191 
getDfuState()192     public abstract DfuResult getDfuState();
193 
supportsBackgroundDfu()194     public abstract boolean supportsBackgroundDfu();
195 }
196