Skip to content

Commit 299aad0

Browse files
committed
Fixed android 14 support
1 parent 3268a71 commit 299aad0

File tree

3 files changed

+79
-76
lines changed

3 files changed

+79
-76
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<a href="https://www.gnu.org/licenses/gpl-3.0">
99
<img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg" alt="License: GPLv3">
1010
</a>
11-
<img alt="Minimum SDK" src="https://img.shields.io/badge/API-23%2B-green">
11+
<img alt="Minimum SDK" src="https://img.shields.io/badge/API-26%2B-green">
1212
</p>
1313
<p align="center">
1414
<a href="https://f-droid.org/packages/com.dosse.airpods">

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
android:usesPermissionFlags="neverForLocation"
1515
tools:targetApi="s" />
1616
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
17+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
18+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
1719
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
1820
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
1921

app/src/main/java/com/dosse/airpods/pods/PodsService.java

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@
1515
import android.content.BroadcastReceiver;
1616
import android.content.Context;
1717
import android.content.Intent;
18-
import android.os.Build;
1918
import android.os.IBinder;
2019
import android.os.ParcelUuid;
2120
import android.provider.Settings;
22-
import androidx.annotation.RequiresApi;
2321

2422
import com.dosse.airpods.R;
2523
import com.dosse.airpods.notification.NotificationThread;
@@ -40,28 +38,27 @@
4038
* - Display the notification with the status
4139
*/
4240
public class PodsService extends Service {
41+
private BluetoothLeScanner mBluetoothScanner;
42+
private PodsStatus mStatus = PodsStatus.DISCONNECTED;
4343

44-
private BluetoothLeScanner btScanner;
45-
private PodsStatus status = PodsStatus.DISCONNECTED;
44+
private static NotificationThread mNotificationThread = null;
45+
private static boolean mMaybeConnected = false;
4646

47-
private static NotificationThread n = null;
48-
private static boolean maybeConnected = false;
49-
50-
private BroadcastReceiver btReceiver = null;
51-
private BroadcastReceiver screenReceiver = null;
52-
private PodsStatusScanCallback scanCallback = null;
47+
private BroadcastReceiver mBluetoothReceiver = null;
48+
private BroadcastReceiver mScreenReceiver = null;
49+
private PodsStatusScanCallback mScanCallback = null;
5350

5451
/**
5552
* The following method (startAirPodsScanner) creates a bluetooth LE scanner.
5653
* This scanner receives all beacons from nearby BLE devices (not just your devices!) so we need to do 3 things:
5754
* - Check that the beacon comes from something that looks like a pair of AirPods
5855
* - Make sure that it is YOUR pair of AirPods
5956
* - Decode the beacon to get the status
60-
*
57+
* <p>
6158
* After decoding a beacon, the status is written to PodsStatus so that the NotificationThread can use the information
6259
*/
6360
@SuppressLint("MissingPermission")
64-
private void startAirPodsScanner () {
61+
private void startAirPodsScanner() {
6562
try {
6663
Logger.debug("START SCANNER");
6764

@@ -73,111 +70,110 @@ private void startAirPodsScanner () {
7370
return;
7471
}
7572

76-
if (btScanner != null && scanCallback != null) {
77-
btScanner.stopScan(scanCallback);
78-
scanCallback = null;
73+
if (mBluetoothScanner != null && mScanCallback != null) {
74+
mBluetoothScanner.stopScan(mScanCallback);
75+
mScanCallback = null;
7976
}
8077

8178
if (!btAdapter.isEnabled()) {
8279
Logger.debug("BT Off");
8380
return;
8481
}
8582

86-
btScanner = btAdapter.getBluetoothLeScanner();
83+
mBluetoothScanner = btAdapter.getBluetoothLeScanner();
8784

8885
ScanSettings scanSettings = new ScanSettings.Builder()
8986
.setScanMode(isSavingBattery(getApplicationContext()) ? ScanSettings.SCAN_MODE_LOW_POWER : ScanSettings.SCAN_MODE_LOW_LATENCY)
9087
.setReportDelay(1) // DON'T USE 0
9188
.build();
9289

93-
scanCallback = new PodsStatusScanCallback() {
90+
mScanCallback = new PodsStatusScanCallback() {
9491
@Override
95-
public void onStatus (PodsStatus newStatus) {
96-
status = newStatus;
92+
public void onStatus(PodsStatus newStatus) {
93+
mStatus = newStatus;
9794
}
9895
};
9996

100-
btScanner.startScan(getScanFilters(), scanSettings, scanCallback);
97+
mBluetoothScanner.startScan(getScanFilters(), scanSettings, mScanCallback);
10198
} catch (Throwable t) {
10299
Logger.error(t);
103100
}
104101
}
105102

106103
@SuppressLint("MissingPermission")
107-
private void stopAirPodsScanner () {
104+
private void stopAirPodsScanner() {
108105
try {
109-
if (btScanner != null && scanCallback != null) {
106+
if (mBluetoothScanner != null && mScanCallback != null) {
110107
Logger.debug("STOP SCANNER");
111108

112-
btScanner.stopScan(scanCallback);
113-
scanCallback = null;
109+
mBluetoothScanner.stopScan(mScanCallback);
110+
mScanCallback = null;
114111
}
115-
status = PodsStatus.DISCONNECTED;
112+
mStatus = PodsStatus.DISCONNECTED;
116113
} catch (Throwable t) {
117114
Logger.error(t);
118115
}
119116
}
120117

121-
public PodsService () {
118+
public PodsService() {
122119
}
123120

124121
@Override
125-
public IBinder onBind (Intent intent) {
122+
public IBinder onBind(Intent intent) {
126123
return null;
127124
}
128125

129126
/**
130127
* When the service is created, we register to get as many bluetooth and airpods related events as possible.
131128
* ACL_CONNECTED and ACL_DISCONNECTED should have been enough, but you never know with android these days.
132129
*/
130+
@SuppressLint("UnspecifiedRegisterReceiverFlag")
133131
@Override
134-
public void onCreate () {
132+
public void onCreate() {
135133
super.onCreate();
136-
137-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
138-
startForeground(101, createBackgroundNotification());
134+
startForeground(101, createBackgroundNotification());
139135

140136
unregisterBtReceiver();
141137

142-
btReceiver = new BluetoothReceiver() {
138+
mBluetoothReceiver = new BluetoothReceiver() {
143139
@Override
144-
public void onStart () {
140+
public void onStart() {
145141
// Bluetooth turned on, start/restart scanner.
146142
Logger.debug("BT ON");
147143
startAirPodsScanner();
148144
}
149145

150146
@Override
151-
public void onStop () {
147+
public void onStop() {
152148
// Bluetooth turned off, stop scanner and remove notification.
153149
Logger.debug("BT OFF");
154-
maybeConnected = false;
150+
mMaybeConnected = false;
155151
stopAirPodsScanner();
156152
}
157153

158154
@Override
159-
public void onConnect (BluetoothDevice bluetoothDevice) {
155+
public void onConnect(BluetoothDevice bluetoothDevice) {
160156
// Airpods filter
161157
if (checkUUID(bluetoothDevice)) {
162158
// Airpods connected, show notification.
163159
Logger.debug("ACL CONNECTED");
164-
maybeConnected = true;
160+
mMaybeConnected = true;
165161
}
166162
}
167163

168164
@Override
169-
public void onDisconnect (BluetoothDevice bluetoothDevice) {
165+
public void onDisconnect(BluetoothDevice bluetoothDevice) {
170166
// Airpods filter
171167
if (checkUUID(bluetoothDevice)) {
172168
// Airpods disconnected, remove notification but leave the scanner going.
173169
Logger.debug("ACL DISCONNECTED");
174-
maybeConnected = false;
170+
mMaybeConnected = false;
175171
}
176172
}
177173
};
178174

179175
try {
180-
registerReceiver(btReceiver, BluetoothReceiver.buildFilter());
176+
registerReceiver(mBluetoothReceiver, BluetoothReceiver.buildFilter());
181177
} catch (Throwable t) {
182178
Logger.error(t);
183179
}
@@ -187,102 +183,108 @@ public void onDisconnect (BluetoothDevice bluetoothDevice) {
187183
BluetoothAdapter ba = ((BluetoothManager)Objects.requireNonNull(getSystemService(Context.BLUETOOTH_SERVICE))).getAdapter();
188184
ba.getProfileProxy(getApplicationContext(), new BluetoothListener() {
189185
@Override
190-
public boolean onConnect (BluetoothDevice device) {
186+
public boolean onConnect(BluetoothDevice device) {
191187
Logger.debug("BT PROXY SERVICE CONNECTED ");
192188

193189
if (checkUUID(device)) {
194190
Logger.debug("BT PROXY: AIRPODS ALREADY CONNECTED");
195-
maybeConnected = true;
191+
mMaybeConnected = true;
196192
return true;
197193
}
198194

199195
return false;
200196
}
201197

202198
@Override
203-
public void onDisconnect () {
199+
public void onDisconnect() {
204200
Logger.debug("BT PROXY SERVICE DISCONNECTED ");
205-
maybeConnected = false;
201+
mMaybeConnected = false;
206202
}
207203
}, BluetoothProfile.HEADSET);
208204

209-
if (ba.isEnabled())
210-
startAirPodsScanner(); // If BT is already on when the app is started, start the scanner without waiting for an event to happen
205+
// If BT is already on when the app is started, start the scanner without waiting for an event to happen
206+
if (ba.isEnabled()) {
207+
startAirPodsScanner();
208+
}
211209

212210
// Screen on/off listener to suspend scanning when the screen is off, to save battery
213211
unregisterScreenReceiver();
214212

215213
if (isSavingBattery(getApplicationContext())) {
216-
screenReceiver = new ScreenReceiver() {
214+
mScreenReceiver = new ScreenReceiver() {
217215
@Override
218-
public void onStart () {
216+
public void onStart() {
219217
Logger.debug("SCREEN ON");
220218
startAirPodsScanner();
221219
}
222220

223221
@Override
224-
public void onStop () {
222+
public void onStop() {
225223
Logger.debug("SCREEN OFF");
226224
stopAirPodsScanner();
227225
}
228226
};
229227

230228
try {
231-
registerReceiver(screenReceiver, ScreenReceiver.buildFilter());
229+
registerReceiver(mScreenReceiver, ScreenReceiver.buildFilter());
232230
} catch (Throwable t) {
233231
Logger.error(t);
234232
}
235233
}
236234
}
237235

238236
@SuppressLint("MissingPermission")
239-
private static boolean checkUUID (BluetoothDevice bluetoothDevice) {
237+
private static boolean checkUUID(BluetoothDevice bluetoothDevice) {
240238
ParcelUuid[] AIRPODS_UUIDS = {
241239
ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"),
242240
ParcelUuid.fromString("2a72e02b-7b99-778f-014d-ad0b7221ec74")
243241
};
244242
ParcelUuid[] uuids = bluetoothDevice.getUuids();
245243

246-
if (uuids == null)
244+
if (uuids == null) {
247245
return false;
246+
}
248247

249-
for (ParcelUuid u : uuids)
250-
for (ParcelUuid v : AIRPODS_UUIDS)
251-
if (u.equals(v)) return true;
248+
for (ParcelUuid u : uuids) {
249+
for (ParcelUuid v : AIRPODS_UUIDS) {
250+
if (u.equals(v)) {
251+
return true;
252+
}
253+
}
254+
}
252255

253256
return false;
254257
}
255258

256259
@Override
257-
public void onDestroy () {
260+
public void onDestroy() {
258261
super.onDestroy();
259262
unregisterBtReceiver();
260263
unregisterScreenReceiver();
261264
}
262265

263266
@Override
264-
public int onStartCommand (Intent intent, int flags, int startId) {
265-
if (n == null || !n.isAlive()) {
266-
n = new NotificationThread(this) {
267+
public int onStartCommand(Intent intent, int flags, int startId) {
268+
if (mNotificationThread == null || !mNotificationThread.isAlive()) {
269+
mNotificationThread = new NotificationThread(this) {
267270
@Override
268-
public boolean isConnected () {
269-
return maybeConnected;
271+
public boolean isConnected() {
272+
return mMaybeConnected;
270273
}
271274

272275
@Override
273-
public PodsStatus getStatus () {
274-
return status;
276+
public PodsStatus getStatus() {
277+
return mStatus;
275278
}
276279
};
277-
n.start();
280+
mNotificationThread.start();
278281
}
279282
return START_STICKY;
280283
}
281284

282285
// Foreground service for background notification (confusing I know).
283286
// Only enabled for API30+
284-
@RequiresApi(api = Build.VERSION_CODES.O)
285-
private Notification createBackgroundNotification () {
287+
private Notification createBackgroundNotification() {
286288
final String notChannelID = "FOREGROUND_ID";
287289

288290
NotificationManager notManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
@@ -307,26 +309,25 @@ private Notification createBackgroundNotification () {
307309
return builder.build();
308310
}
309311

310-
private void unregisterBtReceiver () {
312+
private void unregisterBtReceiver() {
311313
try {
312-
if (btReceiver != null) {
313-
unregisterReceiver(btReceiver);
314-
btReceiver = null;
314+
if (mBluetoothReceiver != null) {
315+
unregisterReceiver(mBluetoothReceiver);
316+
mBluetoothReceiver = null;
315317
}
316318
} catch (Throwable t) {
317319
Logger.error(t);
318320
}
319321
}
320322

321-
private void unregisterScreenReceiver () {
323+
private void unregisterScreenReceiver() {
322324
try {
323-
if (screenReceiver != null) {
324-
unregisterReceiver(screenReceiver);
325-
screenReceiver = null;
325+
if (mScreenReceiver != null) {
326+
unregisterReceiver(mScreenReceiver);
327+
mScreenReceiver = null;
326328
}
327329
} catch (Throwable t) {
328330
Logger.error(t);
329331
}
330332
}
331-
332333
}

0 commit comments

Comments
 (0)