idk what i'm doing

This commit is contained in:
Kavish Devar
2024-12-01 22:25:18 +05:30
parent 4a1d7df82d
commit 71dffd1415
6 changed files with 181 additions and 39 deletions

View File

@@ -22,6 +22,7 @@ import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.lsposed.hiddenapibypass.HiddenApiBypass import org.lsposed.hiddenapibypass.HiddenApiBypass
@@ -35,8 +36,8 @@ class AirPodsService: Service() {
return LocalBinder() return LocalBinder()
} }
fun showPopup(context: Context, name: String) { fun showPopup(service: Service, name: String) {
val window = Window(context) val window = Window(service.applicationContext)
window.open(name, batteryNotification) window.open(name, batteryNotification)
} }
@@ -47,6 +48,7 @@ class AirPodsService: Service() {
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java) intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java)
val action = intent.action val action = intent.action
val context = context?.applicationContext val context = context?.applicationContext
val name = context?.getSharedPreferences("settings", MODE_PRIVATE)?.getString("name", bluetoothDevice?.name)
if (bluetoothDevice != null && action != null && !action.isEmpty()) { if (bluetoothDevice != null && action != null && !action.isEmpty()) {
Log.d("BluetoothReceiver", "Received broadcast") Log.d("BluetoothReceiver", "Received broadcast")
if (BluetoothDevice.ACTION_ACL_CONNECTED == action) { if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
@@ -54,7 +56,7 @@ class AirPodsService: Service() {
if (bluetoothDevice.uuids.contains(uuid)) { if (bluetoothDevice.uuids.contains(uuid)) {
Log.d("AirPodsService", "Service started") Log.d("AirPodsService", "Service started")
val intent = Intent(AirPodsNotifications.AIRPODS_CONNECTION_DETECTED) val intent = Intent(AirPodsNotifications.AIRPODS_CONNECTION_DETECTED)
intent.putExtra("name", bluetoothDevice.name) intent.putExtra("name", name)
intent.putExtra("device", bluetoothDevice) intent.putExtra("device", bluetoothDevice)
context?.sendBroadcast(intent) context?.sendBroadcast(intent)
} }
@@ -104,8 +106,9 @@ class AirPodsService: Service() {
registerReceiver(object: BroadcastReceiver() { registerReceiver(object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
showPopup(context!!, intent!!.getStringExtra("name")!!) val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).getString("name", device?.name)
device = intent.getParcelableExtra("device", BluetoothDevice::class.java)!! device = intent?.getParcelableExtra("device", BluetoothDevice::class.java)!!
showPopup(this@AirPodsService, name.toString())
connectToSocket(device!!) connectToSocket(device!!)
sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED).apply { sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED).apply {
putExtra("device", device) putExtra("device", device)
@@ -188,12 +191,18 @@ class AirPodsService: Service() {
this@AirPodsService.device = device this@AirPodsService.device = device
isConnected = true isConnected = true
socket.let { it -> socket.let { it ->
it.outputStream.write(Enums.HANDSHAKE.value) CoroutineScope(Dispatchers.IO).launch {
it.outputStream.flush() it.outputStream.write(Enums.HANDSHAKE.value)
it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value) it.outputStream.flush()
it.outputStream.flush() delay(500)
it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value) it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
it.outputStream.flush() it.outputStream.flush()
delay(500)
it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
it.outputStream.flush()
Log.d("AirPodsService","This should run first")
}
Log.d("AirPodsService","This should run later")
sendBroadcast( sendBroadcast(
Intent(AirPodsNotifications.AIRPODS_CONNECTED) Intent(AirPodsNotifications.AIRPODS_CONNECTED)
.putExtra("device", device) .putExtra("device", device)

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothDevice
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
@@ -82,6 +83,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.primex.core.ExperimentalToolkitApi import com.primex.core.ExperimentalToolkitApi
import com.primex.core.blur.newBackgroundBlur import com.primex.core.blur.newBackgroundBlur
import me.kavishdevar.aln.AirPodsService
import kotlin.math.roundToInt import kotlin.math.roundToInt
@Composable @Composable
@@ -90,7 +92,12 @@ fun BatteryView() {
@Suppress("DEPRECATION") val batteryReceiver = remember { @Suppress("DEPRECATION") val batteryReceiver = remember {
object : BroadcastReceiver() { object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
batteryStatus.value = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { intent.getParcelableArrayListExtra("data", Battery::class.java) } else { intent.getParcelableArrayListExtra("data") }?.toList() ?: listOf() batteryStatus.value =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableArrayListExtra("data", Battery::class.java)
} else {
intent.getParcelableArrayListExtra("data")
}?.toList() ?: listOf()
} }
} }
} }
@@ -99,7 +106,11 @@ fun BatteryView() {
LaunchedEffect(context) { LaunchedEffect(context) {
val batteryIntentFilter = IntentFilter(AirPodsNotifications.BATTERY_DATA) val batteryIntentFilter = IntentFilter(AirPodsNotifications.BATTERY_DATA)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(batteryReceiver, batteryIntentFilter, Context.RECEIVER_EXPORTED) context.registerReceiver(
batteryReceiver,
batteryIntentFilter,
Context.RECEIVER_EXPORTED
)
} }
} }
@@ -482,7 +493,7 @@ fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService?,
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
title = { title = {
Text( Text(
text = if (device != null) device.name else "", text = if (device != null) LocalContext.current.getSharedPreferences("settings", MODE_PRIVATE).getString("name", device.name).toString() else "",
color = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black, color = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black,
) )
}, },

View File

@@ -53,9 +53,10 @@ class CustomDevice : ComponentActivity() {
HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;") HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
val manager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager val manager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
// val device: BluetoothDevice = manager.adapter.getRemoteDevice("EC:D6:F4:3D:89:B8") // val device: BluetoothDevice = manager.adapter.getRemoteDevice("EC:D6:F4:3D:89:B8")
val device: BluetoothDevice = manager.adapter.getRemoteDevice("E0:90:8F:D9:94:73") val device: BluetoothDevice = manager.adapter.getRemoteDevice("DE:F4:C6:A3:CD:7A")
// val socket = device.createInsecureL2capChannel(31) // val socket = device.createInsecureL2capChannel(31)
val batteryLevel = remember { mutableStateOf("") }
// socket.outputStream.write(byteArrayOf(0x12,0x3B,0x00,0x02, 0x00)) // socket.outputStream.write(byteArrayOf(0x12,0x3B,0x00,0x02, 0x00))
// socket.outputStream.write(byteArrayOf(0x12, 0x3A, 0x00, 0x01, 0x00, 0x08,0x01)) // socket.outputStream.write(byteArrayOf(0x12, 0x3A, 0x00, 0x01, 0x00, 0x08,0x01))
@@ -66,9 +67,12 @@ class CustomDevice : ComponentActivity() {
gatt.services.forEach { service -> gatt.services.forEach { service ->
Log.d("GATT", "Service UUID: ${service.uuid}") Log.d("GATT", "Service UUID: ${service.uuid}")
service.characteristics.forEach { characteristic -> service.characteristics.forEach { characteristic ->
Log.d("GATT", " Characteristic UUID: ${characteristic.uuid}") characteristic.descriptors.forEach { descriptor ->
Log.d("GATT", " Descriptor UUID: ${descriptor.uuid}: ${gatt.readDescriptor(descriptor)}")
}
} }
} }
} }
} }
@@ -115,12 +119,13 @@ class CustomDevice : ComponentActivity() {
} }
Button(onClick = { Button(onClick = {
val characteristicUuid = "4f860002-943b-49ef-bed4-2f730304427a" // val characteristicUuid = "4f860002-943b-49ef-bed4-2f730304427a"
val value = byteArrayOf(0x01, 0x00, 0x02) // val value = byteArrayOf(0x01, 0x00, 0x02)
// sendWriteRequest(gatt, characteristicUuid, value)
sendWriteRequest(gatt, characteristicUuid, value)
}) { }) {
Text("Play Sound") Text("batteryLevel.value")
} }
} }
} }

View File

@@ -77,7 +77,6 @@ fun Main() {
context.registerReceiver(disconnectReceiver, IntentFilter(AirPodsNotifications.AIRPODS_DISCONNECTED), context.registerReceiver(disconnectReceiver, IntentFilter(AirPodsNotifications.AIRPODS_DISCONNECTED),
Context.RECEIVER_NOT_EXPORTED) Context.RECEIVER_NOT_EXPORTED)
// UI logic // UI logic
NavHost( NavHost(
navController = navController, navController = navController,
@@ -127,7 +126,8 @@ fun Main() {
context.bindService(Intent(context, AirPodsService::class.java), serviceConnection, Context.BIND_AUTO_CREATE) context.bindService(Intent(context, AirPodsService::class.java), serviceConnection, Context.BIND_AUTO_CREATE)
if (airPodsService.value?.isConnected == true) { val alreadyConnected = remember { mutableStateOf(false) }
if (airPodsService.value?.isConnected == true && !alreadyConnected.value) {
Log.d("ALN", "Connected") Log.d("ALN", "Connected")
navController.navigate("settings") navController.navigate("settings")
} else { } else {

View File

@@ -14,17 +14,19 @@ import android.view.WindowManager
import android.view.animation.AccelerateInterpolator import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import android.widget.VideoView import android.widget.VideoView
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.setViewTreeLifecycleOwner
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.lang.Exception import java.lang.Exception
class Window @SuppressLint("InflateParams") constructor( @SuppressLint("InflateParams")
context: Context class Window (context: Context) {
) {
private val mView: View private val mView: View
private val mParams: WindowManager.LayoutParams = WindowManager.LayoutParams( private val mParams: WindowManager.LayoutParams = WindowManager.LayoutParams(
(context.resources.displayMetrics.widthPixels * 0.95).toInt(), (context.resources.displayMetrics.widthPixels * 0.95).toInt(),
@@ -50,6 +52,11 @@ class Window @SuppressLint("InflateParams") constructor(
close() close()
} }
val ll = mView.findViewById<LinearLayout>(R.id.linear_layout)
ll.setOnClickListener {
close()
}
ll.setViewTreeLifecycleOwner(mView.findViewTreeLifecycleOwner())
mWindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager mWindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
} }
@@ -62,17 +69,81 @@ class Window @SuppressLint("InflateParams") constructor(
mWindowManager.addView(mView, mParams) mWindowManager.addView(mView, mParams)
mView.findViewById<TextView>(R.id.name).text = name mView.findViewById<TextView>(R.id.name).text = name
val vid = mView.findViewById<VideoView>(R.id.video) val vid = mView.findViewById<VideoView>(R.id.video)
vid.setVideoPath("android.resource://me.kavishdevar.aln/" + R.raw.connected) vid.setVideoPath("android.resource://me.kavishdevar.aln/" + R.raw.connected)
vid.resolveAdjustedSize(vid.width, vid.height) vid.resolveAdjustedSize(vid.width, vid.height)
vid.start() vid.start()
vid.setOnCompletionListener { vid.setOnCompletionListener {
vid.start() vid.start()
} }
// receive battery broadcast and set to R.id.battery val batteryStatus = batteryNotification.getBattery()
val batteryText = mView.findViewById<TextView>(R.id.battery) val batteryLeftText = mView.findViewById<TextView>(R.id.left_battery)
val batteryList = batteryNotification.getBattery() val batteryRightText = mView.findViewById<TextView>(R.id.right_battery)
batteryText.text = "Why are the battery levels zero :( " + batteryList[0].level.toString() + "%" + " " + batteryList[0].status + " " + batteryList[1].level.toString() + "%" + " " + batteryList[1].status + " " + batteryList[2].level.toString() + "%" + " " + batteryList[2].status val batteryCaseText = mView.findViewById<TextView>(R.id.case_battery)
batteryLeftText.text = batteryStatus.find { it.component == BatteryComponent.LEFT }?.let {
"\uDBC3\uDC8E ${it.level}%"
} ?: ""
batteryRightText.text = batteryStatus.find { it.component == BatteryComponent.RIGHT }?.let {
"\uDBC3\uDC8D ${it.level}%"
} ?: ""
batteryCaseText.text = batteryStatus.find { it.component == BatteryComponent.CASE }?.let {
"\uDBC3\uDE6C ${it.level}%"
} ?: ""
// bText.text =
// batteryStatus.joinToString(separator = "") {
// when (it.component) {
// BatteryComponent.LEFT -> "\uDBC6\uDCE5 ${it.level}%"
// BatteryComponent.RIGHT -> "\uDBC6\uDCE8 ${it.level}%"
// BatteryComponent.CASE -> "\uDBC6\uDCE6 ${it.level}%"
// else -> ""
// }
// }
// composeView.setContent {
// Row (
// modifier = Modifier
// .fillMaxWidth(),
// horizontalArrangement = Arrangement.Center,
// verticalAlignment = Alignment.CenterVertically
// ) {
// Row (
// modifier = Modifier
// .fillMaxWidth(0.5f),
// horizontalArrangement = Arrangement.SpaceBetween
// ){
// val left = batteryStatus.find { it.component == BatteryComponent.LEFT }
// val right = batteryStatus.find { it.component == BatteryComponent.RIGHT }
// if ((right?.status == BatteryStatus.CHARGING && left?.status == BatteryStatus.CHARGING) || (left?.status == BatteryStatus.NOT_CHARGING && right?.status == BatteryStatus.NOT_CHARGING))
// {
// BatteryIndicator(right.level.let { left.level.coerceAtMost(it) }, left.status == BatteryStatus.CHARGING)
// }
// else {
// Row {
// if (left?.status != BatteryStatus.DISCONNECTED) {
// Text(text = "\uDBC6\uDCE5", fontFamily = FontFamily(Font(R.font.sf_pro)))
// BatteryIndicator(left?.level ?: 0, left?.status == BatteryStatus.CHARGING)
// Spacer(modifier = Modifier.width(16.dp))
// }
// if (right?.status != BatteryStatus.DISCONNECTED) {
// Text(text = "\uDBC6\uDCE8", fontFamily = FontFamily(Font(R.font.sf_pro)))
// BatteryIndicator(right?.level ?: 0, right?.status == BatteryStatus.CHARGING)
// }
// }
// }
// }
// Row (
// modifier = Modifier
// .fillMaxWidth(),
// horizontalArrangement = Arrangement.Center
// ) {
// val case =
// batteryStatus.find { it.component == BatteryComponent.CASE }
// BatteryIndicator(case?.level ?: 0)
// }
// }
// }
// Slide-up animation // Slide-up animation
val displayMetrics = mView.context.resources.displayMetrics val displayMetrics = mView.context.resources.displayMetrics

View File

@@ -5,6 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16.dp" android:layout_margin="16.dp"
android:id="@+id/linear_layout"
android:orientation="vertical" android:orientation="vertical"
android:background="@drawable/shape"> android:background="@drawable/shape">
@@ -12,6 +13,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="end" android:gravity="end"
android:id="@+id/constraint_layout"
android:paddingBottom="48dp" android:paddingBottom="48dp"
android:orientation="horizontal"> android:orientation="horizontal">
@@ -49,15 +51,59 @@
android:contentDescription="AirPods" android:contentDescription="AirPods"
android:src="@raw/connected" android:src="@raw/connected"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView
android:id="@+id/battery" <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:orientation="horizontal">
android:fontFamily="@font/sf_pro"
android:gravity="center" <!-- Left Half -->
android:text="" <LinearLayout
android:textColor="@color/white" android:layout_width="0dp"
android:textSize="16sp" android:layout_height="wrap_content"
tools:ignore="HardcodedText" /> android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAlignment="center"
android:layout_marginTop="16dp"
android:fontFamily="@font/sf_pro"
android:text=""
android:textColor="@color/white"
android:textSize="20sp"
android:id="@+id/left_battery"
android:gravity="center"
tools:ignore="NestedWeights" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAlignment="center"
android:layout_marginTop="16dp"
android:fontFamily="@font/sf_pro"
android:gravity="center"
android:text=""
android:id="@+id/right_battery"
android:textColor="@color/white"
android:textSize="20sp" />
</LinearLayout>
<!-- Right Half -->
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAlignment="center"
android:id="@+id/case_battery"
android:layout_marginTop="16dp"
android:fontFamily="@font/sf_pro"
android:gravity="center"
android:text=""
android:textColor="@color/white"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>