diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 0000000..7163114
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,34 @@
+name: Android CI Build APK
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ # Set up JDK
+ - name: Set up JDK 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: gradle
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ - name: Build Debug APK
+ run: ./gradlew assembleDebug --no-daemon
+
+ - name: Upload Debug APK Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: app-debug-apk-from-cloud
+ path: app/build/outputs/apk/debug/*.apk
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..a945fdf
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,57 @@
+name: Android CI Build Release
+
+on:
+ push:
+ tags:
+ - '[0-9]+.[0-9]+*'
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: set up JDK 11
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: gradle
+
+ - name: Build Release APK
+ run: ./gradlew assembleRelease
+
+ - name: Sign APK
+ uses: r0adkll/sign-android-release@v1
+ id: sign_app
+ with:
+ releaseDirectory: app/build/outputs/apk/release
+ signingKeyBase64: ${{ secrets.SIGNING_KEY }}
+ alias: ${{ secrets.ALIAS }}
+ keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
+ keyPassword: ${{ secrets.KEY_PASSWORD }}
+ env:
+ BUILD_TOOLS_VERSION: "34.0.0"
+
+ - name: Rename and Strip Dots
+ id: rename_apk
+ run: |
+
+ raw_tag=${GITHUB_REF#refs/tags/}
+ clean_tag="${raw_tag//./}"
+ signed_file="${{ steps.sign_app.outputs.signedReleaseFile }}"
+ new_name="auto-off-bluetooth-${clean_tag}.apk"
+ mv "$signed_file" "app/build/outputs/apk/release/$new_name"
+ echo "new_path=app/build/outputs/apk/release/$new_name" >> $GITHUB_OUTPUT
+
+ - name: Upload Signed APK to GitHub Release
+ uses: softprops/action-gh-release@v1
+ with:
+ files: ${{ steps.rename_apk.outputs.new_path }}
+ generate_release_notes: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 30aa626..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 61a9130..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index 17fd017..0000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index bd152bd..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index ca94c59..73775aa 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,34 @@
-# autooffbluetooth
-A simple Android app to automatically turn off bluetooth if disconnected.
+# Auto Off Bluetooth
-No configuration, should work as-is, no guarentees and might need you to disable battery optimization for the app. For recent versions of android, it seems to need to be launched at least once for it to work.
+Auto Off Bluetooth is a lightweight utility for Android designed to preserve battery life and increase device security. The app monitors your Bluetooth connection status and automatically turns off the Bluetooth radio after 20 seconds if no devices are connected.
-If BT is disconnected and reconnected quickly, the app will avoid disabling unnecessarily.
+## How it works
-[](https://f-droid.org/packages/com.mystro256.autooffbluetooth/)
+The app listens for Bluetooth state changes in the stack and for Asynchronous Connection-Less disconnection events in the background. When a device disconnects, the app starts a timer. If the timer expires without a reconnection, the app automatically disables the Bluetooth adapter to save power. If a Bluetooth device reconnects, the app postpones the Auto Off task until the next disconnect.
+
+## Screenshots
-Use at your own risk, all code is licensed GPLv3, see [LICENSE file](https://github.com/Mystro256/autooffbluetooth/blob/master/LICENSE) for details.
+
+
+
+
+## Permissions
+
+The app requires the following permissions to manage your Bluetooth hardware:
+
+* `BLUETOOTH`: Allows the app to see the status of connections.
+* `BLUETOOTH_ADMIN`: Allows the app to toggle the Bluetooth radio on/off.
+* `BLUETOOTH_CONNECT`: To interact with paired devices (required for Android 12+).
+
+## Installation & License
+
+
+
+
+---
+
+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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+---
diff --git a/app/build.gradle b/app/build.gradle
index 0078838..a3433b5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,28 +1,43 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
+ // Required to support Android 12+ Bluetooth features
+ compileSdkVersion 31
+
defaultConfig {
- applicationId "com.mystro256.autooffbluetooth"
+ applicationId "com.mine.autooffbluetooth"
minSdkVersion 15
- targetSdkVersion 28
- versionCode 5
- versionName "1.4"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ targetSdkVersion 31
+ versionCode 6
+ versionName "1.5"
+
+ // Updated for AndroidX testing
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
+
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+
+ // Required for AGP 7.0+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
+ }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:28.0.0'
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+
+ // MIGRATED TO ANDROIDX: Replacements for com.android.support libraries
+ implementation 'androidx.appcompat:appcompat:1.4.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
+
+ // Testing dependencies updated for AndroidX
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
diff --git a/app/src/androidTest/java/com/mystro256/autooffbluetooth/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/mystro256/autooffbluetooth/ExampleInstrumentedTest.java
deleted file mode 100644
index af1b326..0000000
--- a/app/src/androidTest/java/com/mystro256/autooffbluetooth/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.mystro256.autooffbluetooth;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.mystro256.autooffbluetooth", appContext.getPackageName());
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 164027a..5141865 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,9 +1,11 @@
+ package="com.mine.autooffbluetooth">
-
-
+
+
+
+
-
+
+
-
-
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/java/com/mine/autooffbluetooth/BTReceiver.java b/app/src/main/java/com/mine/autooffbluetooth/BTReceiver.java
new file mode 100644
index 0000000..ecc1ff7
--- /dev/null
+++ b/app/src/main/java/com/mine/autooffbluetooth/BTReceiver.java
@@ -0,0 +1,117 @@
+package com.mine.autooffbluetooth;
+
+import android.Manifest;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import androidx.core.content.ContextCompat;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+public class BTReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "BTReceiver";
+ private static final Handler handler = new Handler(Looper.getMainLooper());
+
+ private static final Runnable shutdownTask = new Runnable() {
+ @Override
+ public void run() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null && adapter.isEnabled()) {
+ // If nothing has reconnected in 20 seconds, disable Bluetooth.
+ if (!isAnyDeviceConnected(adapter)) {
+ Log.d(TAG, "Confirmed: No devices. Turning off Bluetooth.");
+ try {
+ adapter.disable();
+ } catch (SecurityException e) {
+ Log.e(TAG, "Permission denied for disable()");
+ }
+ } else {
+ Log.d(TAG, "Device reconnected during countdown. Aborting shutdown.");
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (adapter == null || !adapter.isEnabled()) return;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT)
+ != PackageManager.PERMISSION_GRANTED) return;
+ }
+
+ Log.d(TAG, "Received Broadcast: " + action);
+
+ // If a device connects, always stop the timer immediately.
+ if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
+ Log.d(TAG, "ACL_CONNECTED: Stopping timer.");
+ handler.removeCallbacks(shutdownTask);
+ return;
+ }
+
+ // If a device disconnects.
+ if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action) ||
+ BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
+
+ Log.d(TAG, "ACL_DISCONNECTED: Triggering 20s countdown.");
+
+ // We wait 2 seconds before checking "isAnyDeviceConnected" to let the stack finish the disconnection process.
+ handler.postDelayed(() -> {
+ if (!isAnyDeviceConnected(adapter)) {
+ handler.removeCallbacks(shutdownTask);
+ handler.postDelayed(shutdownTask, 20000);
+ }
+ }, 2000);
+ }
+ }
+
+ private static boolean isAnyDeviceConnected(BluetoothAdapter adapter) {
+ // Standard Profiles: 1=Headset, 2=A2DP, 7=GATT, 4=HID, 5=PAN.
+ int[] profiles = {1, 2, 7, 4, 5};
+
+ for (int profileId : profiles) {
+ try {
+ int state = adapter.getProfileConnectionState(profileId);
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ Log.d(TAG, "Active Profile Found: " + profileId);
+ return true;
+ }
+ } catch (Exception e) { }
+ }
+
+ // Bonded Reflection.
+ try {
+ Set bondedDevices = adapter.getBondedDevices();
+ if (bondedDevices != null) {
+ for (BluetoothDevice device : bondedDevices) {
+ if (isConnectedReflection(device)) {
+ Log.d(TAG, "Active Device Found (Reflection): " + device.getName());
+ return true;
+ }
+ }
+ }
+ } catch (SecurityException e) { }
+
+ return false;
+ }
+
+ private static boolean isConnectedReflection(BluetoothDevice device) {
+ try {
+ Method m = device.getClass().getMethod("isConnected");
+ return (boolean) m.invoke(device);
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/app/src/main/java/com/mine/autooffbluetooth/MainActivity.java b/app/src/main/java/com/mine/autooffbluetooth/MainActivity.java
new file mode 100644
index 0000000..b433670
--- /dev/null
+++ b/app/src/main/java/com/mine/autooffbluetooth/MainActivity.java
@@ -0,0 +1,86 @@
+package com.mine.autooffbluetooth;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.view.View;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MainActivity extends AppCompatActivity {
+
+ private static final int PERMISSION_REQUEST_CODE = 101;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ checkAndRequestPermissions();
+ }
+
+ public void disableBatteryOptimization(View view) {
+ requestIgnoreBatteryOptimizations();
+ }
+
+ private void checkAndRequestPermissions() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ List permissionsNeeded = new ArrayList<>();
+
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
+ permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
+ }
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
+ permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
+ }
+
+ if (!permissionsNeeded.isEmpty()) {
+ ActivityCompat.requestPermissions(this, permissionsNeeded.toArray(new String[0]), PERMISSION_REQUEST_CODE);
+ }
+ }
+ }
+
+ private void requestIgnoreBatteryOptimizations() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ String packageName = getPackageName();
+ PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+
+ // Check if already allowed
+ if (pm != null && !pm.isIgnoringBatteryOptimizations(packageName)) {
+ try {
+ Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ intent.setData(Uri.parse("package:" + packageName));
+ startActivity(intent);
+ } catch (Exception e) {
+ // Fallback for devices that block direct intent
+ Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
+ startActivity(intent);
+ }
+ } else {
+ Toast.makeText(this, "Battery optimization is already disabled.", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (requestCode == PERMISSION_REQUEST_CODE) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "Bluetooth permissions granted!", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(this, "Permissions are required to detect your watch/headphones.", Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/mystro256/autooffbluetooth/BTReceiver.java b/app/src/main/java/com/mystro256/autooffbluetooth/BTReceiver.java
deleted file mode 100644
index 24fd979..0000000
--- a/app/src/main/java/com/mystro256/autooffbluetooth/BTReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.mystro256.autooffbluetooth;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class BTReceiver extends BroadcastReceiver {
-
- // "OnReceive" is an abstract function called when there's BT activity
- // or state change; we can use this to try to catch a disconnection. When
- // called, if no devices are connected then we can disable BT.
- // See AndroidManifest.xml for the intent triggers.
- @Override
- public void onReceive(Context context, Intent intent) {
- // Check if BT adapter is valid and hasn't already been disabled
- if (BluetoothAdapter.getDefaultAdapter() != null && BluetoothAdapter.getDefaultAdapter().isEnabled()) {
- int[] profiles = {BluetoothProfile.A2DP, BluetoothProfile.HEADSET, BluetoothProfile.HEALTH};
- for (int profileId : profiles) {
- // If any device is connected, return to avoid disabling BT
- if (BluetoothAdapter.getDefaultAdapter().getProfileConnectionState(profileId) ==
- BluetoothProfile.STATE_CONNECTED) {
- return;
- }
- }
- // This point should only be reacted if nothing is connected
- BluetoothAdapter.getDefaultAdapter().disable();
- }
- }
-
-}
diff --git a/app/src/main/java/com/mystro256/autooffbluetooth/MainActivity.java b/app/src/main/java/com/mystro256/autooffbluetooth/MainActivity.java
deleted file mode 100644
index fb0f2c0..0000000
--- a/app/src/main/java/com/mystro256/autooffbluetooth/MainActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.mystro256.autooffbluetooth;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.PowerManager;
-import android.provider.Settings;
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class MainActivity extends AppCompatActivity {
-
- static final int DISABLE_BATTERY_OPTIMIZATION = 0;
-
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- // Call back if user agrees to disabling battery optimization
- if (requestCode == DISABLE_BATTERY_OPTIMIZATION) {
- if (resultCode == RESULT_OK) {
- hideBatteryOptimization();
- }
- }
- }
-
- // By default, a battery optimization warning amd button is shown; this
- // function hides the warning/button and shows the welcome text instead
- private void hideBatteryOptimization() {
- TextView WelcomeText = findViewById(R.id.WelcomeText);
- TextView batteryOptimizationText = findViewById(R.id.batteryOptimizationText);
- Button batteryOptimizationButton = findViewById(R.id.batteryOptimizationButton);
-
- WelcomeText.setVisibility(View.VISIBLE);
- batteryOptimizationText.setVisibility(View.GONE);
- batteryOptimizationButton.setVisibility(View.GONE);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Hide battery optimization warning if battery optimization is
- // already disabled or user is running something older than android M
- PowerManager powMan = (PowerManager) getSystemService(POWER_SERVICE);
- String packageName = getPackageName();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
- powMan.isIgnoringBatteryOptimizations(packageName)) {
- hideBatteryOptimization();
- }
- }
-
- public void disableBatteryOptimization(View v) {
- Intent intent = new Intent();
- String packageName = getPackageName();
-
- // Request disabling battery optimization and request a call back
- intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- intent.setData(Uri.parse("package:" + packageName));
- startActivityForResult(intent, DISABLE_BATTERY_OPTIMIZATION);
- }
-}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 9764ca0..7c5f68d 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,5 +1,6 @@
-
-
\ No newline at end of file
+
diff --git a/app/src/test/java/com/mystro256/autooffbluetooth/ExampleUnitTest.java b/app/src/test/java/com/mystro256/autooffbluetooth/ExampleUnitTest.java
deleted file mode 100644
index 7f229e2..0000000
--- a/app/src/test/java/com/mystro256/autooffbluetooth/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.mystro256.autooffbluetooth;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 9313af6..e970f21 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,24 +1,17 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
buildscript {
repositories {
google()
- jcenter()
-
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ classpath 'com.android.tools.build:gradle:7.2.2'
}
}
allprojects {
repositories {
google()
- jcenter()
-
+ mavenCentral()
}
}
diff --git a/fastlane/metadata/android/de/short_description.txt b/fastlane/metadata/android/de/short_description.txt
deleted file mode 100644
index cfa5809..0000000
--- a/fastlane/metadata/android/de/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Bluetooth automatisch bei Disconnect abschalten
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2.txt b/fastlane/metadata/android/en-US/changelogs/2.txt
deleted file mode 100644
index 713a46a..0000000
--- a/fastlane/metadata/android/en-US/changelogs/2.txt
+++ /dev/null
@@ -1 +0,0 @@
-* Changing from leanback launcher to regular launcher to fix on Android Pie
diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt
deleted file mode 100644
index dcbd1b9..0000000
--- a/fastlane/metadata/android/en-US/changelogs/3.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-* Detects and suggests disabling battery optimization if available
-* Built with newer tools
diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt
deleted file mode 100644
index 1f8d5b1..0000000
--- a/fastlane/metadata/android/en-US/changelogs/4.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-* French, Spanish, and Portuguese translations
-* Fix bug: don't hide battery optimization warning if user denies disabling it
diff --git a/fastlane/metadata/android/en-US/changelogs/5.txt b/fastlane/metadata/android/en-US/changelogs/5.txt
deleted file mode 100644
index 7cc4e51..0000000
--- a/fastlane/metadata/android/en-US/changelogs/5.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-* Drop unnecessary wake lock permission
-* Add new icon
diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt
deleted file mode 100644
index 0cc2bf6..0000000
--- a/fastlane/metadata/android/en-US/full_description.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-A simple Android app to automatically turn off bluetooth if disconnected.
-
-No configuration, should work as-is, no guarentees and might need you to disable battery optimization for the app. For recent versions of android, it seems to need to be launched at least once for it to work.
-
-If BT is disconnected and reconnected quickly, the app will avoid disabling unnecessarily.
diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt
deleted file mode 100644
index 7a91b18..0000000
--- a/fastlane/metadata/android/en-US/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Automatically turn off bluetooth if disconnected
diff --git a/fastlane/metadata/android/es-ES/full_description.txt b/fastlane/metadata/android/es-ES/full_description.txt
deleted file mode 100644
index d8fe4fa..0000000
--- a/fastlane/metadata/android/es-ES/full_description.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Una aplicación simple de Android para apagar automáticamente la conectividad blutooth en caso que este sea desconectado.
-
-No se necesita configuración, deberia de funcionar tal cual. No se garantiza su funcionamiento y puede que se llegue a necesitar la desactivación de la optimización de energía para la aplicación. Para versiones recientes de android parece que se necesita inicializar el programa al menos una véz.
-
-Si el bluetooth se desconecta y reconecta de forma rápida, la aplicación evitará ser activada de forma innecesaria.
-
diff --git a/fastlane/metadata/android/es-ES/short_description.txt b/fastlane/metadata/android/es-ES/short_description.txt
deleted file mode 100644
index 9ca6904..0000000
--- a/fastlane/metadata/android/es-ES/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Apagar el blutooth automáticamente en caso que sea desconectado.
\ No newline at end of file
diff --git a/fastlane/metadata/android/es-ES/title.txt b/fastlane/metadata/android/es-ES/title.txt
deleted file mode 100644
index 1396bfc..0000000
--- a/fastlane/metadata/android/es-ES/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-Auto apagador de Bluetooth
\ No newline at end of file
diff --git a/fastlane/metadata/android/fr/short_description.txt b/fastlane/metadata/android/fr/short_description.txt
deleted file mode 100644
index 9efd4a5..0000000
--- a/fastlane/metadata/android/fr/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Désactiver automatiquement Bluetooth lors de la déconnexion
diff --git a/fastlane/metadata/android/fr/title.txt b/fastlane/metadata/android/fr/title.txt
deleted file mode 100644
index b1d46bd..0000000
--- a/fastlane/metadata/android/fr/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-Auto-Désactivé Bluetooth
diff --git a/fastlane/metadata/android/pt/full_description.txt b/fastlane/metadata/android/pt/full_description.txt
deleted file mode 100644
index b07a0b7..0000000
--- a/fastlane/metadata/android/pt/full_description.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Um aplicativo Android simples para desactivar automaticamente o bluetooth quando desconectado.
-
-Sem configuração, deve funcionar como está, sem garantias e pode ser necessário desativar a otimização da bateria para o aplicativo. Para versões recentes do Android, parece que ele precisa ser iniciado pelo menos uma vez para funcionar.
-
-Se o BT for desconectado e reconectado rapidamente, o aplicativo evitará a desativação desnecessária.
diff --git a/fastlane/metadata/android/pt/short_description.txt b/fastlane/metadata/android/pt/short_description.txt
deleted file mode 100644
index 8d5ac51..0000000
--- a/fastlane/metadata/android/pt/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Desactivar automaticamente o bluetooth se desconectado
diff --git a/fastlane/metadata/android/pt/title.txt b/fastlane/metadata/android/pt/title.txt
deleted file mode 100644
index f619081..0000000
--- a/fastlane/metadata/android/pt/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-Desligamento automático do bluetooth
diff --git a/gradle.properties b/gradle.properties
index 82618ce..e694a99 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,15 +1,6 @@
# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-
+# Mandatory fix for AndroidX dependencies
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 3eb1008..2ec77e5 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=23e7d37e9bb4f8dabb8a3ea7fdee9dd0428b9b1a71d298aefd65b11dccea220f
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/images/GitHub.png b/images/GitHub.png
new file mode 100644
index 0000000..9082d22
Binary files /dev/null and b/images/GitHub.png differ
diff --git a/images/IzzyOnDroid.png b/images/IzzyOnDroid.png
new file mode 100644
index 0000000..cb10c3a
Binary files /dev/null and b/images/IzzyOnDroid.png differ
diff --git a/metadata/en-US/changelogs/1.txt b/metadata/en-US/changelogs/1.txt
new file mode 100644
index 0000000..37b509f
--- /dev/null
+++ b/metadata/en-US/changelogs/1.txt
@@ -0,0 +1 @@
+Initial release of the Auto Off Bluetooth application that is available in F-Droid repository, but seems being abandoned by its author. The app is built from the source code based on the 1.4 codebase with improved algorithm logic and Android newer versions compatibility.
diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt
new file mode 100644
index 0000000..78e3e67
--- /dev/null
+++ b/metadata/en-US/full_description.txt
@@ -0,0 +1,15 @@
+Auto Off Bluetooth
+
+Auto Off Bluetooth is a lightweight utility for Android designed to preserve battery life and increase device security. The app monitors your Bluetooth connection status and automatically turns off the Bluetooth radio after 20 seconds if no devices are connected.
+
+How it works
+
+The app listens for Bluetooth state changes in the stack and for Asynchronous Connection-Less disconnection events in the background. When a device disconnects, the app starts a timer. If the timer expires without a reconnection, the app automatically disables the Bluetooth adapter to save power. If a Bluetooth device reconnects, the app postpones the Auto Off task until the next disconnect.
+
+Permissions
+
+The app requires the following permissions to manage your Bluetooth hardware:
+
+* BLUETOOTH: Allows the app to see the status of connections.
+* BLUETOOTH_ADMIN: Allows the app to toggle the Bluetooth radio on/off.
+* BLUETOOTH_CONNECT: To interact with paired devices (required for Android 12+).
diff --git a/metadata/en-US/images/icon.png b/metadata/en-US/images/icon.png
new file mode 100644
index 0000000..22b9a95
Binary files /dev/null and b/metadata/en-US/images/icon.png differ
diff --git a/metadata/en-US/images/phoneScreenshots/01.png b/metadata/en-US/images/phoneScreenshots/01.png
new file mode 100644
index 0000000..1b206fb
Binary files /dev/null and b/metadata/en-US/images/phoneScreenshots/01.png differ
diff --git a/metadata/en-US/short_description.txt b/metadata/en-US/short_description.txt
new file mode 100644
index 0000000..9dc90c7
--- /dev/null
+++ b/metadata/en-US/short_description.txt
@@ -0,0 +1 @@
+The app monitors Bluetooth connection status and automatically turns it off.
diff --git a/fastlane/metadata/android/en-US/title.txt b/metadata/en-US/title.txt
similarity index 100%
rename from fastlane/metadata/android/en-US/title.txt
rename to metadata/en-US/title.txt