Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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.android.car; |
| 18 | |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 19 | import android.bluetooth.BluetoothAdapter; |
| 20 | import android.bluetooth.BluetoothDevice; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 21 | import android.car.VehicleAreaSeat; |
| 22 | import android.car.VehicleAreaType; |
| 23 | import android.car.VehiclePropertyIds; |
| 24 | import android.car.VehicleSeatOccupancyState; |
| 25 | import android.car.drivingstate.CarDrivingStateEvent; |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 26 | import android.car.hardware.CarPropertyConfig; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 27 | import android.car.hardware.CarPropertyValue; |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 28 | import android.car.hardware.power.CarPowerPolicy; |
| 29 | import android.car.hardware.power.CarPowerPolicyFilter; |
Eric Jeong | d48f707 | 2021-02-25 18:21:06 -0800 | [diff] [blame] | 30 | import android.car.hardware.power.ICarPowerPolicyListener; |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 31 | import android.car.hardware.power.PowerComponent; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 32 | import android.car.hardware.property.CarPropertyEvent; |
| 33 | import android.car.hardware.property.CarPropertyManager; |
| 34 | import android.car.hardware.property.ICarPropertyEventListener; |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 35 | import android.content.BroadcastReceiver; |
| 36 | import android.content.Context; |
| 37 | import android.content.Intent; |
| 38 | import android.content.IntentFilter; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 39 | import android.os.RemoteException; |
Ram Periathiruvadi | e011a40 | 2018-03-22 18:54:33 -0700 | [diff] [blame] | 40 | import android.os.UserHandle; |
Joseph Pirozzo | 6b5c8dd | 2021-01-22 10:01:17 -0800 | [diff] [blame] | 41 | import android.os.UserManager; |
Ram Periathiruvadi | e011a40 | 2018-03-22 18:54:33 -0700 | [diff] [blame] | 42 | import android.provider.Settings; |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 43 | import android.util.Log; |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 44 | import android.util.Slog; |
Ram Periathiruvadi | 83ee901 | 2017-07-18 19:21:06 -0700 | [diff] [blame] | 45 | |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 46 | import com.android.car.power.CarPowerManagementService; |
Jim Kaye | 9c2a155 | 2020-06-04 13:48:54 -0700 | [diff] [blame] | 47 | import com.android.internal.annotations.VisibleForTesting; |
| 48 | |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 49 | import java.io.PrintWriter; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 50 | import java.util.List; |
Justin Paupore | c813ead | 2018-12-28 20:18:25 -0800 | [diff] [blame] | 51 | import java.util.Objects; |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 52 | |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 53 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 54 | * A Bluetooth Device Connection policy that is specific to the use cases of a Car. Contains policy |
| 55 | * for deciding when to trigger connection and disconnection events. |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 56 | */ |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 57 | public class BluetoothDeviceConnectionPolicy { |
Mayank Garg | 72c71d2 | 2021-02-03 23:54:45 -0800 | [diff] [blame] | 58 | private static final String TAG = CarLog.tagFor(BluetoothDeviceConnectionPolicy.class); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 59 | private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); |
Justin Paupore | 7b17ea6 | 2018-12-28 20:27:33 -0800 | [diff] [blame] | 60 | |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 61 | private final int mUserId; |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 62 | private final Context mContext; |
Ram Periathiruvadi | ee28c00 | 2017-02-07 21:35:01 -0800 | [diff] [blame] | 63 | private final BluetoothAdapter mBluetoothAdapter; |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 64 | private final CarBluetoothService mCarBluetoothService; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 65 | private final CarServicesHelper mCarHelper; |
Joseph Pirozzo | 6b5c8dd | 2021-01-22 10:01:17 -0800 | [diff] [blame] | 66 | private final UserManager mUserManager; |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 67 | |
Eric Jeong | d48f707 | 2021-02-25 18:21:06 -0800 | [diff] [blame] | 68 | private final ICarPowerPolicyListener mPowerPolicyListener = |
| 69 | new ICarPowerPolicyListener.Stub() { |
Jim Kaye | 9c2a155 | 2020-06-04 13:48:54 -0700 | [diff] [blame] | 70 | @Override |
Eric Jeong | 8f0d3c4 | 2021-03-16 20:12:24 -0700 | [diff] [blame] | 71 | public void onPolicyChanged(CarPowerPolicy appliedPolicy, |
| 72 | CarPowerPolicy accumulatedPolicy) { |
| 73 | boolean isOn = accumulatedPolicy.isComponentEnabled(PowerComponent.BLUETOOTH); |
Joseph Pirozzo | 6b5c8dd | 2021-01-22 10:01:17 -0800 | [diff] [blame] | 74 | if (!mUserManager.isUserUnlocked(mUserId)) { |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 75 | logd("User " + mUserId + " is locked, ignoring bluetooth power change " |
| 76 | + (isOn ? "on" : "off")); |
Joseph Pirozzo | 6b5c8dd | 2021-01-22 10:01:17 -0800 | [diff] [blame] | 77 | return; |
| 78 | } |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 79 | if (isOn) { |
Jim Kaye | 9c2a155 | 2020-06-04 13:48:54 -0700 | [diff] [blame] | 80 | if (isBluetoothPersistedOn()) { |
| 81 | enableBluetooth(); |
| 82 | } |
| 83 | // The above isBluetoothPersistedOn() call is always true when the |
| 84 | // adapter is on, but can be true or false if the adapter is off. If we |
| 85 | // turned the adapter back on then this connectDevices() call would fail |
| 86 | // at first here but be caught by the following adapter on broadcast |
| 87 | // below. We'll only do this if the adapter is on. |
| 88 | if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { |
| 89 | connectDevices(); |
| 90 | } |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 91 | } else { |
| 92 | // we'll turn off Bluetooth to disconnect devices and better the "off" |
| 93 | // illusion |
| 94 | logd("Car power policy turns off bluetooth. Disable bluetooth adapter"); |
| 95 | disableBluetooth(); |
Jim Kaye | 9c2a155 | 2020-06-04 13:48:54 -0700 | [diff] [blame] | 96 | } |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 97 | } |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 98 | }; |
| 99 | |
Jim Kaye | 9c2a155 | 2020-06-04 13:48:54 -0700 | [diff] [blame] | 100 | @VisibleForTesting |
Eric Jeong | d48f707 | 2021-02-25 18:21:06 -0800 | [diff] [blame] | 101 | public ICarPowerPolicyListener getPowerPolicyListener() { |
| 102 | return mPowerPolicyListener; |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 106 | * A BroadcastReceiver that listens specifically for actions related to the profile we're |
| 107 | * tracking and uses them to update the status. |
| 108 | * |
| 109 | * On BluetoothAdapter.ACTION_STATE_CHANGED: |
| 110 | * If the adapter is going into the ON state, then commit trigger auto connection. |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 111 | */ |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 112 | private class BluetoothBroadcastReceiver extends BroadcastReceiver { |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 113 | @Override |
| 114 | public void onReceive(Context context, Intent intent) { |
| 115 | String action = intent.getAction(); |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 116 | BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 117 | if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { |
| 118 | int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 119 | logd("Bluetooth Adapter state changed: ", Utils.getAdapterStateName(state)); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 120 | if (state == BluetoothAdapter.STATE_ON) { |
| 121 | connectDevices(); |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 122 | } |
| 123 | } |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 124 | } |
| 125 | } |
Sal Savage | 6c10129 | 2019-11-14 15:30:18 -0800 | [diff] [blame] | 126 | private final BluetoothBroadcastReceiver mBluetoothBroadcastReceiver; |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 127 | |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 128 | /** |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 129 | * A helper class to interact with the VHAL and the rest of the car. |
| 130 | */ |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 131 | final class CarServicesHelper { |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 132 | private final CarPropertyService mCarPropertyService; |
| 133 | private final CarDrivingStateService mCarDrivingStateService; |
| 134 | |
| 135 | // Location of the driver's seat, e.g., left or right side. |
| 136 | private final int mDriverSeat; |
| 137 | |
| 138 | CarServicesHelper() { |
| 139 | mCarPropertyService = CarLocalServices.getService(CarPropertyService.class); |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 140 | if (mCarPropertyService == null) Slog.w(TAG, "Cannot find CarPropertyService"); |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 141 | mDriverSeat = getDriverSeatLocationFromVhal(); |
| 142 | mCarDrivingStateService = CarLocalServices.getService(CarDrivingStateService.class); |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 143 | if (mCarDrivingStateService == null) Slog.w(TAG, "Cannot find mCarDrivingStateService"); |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Set up vehicle event listeners. Remember to call {@link release()} when done. |
| 148 | */ |
| 149 | public void init() { |
| 150 | if (mCarPropertyService != null) { |
| 151 | mCarPropertyService.registerListener(VehiclePropertyIds.SEAT_OCCUPANCY, |
| 152 | CarPropertyManager.SENSOR_RATE_ONCHANGE, mSeatOnOccupiedListener); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | public void release() { |
| 157 | if (mCarPropertyService != null) { |
| 158 | mCarPropertyService.unregisterListener(VehiclePropertyIds.SEAT_OCCUPANCY, |
| 159 | mSeatOnOccupiedListener); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * A {@code ICarPropertyEventListener} that triggers the auto-connection process when |
| 165 | * {@code SEAT_OCCUPANCY} is {@code OCCUPIED}. |
| 166 | */ |
| 167 | private final ICarPropertyEventListener mSeatOnOccupiedListener = |
| 168 | new ICarPropertyEventListener.Stub() { |
| 169 | @Override |
| 170 | public void onEvent(List<CarPropertyEvent> events) throws RemoteException { |
| 171 | for (CarPropertyEvent event : events) { |
| 172 | onSeatOccupancyCarPropertyEvent(event); |
| 173 | } |
| 174 | } |
| 175 | }; |
| 176 | |
| 177 | /** |
| 178 | * Acts on {@link CarPropertyEvent} events marked with |
| 179 | * {@link CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE} and marked with {@link |
| 180 | * VehiclePropertyIds.SEAT_OCCUPANCY} by calling {@link connectDevices}. |
| 181 | * <p> |
| 182 | * Default implementation filters on driver's seat only, but can change to trigger on |
| 183 | * any front row seat, or any seat in the car. |
| 184 | * <p> |
| 185 | * Default implementation also restricts this trigger to when the car is in the |
| 186 | * parked state, to discourage drivers from exploiting to connect while driving, and to |
| 187 | * also filter out spurious seat sensor signals while driving. |
| 188 | * <p> |
| 189 | * This method does nothing if the event parameter is {@code null}. |
| 190 | * |
| 191 | * @param event - The {@link CarPropertyEvent} to be handled. |
| 192 | */ |
| 193 | private void onSeatOccupancyCarPropertyEvent(CarPropertyEvent event) { |
| 194 | if ((event == null) |
| 195 | || (event.getEventType() != CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE)) { |
| 196 | return; |
| 197 | } |
| 198 | CarPropertyValue value = event.getCarPropertyValue(); |
| 199 | logd("Car property changed: ", value.toString()); |
| 200 | if (mBluetoothAdapter.isEnabled() |
| 201 | && (value.getPropertyId() == VehiclePropertyIds.SEAT_OCCUPANCY) |
| 202 | && ((int) value.getValue() == VehicleSeatOccupancyState.OCCUPIED) |
| 203 | && (value.getAreaId() == mDriverSeat) |
| 204 | && isParked()) { |
| 205 | connectDevices(); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | /** |
| 210 | * Gets the location of the driver's seat (e.g., front-left, front-right) from the VHAL. |
| 211 | * <p> |
| 212 | * Default implementation sets the driver's seat to front-left if mCarPropertyService is |
| 213 | * not found. |
| 214 | * <p> |
| 215 | * Note, comments for {@link CarPropertyManager#getIntProperty(int, int)} indicate it may |
| 216 | * take a couple of seconds to complete, whereas there are no such comments for |
Kai Wang | 301dd47 | 2021-05-18 06:09:44 +0000 | [diff] [blame^] | 217 | * {@link CarPropertyService#getPropertySafe(int, int)}, but we assume there is also similar |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 218 | * latency in querying VHAL properties. |
| 219 | * |
| 220 | * @return An {@code int} representing driver's seat location. |
| 221 | */ |
| 222 | private int getDriverSeatLocationFromVhal() { |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 223 | int defaultLocation = VehicleAreaSeat.SEAT_ROW_1_LEFT; |
| 224 | |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 225 | if (mCarPropertyService == null) { |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 226 | return defaultLocation; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 227 | } |
Kai Wang | 301dd47 | 2021-05-18 06:09:44 +0000 | [diff] [blame^] | 228 | CarPropertyValue value = mCarPropertyService.getPropertySafe( |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 229 | VehiclePropertyIds.INFO_DRIVER_SEAT, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL); |
| 230 | if (value == null) { |
| 231 | // Distinguish between two possible causes for null, based on |
| 232 | // {@code mConfigs.get(prop)} in {@link CarPropertyService#getProperty} and |
| 233 | // {@link CarPropertyService#getPropertyConfigList} |
| 234 | List<CarPropertyConfig> availableProp = mCarPropertyService.getPropertyConfigList( |
| 235 | new int[] {VehiclePropertyIds.INFO_DRIVER_SEAT}); |
| 236 | if (availableProp.isEmpty() || availableProp.get(0) == null) { |
| 237 | logd("Driver seat location property is not in config list."); |
| 238 | } else { |
| 239 | logd("Driver seat location property is not ready yet."); |
| 240 | } |
| 241 | return defaultLocation; |
| 242 | } |
| 243 | return (int) value.getValue(); |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | public int getDriverSeatLocation() { |
| 247 | return mDriverSeat; |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * Returns {@code true} if the car is in parked gear. |
| 252 | * <p> |
| 253 | * We are being conservative and only want to trigger when car is in parked state. Extending |
| 254 | * this conservative approach, we default return false if {@code mCarDrivingStateService} |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 255 | * is not found, or if we otherwise can't get the value. |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 256 | */ |
| 257 | public boolean isParked() { |
| 258 | if (mCarDrivingStateService == null) { |
| 259 | return false; |
| 260 | } |
Andrew Cheng | 04a9555 | 2021-04-01 14:42:14 -0700 | [diff] [blame] | 261 | CarDrivingStateEvent event = mCarDrivingStateService.getCurrentDrivingState(); |
| 262 | if (event == null) { |
| 263 | return false; |
| 264 | } |
| 265 | return event.eventValue == CarDrivingStateEvent.DRIVING_STATE_PARKED; |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 266 | } |
| 267 | } |
| 268 | |
| 269 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 270 | * Create a new BluetoothDeviceConnectionPolicy object, responsible for encapsulating the |
| 271 | * default policy for when to initiate device connections given the list of prioritized devices |
| 272 | * for each profile. |
| 273 | * |
| 274 | * @param context - The context of the creating application |
| 275 | * @param userId - The user ID we're operating as |
| 276 | * @param bluetoothService - A reference to CarBluetoothService so we can connect devices |
| 277 | * @return A new instance of a BluetoothProfileDeviceManager, or null on any error |
| 278 | */ |
| 279 | public static BluetoothDeviceConnectionPolicy create(Context context, int userId, |
| 280 | CarBluetoothService bluetoothService) { |
| 281 | try { |
| 282 | return new BluetoothDeviceConnectionPolicy(context, userId, bluetoothService); |
| 283 | } catch (NullPointerException e) { |
| 284 | return null; |
Ram Periathiruvadi | be7ea0fe | 2017-05-31 23:31:40 -0700 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | |
| 288 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 289 | * Create a new BluetoothDeviceConnectionPolicy object, responsible for encapsulating the |
| 290 | * default policy for when to initiate device connections given the list of prioritized devices |
| 291 | * for each profile. |
Ram Periathiruvadi | be7ea0fe | 2017-05-31 23:31:40 -0700 | [diff] [blame] | 292 | * |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 293 | * @param context - The context of the creating application |
| 294 | * @param userId - The user ID we're operating as |
| 295 | * @param bluetoothService - A reference to CarBluetoothService so we can connect devices |
| 296 | * @return A new instance of a BluetoothProfileDeviceManager |
Ram Periathiruvadi | be7ea0fe | 2017-05-31 23:31:40 -0700 | [diff] [blame] | 297 | */ |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 298 | private BluetoothDeviceConnectionPolicy(Context context, int userId, |
| 299 | CarBluetoothService bluetoothService) { |
| 300 | mUserId = userId; |
| 301 | mContext = Objects.requireNonNull(context); |
| 302 | mCarBluetoothService = bluetoothService; |
Sal Savage | 6c10129 | 2019-11-14 15:30:18 -0800 | [diff] [blame] | 303 | mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver(); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 304 | mBluetoothAdapter = Objects.requireNonNull(BluetoothAdapter.getDefaultAdapter()); |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 305 | mCarHelper = new CarServicesHelper(); |
Joseph Pirozzo | 6b5c8dd | 2021-01-22 10:01:17 -0800 | [diff] [blame] | 306 | mUserManager = mContext.getSystemService(UserManager.class); |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 307 | } |
| 308 | |
| 309 | /** |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 310 | * Setup the Bluetooth profile service connections and Vehicle Event listeners. |
| 311 | * and start the state machine -{@link BluetoothAutoConnectStateMachine} |
| 312 | */ |
Sal Savage | 6c10129 | 2019-11-14 15:30:18 -0800 | [diff] [blame] | 313 | public void init() { |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 314 | logd("init()"); |
Pavel Maltsev | c9e86e8 | 2017-03-22 11:37:21 -0700 | [diff] [blame] | 315 | IntentFilter profileFilter = new IntentFilter(); |
Pavel Maltsev | c9e86e8 | 2017-03-22 11:37:21 -0700 | [diff] [blame] | 316 | profileFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 317 | mContext.registerReceiverAsUser(mBluetoothBroadcastReceiver, UserHandle.CURRENT, |
| 318 | profileFilter, null, null); |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 319 | CarPowerManagementService cpms = CarLocalServices.getService( |
| 320 | CarPowerManagementService.class); |
| 321 | if (cpms != null) { |
| 322 | CarPowerPolicyFilter filter = new CarPowerPolicyFilter.Builder() |
Eric Jeong | 72c850d | 2021-04-12 15:29:15 -0700 | [diff] [blame] | 323 | .setComponents(PowerComponent.BLUETOOTH).build(); |
Eric Jeong | d48f707 | 2021-02-25 18:21:06 -0800 | [diff] [blame] | 324 | cpms.addPowerPolicyListener(filter, mPowerPolicyListener); |
Ram Periathiruvadi | e011a40 | 2018-03-22 18:54:33 -0700 | [diff] [blame] | 325 | } else { |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 326 | Slog.w(TAG, "Cannot find CarPowerManagementService"); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 327 | } |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 328 | mCarHelper.init(); |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 329 | |
| 330 | // Since we do this only on start up and on user switch, it's safe to kick off a connect on |
| 331 | // init. If we have a connect in progress, this won't hurt anything. If we already have |
| 332 | // devices connected, this will add on top of it. We _could_ enter this from a crash |
| 333 | // recovery, but that would at worst cause more devices to connect and wouldn't change the |
| 334 | // existing devices. |
| 335 | if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { |
| 336 | // CarPowerManager doesn't provide a getState() or that would go here too. |
| 337 | connectDevices(); |
Ram Periathiruvadi | e011a40 | 2018-03-22 18:54:33 -0700 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 341 | /** |
| 342 | * Clean up slate. Close the Bluetooth profile service connections and quit the state machine - |
| 343 | * {@link BluetoothAutoConnectStateMachine} |
| 344 | */ |
Sal Savage | 6c10129 | 2019-11-14 15:30:18 -0800 | [diff] [blame] | 345 | public void release() { |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 346 | logd("release()"); |
Eric Jeong | 07a81f1 | 2021-02-12 17:58:13 -0800 | [diff] [blame] | 347 | CarPowerManagementService cpms = |
| 348 | CarLocalServices.getService(CarPowerManagementService.class); |
| 349 | if (cpms != null) { |
Eric Jeong | d48f707 | 2021-02-25 18:21:06 -0800 | [diff] [blame] | 350 | cpms.removePowerPolicyListener(mPowerPolicyListener); |
Ram Periathiruvadi | ee28c00 | 2017-02-07 21:35:01 -0800 | [diff] [blame] | 351 | } |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 352 | if (mBluetoothBroadcastReceiver != null) { |
| 353 | mContext.unregisterReceiver(mBluetoothBroadcastReceiver); |
Ram Periathiruvadi | a048c0a | 2017-05-09 07:35:03 -0700 | [diff] [blame] | 354 | } |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 355 | mCarHelper.release(); |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 359 | * Tell each Profile device manager that its time to begin auto connecting devices |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 360 | */ |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 361 | public void connectDevices() { |
| 362 | logd("Connect devices for each profile"); |
| 363 | mCarBluetoothService.connectDevices(); |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 364 | } |
| 365 | |
| 366 | /** |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 367 | * Get the persisted Bluetooth state from Settings |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 368 | * |
| 369 | * @return True if the persisted Bluetooth state is on, false otherwise |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 370 | */ |
| 371 | private boolean isBluetoothPersistedOn() { |
| 372 | return (Settings.Global.getInt( |
| 373 | mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, -1) != 0); |
| 374 | } |
| 375 | |
| 376 | /** |
| 377 | * Turn on the Bluetooth Adapter. |
| 378 | */ |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 379 | private void enableBluetooth() { |
| 380 | logd("Enable bluetooth adapter"); |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 381 | if (mBluetoothAdapter == null) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 382 | Slog.e(TAG, "Cannot enable Bluetooth adapter. The object is null."); |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 383 | return; |
| 384 | } |
| 385 | mBluetoothAdapter.enable(); |
| 386 | } |
| 387 | |
| 388 | /** |
| 389 | * Turn off the Bluetooth Adapter. |
| 390 | * |
| 391 | * Tells BluetoothAdapter to shut down _without_ persisting the off state as the desired state |
| 392 | * of the Bluetooth adapter for next start up. |
| 393 | */ |
| 394 | private void disableBluetooth() { |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 395 | logd("Disable bluetooth, do not persist state across reboot"); |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 396 | if (mBluetoothAdapter == null) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 397 | Slog.e(TAG, "Cannot disable Bluetooth adapter. The object is null."); |
Sal Savage | ed6b04e | 2019-03-15 13:27:27 -0700 | [diff] [blame] | 398 | return; |
| 399 | } |
| 400 | mBluetoothAdapter.disable(false); |
| 401 | } |
| 402 | |
| 403 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 404 | * Print the verbose status of the object |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 405 | */ |
Sal Savage | 6c10129 | 2019-11-14 15:30:18 -0800 | [diff] [blame] | 406 | public void dump(PrintWriter writer, String indent) { |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 407 | writer.println(indent + TAG + ":"); |
| 408 | writer.println(indent + "\tUserId: " + mUserId); |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 409 | } |
| 410 | |
| 411 | /** |
Sal Savage | 703c46f | 2019-04-15 08:39:25 -0700 | [diff] [blame] | 412 | * Print to debug if debug is enabled |
Ram Periathiruvadi | acb6024 | 2017-04-13 16:19:09 -0700 | [diff] [blame] | 413 | */ |
Andrew Cheng | b7eaebe | 2020-10-02 08:31:55 -0700 | [diff] [blame] | 414 | private static void logd(String... msgParts) { |
Ram Periathiruvadi | ee28c00 | 2017-02-07 21:35:01 -0800 | [diff] [blame] | 415 | if (DBG) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 416 | Slog.d(TAG, String.join(" ", msgParts)); |
Ram Periathiruvadi | ee28c00 | 2017-02-07 21:35:01 -0800 | [diff] [blame] | 417 | } |
Ram Periathiruvadi | 7ed8418 | 2017-01-20 15:18:08 -0800 | [diff] [blame] | 418 | } |
| 419 | } |