37 Commits
Author SHA1 Message Date
Electric1447 ee7e75b5e8 Update README.md 2022-09-29 22:22:41 +03:00
Electric1447 b939674a62 Add missing airpods pro 2 text in supported devices list 2022-09-29 22:21:44 +03:00
Electric1447 ade3d0a481 Update localizations 2022-09-29 22:20:06 +03:00
Electric1447 70a05a1848 Add Airpods Pro Gen 2 support 2022-09-29 22:17:32 +03:00
Electric1447 6803ef0691 refactor pod models folders 2022-09-29 22:14:18 +03:00
Electric1447 71f08a4098 renamed ``data` to `types`` 2022-09-29 22:07:56 +03:00
Electric1447 17afa55203 Android 13 support 2022-09-29 22:06:36 +03:00
Electric1447 96ffaf1d90 Update localizations 2022-09-29 22:06:22 +03:00
Electric1447 047b9b373c Update build tools 2022-09-29 22:05:54 +03:00
Federico feb2eac287 Release 1.8 2022-09-10 14:08:46 +02:00
Federico cd20f99747 Increased version to 1.8, updated to latest gradle, updated localization and readme 2022-07-28 15:09:27 +02:00
Itai Levin 535790aab1 Merge pull request #147 from d4rken/feature/detect-model-by-full-identifier
Improve model identification and add AirPods Gen3
2022-07-26 09:50:10 +03:00
Itai Levin d938817669 Merge pull request #142 from iris-mobile-accessibility-repair/master
solve issue of low contrast
2022-07-26 09:48:38 +03:00
darken 31cff2ac0c Change model check to compare against the full model identifier (4 bytes) and add support for AirPods 3rd gen.
Closes #140
2022-07-25 18:20:45 +02:00
Electric1447 104dc3454b Update build tools 2022-05-18 00:46:05 +03:00
iris-mobile-accessibility-repair 83b71cb488 Update styles.xml 2022-03-15 22:22:36 +08:00
Electric1447 97f7359057 Location permission is now required 2021-09-12 16:30:21 +03:00
Electric1447 ec67136d44 Update build tools 2021-09-07 23:37:32 +03:00
Electric1447 4f3f365e62 Update README.md 2021-09-01 18:15:03 +03:00
Itai Levin 67a8a4cde9 Merge pull request #126 from Electric1447/master
Update repository organization
2021-09-01 17:28:38 +03:00
Electric1447 b1a056a00b Merge branch 'master' of https://github.com/adolfintel/OpenPods
merge from upstream
2021-09-01 17:26:32 +03:00
Electric1447 b6941b6686 Update README.md 2021-09-01 17:25:13 +03:00
Electric1447 84272fd7a5 Update README.md 2021-09-01 17:19:43 +03:00
Electric1447 6b7ddd4618 Update README.md 2021-09-01 17:09:56 +03:00
Electric1447 12bc363f45 Update README.md 2021-09-01 16:56:46 +03:00
Federico Dossena cac56e641a Deleted syncthing garbage 2021-09-01 13:44:19 +00:00
dosse91 cd416877f9 Merge branch 'master' of github.com:adolfintel/OpenPods 2021-09-01 15:44:10 +02:00
dosse91 dfb76e7791 Added changelogs for fastlane 2021-09-01 15:43:27 +02:00
Electric1447 e47a1b0eee Update README.md 2021-09-01 16:16:27 +03:00
Electric1447 d4fea733b7 Add fastlane text metadata files 2021-09-01 15:50:36 +03:00
Electric1447 0479652a53 Remove .idea folder 2021-09-01 15:30:31 +03:00
Electric1447 65c053002c Update .gitignore 2021-09-01 15:29:20 +03:00
Electric1447 73befc9e7b Move app files to root folder 2021-09-01 15:24:27 +03:00
Electric1447 cd462fd2bb remove old .gitignore 2021-09-01 15:21:00 +03:00
Electric1447 07047a97ec fix Dutch strings.xml 2021-08-31 23:16:44 +03:00
Federico Dossena 7e48ddd4c5 Merge pull request #125 from Vistaus/master
Updated Dutch translation
2021-08-31 16:00:51 +00:00
Heimen Stoffels e66be09b4b Updated Dutch translation 2021-08-31 17:34:17 +02:00
156 changed files with 404 additions and 285 deletions
+15 -1
View File
@@ -1 +1,15 @@
/_old_
# Android specific
local.properties
# Gradle
.cxx
.externalNativeBuild
.gradle
build
# IntelliJ IDEA
.idea
*.iml
# macOS
.DS_Store
-17
View File
@@ -1,17 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/codeStyles
/.idea/dictionaries
/.idea/libraries
/.idea/gradle.xml
/.idea/misc.xml
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
-17
View File
@@ -1,17 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="3">
<item index="0" class="java.lang.String" itemvalue="data-wgscriptallow" />
<item index="1" class="java.lang.String" itemvalue="data-cbscriptallow" />
<item index="2" class="java.lang.String" itemvalue="data-acxscriptallow" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
</profile>
</component>
-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RenderSettings">
<option name="showDecorations" value="true" />
</component>
</project>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
@@ -1,26 +0,0 @@
package com.dosse.airpods.pods.data;
public interface IPods {
String MODEL_AIRPODS_GEN1 = "airpods1";
String MODEL_AIRPODS_GEN2 = "airpods2";
String MODEL_AIRPODS_PRO = "airpodspro";
String MODEL_AIRPODS_MAX = "airpodsmax";
String MODEL_BEATS_X = "beatsx";
String MODEL_BEATS_FLEX = "beatsflex";
String MODEL_BEATS_SOLO_3 = "beatssolo3";
String MODEL_BEATS_STUDIO_3 = "beatsstudio3";
String MODEL_POWERBEATS_3 = "powerbeats3";
String MODEL_POWERBEATS_PRO = "powerbeatspro";
String MODEL_UNKNOWN = "unknown";
String getModel ();
boolean isSingle ();
boolean isDisconnected ();
String parseStatusForLogger ();
}
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="@color/bgColorPrimary"
android:gravity="center"
android:padding="@dimen/padding_default">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/locationDisabledText"
android:textColor="@color/textColorPrimary" />
</RelativeLayout>
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/bgColorPrimary"
android:gravity="center"
android:padding="@dimen/padding_default">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/locationDisabledText"
android:textColor="@color/textColorPrimary" />
</RelativeLayout>
+45 -13
View File
@@ -1,23 +1,53 @@
![OpenPods Logo](fastlane/metadata/android/en-US/images/featureGraphic.png)
<p align="center"><img src="fastlane/metadata/android/en-US/images/icon.png" width="150"></p>
<h1 align="center"><b>OpenPods</b></h1>
<h4 align="center">The Free and Open Source app for monitoring your AirPods on Android</h4>
<p align="center">
<a href="https://github.com/adolfintel/OpenPods/releases">
<img src="https://img.shields.io/github/release/adolfintel/OpenPods.svg?color=blueviolet" alt="GitHub release">
</a>
<a href="https://www.gnu.org/licenses/gpl-3.0">
<img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg" alt="License: GPLv3">
</a>
<img alt="Minimum SDK" src="https://img.shields.io/badge/API-23%2B-green">
</p>
<p align="center">
<a href="https://f-droid.org/packages/com.dosse.airpods">
<img src="assets/get-it-on-fdroid.png" alt="Get it on F-Droid" height="80">
</a>
<a href="https://downloads.fdossena.com/geth.php?r=openpods-apk">
<img src="assets/get-it-on-openpods.png" alt="Get it on OpenPods" height="80">
</a>
</p>
# OpenPods
The Free and Open Source app for monitoring your AirPods on Android
## Download
<a href="https://f-droid.org/packages/com.dosse.airpods"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80"></a>
[Download APK](https://downloads.fdossena.com/geth.php?r=openpods-apk)
## Screenshots
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen1.png"
alt="Big notification"
width="200">](fastlane/metadata/android/en-US/images/phoneScreenshots/screen1.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen2.png"
alt="Small notification"
width="200">](fastlane/metadata/android/en-US/images/phoneScreenshots/screen2.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen3.png"
alt="Setup screen"
width="200">](fastlane/metadata/android/en-US/images/phoneScreenshots/screen3.png)
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen4.png"
alt="Home screen"
width="200">](fastlane/metadata/android/en-US/images/phoneScreenshots/screen4.png)
## Features
* Shows a notification with AirPods status when they are connected
* Respects your privacy
* Free and Open Source software
* Supports Dark Theme
## Supported devices
* Apple AirPods 1st gen
* Apple AirPods 2nd gen
* Apple AirPods 3rd gen
* Apple AirPods Pro
* Apple AirPods Pro 2
* Apple AirPods Max
* Beats X
* Beats Flex
@@ -33,13 +63,10 @@ Legal actions can and will be taken when uploading a compiled version to the Goo
This paragraph was added due to multiple license violations found on the Google Play Store. If you're not sure whether you're allowed to distribute your modified version, please contact the developer.
## Donate
[Donate with PayPal](https://www.paypal.me/sineisochronic)
## Screenshots
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen1.png" width="400"> &nbsp; <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen2.png" width="400"> &nbsp; <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen3.png" width="400"> &nbsp; <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/screen4.png" width="400">
<a href="https://www.paypal.me/sineisochronic"><img src="assets/donate-with-paypal.png" alt="Donate with PayPal" height="80"></a>
## License
Copyright (C) 2021 Federico Dossena
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl-3.0.en.html)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -54,4 +81,9 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
&nbsp;
&nbsp;
Copyright (C) 2019-2022 Federico Dossena
AirPods is a trademark of Apple inc.
+16 -12
View File
@@ -1,15 +1,17 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 31
buildToolsVersion '30.0.3'
namespace 'com.dosse.airpods'
compileSdkVersion 33
buildToolsVersion '33.0.0'
defaultConfig {
applicationId "com.dosse.airpods"
minSdkVersion 23
targetSdkVersion 31
versionCode 18
versionName '1.7'
targetSdkVersion 33
versionCode 21
versionName '1.9'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -22,17 +24,19 @@ android {
}
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceCompatibility = 11
targetCompatibility = 11
}
lint {
abortOnError false
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation "androidx.preference:preference:1.1.1"
//noinspection GradleDependency 1.5.0/1.5.1 is broken
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.preference:preference:1.2.0'
}
+20
View File
@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.dosse.airpods",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 20,
"versionName": "1.8",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dosse.airpods">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
@@ -8,7 +8,10 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@@ -23,7 +26,8 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:ignore="DataExtractionRules">
<activity
android:name=".ui.MainActivity"
@@ -47,13 +51,10 @@
android:launchMode="singleTop"
android:parentActivityName=".ui.MainActivity" />
<activity
android:name=".ui.NoBTActivity"
android:label="@string/app_name" />
<activity android:name=".ui.NoBTActivity" />
<activity
android:name=".ui.IntroActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" />
<receiver
@@ -2,51 +2,38 @@ package com.dosse.airpods.notification;
import android.app.Notification;
import android.content.Context;
import android.os.Build;
import android.view.View;
import android.widget.RemoteViews;
import androidx.core.app.NotificationCompat;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.PodsStatus;
import com.dosse.airpods.pods.data.IPods;
import com.dosse.airpods.pods.data.RegularPods;
import com.dosse.airpods.pods.data.SinglePods;
import com.dosse.airpods.utils.PermissionUtils;
import com.dosse.airpods.pods.models.IPods;
import com.dosse.airpods.pods.models.RegularPods;
import com.dosse.airpods.pods.models.SinglePods;
public class NotificationBuilder {
public static final String TAG = "AirPods";
public static final long TIMEOUT_CONNECTED = 30000;
public static final int NOTIFICATION_ID = 1;
private final RemoteViews[] notificationArr, notificationLocation;
private final Context mContext;
private final RemoteViews[] notificationArr;
private final NotificationCompat.Builder mBuilder;
public NotificationBuilder (Context context) {
mContext = context;
notificationArr = new RemoteViews[] {new RemoteViews(context.getPackageName(), R.layout.status_big), new RemoteViews(context.getPackageName(), R.layout.status_small)};
notificationLocation = new RemoteViews[] {new RemoteViews(context.getPackageName(), R.layout.location_disabled_big), new RemoteViews(context.getPackageName(), R.layout.location_disabled_small)};
mBuilder = new NotificationCompat.Builder(context, TAG);
mBuilder.setShowWhen(false);
mBuilder.setOngoing(true);
mBuilder.setSmallIcon(R.mipmap.notification_icon);
mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
mBuilder.setCustomContentView(notificationArr[1]);
mBuilder.setCustomBigContentView(notificationArr[0]);
}
public Notification build (PodsStatus status) {
// Apparently this restriction was removed ONLY in android Q
if (PermissionUtils.getLocationPermissions(mContext) || Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
mBuilder.setCustomContentView(notificationArr[1]);
mBuilder.setCustomBigContentView(notificationArr[0]);
} else {
mBuilder.setCustomContentView(notificationLocation[1]);
mBuilder.setCustomBigContentView(notificationLocation[0]);
}
IPods airpods = status.getAirpods();
boolean single = airpods.isSingle();
@@ -1,4 +1,4 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods;
import android.view.View;
@@ -1,5 +1,6 @@
package com.dosse.airpods.pods;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -59,6 +60,7 @@ public class PodsService extends Service {
*
* After decoding a beacon, the status is written to PodsStatus so that the NotificationThread can use the information
*/
@SuppressLint("MissingPermission")
private void startAirPodsScanner () {
try {
Logger.debug("START SCANNER");
@@ -71,7 +73,6 @@ public class PodsService extends Service {
return;
}
//if (batterySaver && btScanner != null && scanCallback != null) {
if (btScanner != null && scanCallback != null) {
btScanner.stopScan(scanCallback);
scanCallback = null;
@@ -102,6 +103,7 @@ public class PodsService extends Service {
}
}
@SuppressLint("MissingPermission")
private void stopAirPodsScanner () {
try {
if (btScanner != null && scanCallback != null) {
@@ -132,7 +134,7 @@ public class PodsService extends Service {
public void onCreate () {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startForeground(101, createBackgroundNotification());
unregisterBtReceiver();
@@ -233,6 +235,7 @@ public class PodsService extends Service {
}
}
@SuppressLint("MissingPermission")
private static boolean checkUUID (BluetoothDevice bluetoothDevice) {
ParcelUuid[] AIRPODS_UUIDS = {
ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"),
@@ -1,18 +1,19 @@
package com.dosse.airpods.pods;
import com.dosse.airpods.pods.data.AirPods1;
import com.dosse.airpods.pods.data.AirPods2;
import com.dosse.airpods.pods.data.AirPodsMax;
import com.dosse.airpods.pods.data.AirPodsPro;
import com.dosse.airpods.pods.data.BeatsFlex;
import com.dosse.airpods.pods.data.BeatsSolo3;
import com.dosse.airpods.pods.data.BeatsStudio3;
import com.dosse.airpods.pods.data.BeatsX;
import com.dosse.airpods.pods.data.IPods;
import com.dosse.airpods.pods.data.Pod;
import com.dosse.airpods.pods.data.Powerbeats3;
import com.dosse.airpods.pods.data.PowerbeatsPro;
import com.dosse.airpods.pods.data.RegularPods;
import com.dosse.airpods.pods.models.AirPods1;
import com.dosse.airpods.pods.models.AirPods2;
import com.dosse.airpods.pods.models.AirPods3;
import com.dosse.airpods.pods.models.AirPodsMax;
import com.dosse.airpods.pods.models.AirPodsPro;
import com.dosse.airpods.pods.models.AirPodsPro2;
import com.dosse.airpods.pods.models.BeatsFlex;
import com.dosse.airpods.pods.models.BeatsSolo3;
import com.dosse.airpods.pods.models.BeatsStudio3;
import com.dosse.airpods.pods.models.BeatsX;
import com.dosse.airpods.pods.models.IPods;
import com.dosse.airpods.pods.models.Powerbeats3;
import com.dosse.airpods.pods.models.PowerbeatsPro;
import com.dosse.airpods.pods.models.RegularPods;
/**
* Decoding the beacon:
@@ -68,29 +69,36 @@ public class PodsStatus {
Pod casePod = new Pod(caseStatus, chargeCase, false);
Pod singlePod = new Pod(singleStatus, chargeSingle, false);
char idSingle = status.charAt(7); // We don't know the full ID for all devices
String idFull = status.substring(6, 10);
// Detect which model
switch (status.charAt(7)) {
case '2': pods = new AirPods1(leftPod, rightPod, casePod); // Airpods 1st gen
break;
case 'F': pods = new AirPods2(leftPod, rightPod, casePod); // Airpods 2nd gen
break;
case 'E': pods = new AirPodsPro(leftPod, rightPod, casePod); // Airpods Pro
break;
case 'A': pods = new AirPodsMax(singlePod); // Airpods Max
break;
case 'B': pods = new PowerbeatsPro(leftPod, rightPod, casePod); // Powerbeats Pro
break;
case '5': pods = new BeatsX(singlePod); // Beats X
break;
case '0': pods = new BeatsFlex(singlePod); // Beats Flex
break;
case '6': pods = new BeatsSolo3(singlePod); // Beats Solo 3
break;
case '9': pods = new BeatsStudio3(singlePod); // Beats Studio 3
break;
case '3': pods = new Powerbeats3(singlePod); // Powerbeats 3
break;
default: pods = new RegularPods(leftPod, rightPod, casePod); // Unknown
if ("0220".equals(idFull)) {
pods = new AirPods1(leftPod, rightPod, casePod); // Airpods 1st gen
} else if ("0F20".equals(idFull)) {
pods = new AirPods2(leftPod, rightPod, casePod); // Airpods 2nd gen
} else if ("1320".equals(idFull)) {
pods = new AirPods3(leftPod, rightPod, casePod); // Airpods 3rd gen
} else if ("0E20".equals(idFull)) {
pods = new AirPodsPro(leftPod, rightPod, casePod); // Airpods Pro
} else if ("1420".equals(idFull)) {
pods = new AirPodsPro2(leftPod, rightPod, casePod); // Airpods Pro 2
} else if ('A' == idSingle) {
pods = new AirPodsMax(singlePod); // Airpods Max
} else if ('B' == idSingle) {
pods = new PowerbeatsPro(leftPod, rightPod, casePod); // Powerbeats Pro
} else if ("0520".equals(idFull)) {
pods = new BeatsX(singlePod); // Beats X
} else if ("1020".equals(idFull)) {
pods = new BeatsFlex(singlePod); // Beats Flex
} else if ("0620".equals(idFull)) {
pods = new BeatsSolo3(singlePod); // Beats Solo 3
} else if ('9' == idSingle) {
pods = new BeatsStudio3(singlePod); // Beats Studio 3
} else if ("0320".equals(idFull)) {
pods = new Powerbeats3(singlePod); // Powerbeats 3
} else {
pods = new RegularPods(leftPod, rightPod, casePod); // Unknown
}
}
@@ -1,4 +1,6 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.pods.Pod;
public class AirPods1 extends RegularPods {
@@ -8,7 +10,7 @@ public class AirPods1 extends RegularPods {
@Override
public String getModel () {
return MODEL_AIRPODS_GEN1;
return Constants.MODEL_AIRPODS_GEN1;
}
}
@@ -1,4 +1,6 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.pods.Pod;
public class AirPods2 extends RegularPods {
@@ -8,7 +10,7 @@ public class AirPods2 extends RegularPods {
@Override
public String getModel () {
return MODEL_AIRPODS_GEN2;
return Constants.MODEL_AIRPODS_GEN2;
}
}
@@ -0,0 +1,16 @@
package com.dosse.airpods.pods.models;
import com.dosse.airpods.pods.Pod;
public class AirPods3 extends RegularPods {
public AirPods3(Pod leftPod, Pod rightPod, Pod casePod) {
super(leftPod, rightPod, casePod);
}
@Override
public String getModel () {
return Constants.MODEL_AIRPODS_GEN3;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class AirPodsMax extends SinglePods {
@@ -15,7 +16,7 @@ public class AirPodsMax extends SinglePods {
@Override
public String getModel () {
return MODEL_AIRPODS_MAX;
return Constants.MODEL_AIRPODS_MAX;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class AirPodsPro extends RegularPods {
@@ -25,7 +26,7 @@ public class AirPodsPro extends RegularPods {
@Override
public String getModel () {
return MODEL_AIRPODS_PRO;
return Constants.MODEL_AIRPODS_PRO;
}
}
@@ -0,0 +1,32 @@
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class AirPodsPro2 extends RegularPods {
public AirPodsPro2 (Pod leftPod, Pod rightPod, Pod casePod) {
super(leftPod, rightPod, casePod);
}
@Override
public int getLeftDrawable () {
return getPod(LEFT).isConnected() ? R.drawable.podpro : R.drawable.podpro_disconnected;
}
@Override
public int getRightDrawable () {
return getPod(RIGHT).isConnected() ? R.drawable.podpro : R.drawable.podpro_disconnected;
}
@Override
public int getCaseDrawable () {
return getPod(CASE).isConnected() ? R.drawable.podpro_case : R.drawable.podpro_case_disconnected;
}
@Override
public String getModel () {
return Constants.MODEL_AIRPODS_PRO_2;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class BeatsFlex extends SinglePods {
@@ -15,7 +16,7 @@ public class BeatsFlex extends SinglePods {
@Override
public String getModel () {
return MODEL_BEATS_FLEX;
return Constants.MODEL_BEATS_FLEX;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class BeatsSolo3 extends SinglePods {
@@ -15,7 +16,7 @@ public class BeatsSolo3 extends SinglePods {
@Override
public String getModel () {
return MODEL_BEATS_SOLO_3;
return Constants.MODEL_BEATS_SOLO_3;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class BeatsStudio3 extends SinglePods {
@@ -15,7 +16,7 @@ public class BeatsStudio3 extends SinglePods {
@Override
public String getModel () {
return MODEL_BEATS_STUDIO_3;
return Constants.MODEL_BEATS_STUDIO_3;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class BeatsX extends SinglePods {
@@ -15,7 +16,7 @@ public class BeatsX extends SinglePods {
@Override
public String getModel () {
return MODEL_BEATS_X;
return Constants.MODEL_BEATS_X;
}
}
@@ -0,0 +1,17 @@
package com.dosse.airpods.pods.models;
public final class Constants {
static final String MODEL_AIRPODS_GEN1 = "airpods1";
static final String MODEL_AIRPODS_GEN2 = "airpods2";
static final String MODEL_AIRPODS_GEN3 = "airpods3";
static final String MODEL_AIRPODS_PRO = "airpodspro";
static final String MODEL_AIRPODS_PRO_2 = "airpodspro2";
static final String MODEL_AIRPODS_MAX = "airpodsmax";
static final String MODEL_BEATS_X = "beatsx";
static final String MODEL_BEATS_FLEX = "beatsflex";
static final String MODEL_BEATS_SOLO_3 = "beatssolo3";
static final String MODEL_BEATS_STUDIO_3 = "beatsstudio3";
static final String MODEL_POWERBEATS_3 = "powerbeats3";
static final String MODEL_POWERBEATS_PRO = "powerbeatspro";
static final String MODEL_UNKNOWN = "unknown";
}
@@ -0,0 +1,13 @@
package com.dosse.airpods.pods.models;
public interface IPods {
String getModel ();
boolean isSingle ();
boolean isDisconnected ();
String parseStatusForLogger ();
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class Powerbeats3 extends SinglePods {
@@ -15,7 +16,7 @@ public class Powerbeats3 extends SinglePods {
@Override
public String getModel () {
return MODEL_POWERBEATS_3;
return Constants.MODEL_POWERBEATS_3;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
public class PowerbeatsPro extends RegularPods {
@@ -25,7 +26,7 @@ public class PowerbeatsPro extends RegularPods {
@Override
public String getModel () {
return MODEL_POWERBEATS_PRO;
return Constants.MODEL_POWERBEATS_PRO;
}
}
@@ -1,6 +1,7 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.R;
import com.dosse.airpods.pods.Pod;
import java.util.Locale;
@@ -48,7 +49,7 @@ public class RegularPods implements IPods {
@Override
public String getModel () {
return MODEL_UNKNOWN;
return Constants.MODEL_UNKNOWN;
}
@Override
@@ -1,4 +1,6 @@
package com.dosse.airpods.pods.data;
package com.dosse.airpods.pods.models;
import com.dosse.airpods.pods.Pod;
import java.util.Locale;
@@ -25,7 +25,7 @@ public class StartupReceiver extends BroadcastReceiver {
}
public static void startPodsService (Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService(new Intent(context, PodsService.class));
else
context.startService(new Intent(context, PodsService.class));
@@ -72,7 +72,7 @@ public class IntroActivity extends AppCompatActivity {
return STEP_PERMISSION_BATTERY_OPTIMIZATION;
if (!PermissionUtils.getFineLocationPermission(this))
return STEP_PERMISSION_LOCATION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) if (!PermissionUtils.getBackgroundLocationPermission(this))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) if (!PermissionUtils.getBackgroundLocationPermission(this))
return STEP_PERMISSION_BACKGROUND_LOCATION;
return 0;
@@ -81,7 +81,7 @@ public class IntroActivity extends AppCompatActivity {
@SuppressLint("BatteryLife")
private void initScreen () {
int currentStep = getPermissionState() - ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? 0 : 1);
int numOfSteps = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ? ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? 4 : 3) : 2;
int numOfSteps = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) ? ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? 4 : 3) : 2;
runOnUiThread(() -> {
switch (getPermissionState()) {
@@ -109,7 +109,7 @@ public class IntroActivity extends AppCompatActivity {
case STEP_PERMISSION_BACKGROUND_LOCATION:
msg.setText(String.format(Locale.getDefault(), "%s %d/%d: %s", getString(R.string.intro_step), currentStep, numOfSteps, getString(R.string.intro_loc2_perm)));
btn.setOnClickListener(view -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) requestPermissions(new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_REQUEST_CODE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) requestPermissions(new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_REQUEST_CODE);
});
break;
}
@@ -37,7 +37,7 @@ public class PermissionUtils {
}
public static boolean getLocationPermissions (Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return getFineLocationPermission(context) && getBackgroundLocationPermission(context);
else
return getFineLocationPermission(context);

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 551 KiB

After

Width:  |  Height:  |  Size: 551 KiB

Before

Width:  |  Height:  |  Size: 543 KiB

After

Width:  |  Height:  |  Size: 543 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 161 KiB

@@ -52,6 +52,11 @@
android:layout_height="wrap_content"
android:text="@string/airpods1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airpods3" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -89,6 +94,11 @@
android:layout_height="wrap_content"
android:text="@string/airpodsmax" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airpodspro2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -45,11 +45,21 @@
android:layout_height="wrap_content"
android:text="@string/airpods2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airpods3" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airpodspro" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/airpodspro2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 658 B

After

Width:  |  Height:  |  Size: 658 B

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 341 B

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More