mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-01-28 22:01:50 +00:00
try adding widget; add previews to each composable
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".AirPodsService"
|
||||
android:name=".services.AirPodsService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:foregroundServiceType="connectedDevice"
|
||||
|
||||
@@ -3,11 +3,12 @@ package me.kavishdevar.aln
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.widget.RemoteViews
|
||||
import me.kavishdevar.aln.services.ServiceManager
|
||||
import me.kavishdevar.aln.utils.BatteryComponent
|
||||
import me.kavishdevar.aln.utils.BatteryStatus
|
||||
|
||||
/**
|
||||
* Implementation of App Widget functionality.
|
||||
*/
|
||||
class BatteryWidget : AppWidgetProvider() {
|
||||
override fun onUpdate(
|
||||
context: Context,
|
||||
@@ -34,11 +35,36 @@ internal fun updateAppWidget(
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetId: Int
|
||||
) {
|
||||
val widgetText = context.getString(R.string.appwidget_text)
|
||||
// Construct the RemoteViews object
|
||||
val views = RemoteViews(context.packageName, R.layout.battery_widget)
|
||||
views.setTextViewText(R.id.appwidget_text, widgetText)
|
||||
val service = ServiceManager.getService()
|
||||
val batteryList = service?.batteryNotification?.getBattery()
|
||||
|
||||
val views = RemoteViews(context.packageName, R.layout.battery_widget)
|
||||
Log.d("BatteryWidget", "Battery list: $batteryList")
|
||||
|
||||
views.setTextViewText(R.id.left_battery_widget,
|
||||
batteryList?.find { it.component == BatteryComponent.LEFT }?.let {
|
||||
if (it.status != BatteryStatus.DISCONNECTED) {
|
||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} ?: "")
|
||||
views.setTextViewText(R.id.right_battery_widget,
|
||||
batteryList?.find { it.component == BatteryComponent.RIGHT }?.let {
|
||||
if (it.status != BatteryStatus.DISCONNECTED) {
|
||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} ?: "")
|
||||
views.setTextViewText(R.id.case_battery_widget,
|
||||
batteryList?.find { it.component == BatteryComponent.CASE }?.let {
|
||||
if (it.status != BatteryStatus.DISCONNECTED) {
|
||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} ?: "")
|
||||
|
||||
// Instruct the widget manager to update the widget
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
@@ -37,7 +37,9 @@ import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import me.kavishdevar.aln.screens.AirPodsSettingsScreen
|
||||
import me.kavishdevar.aln.screens.DebugScreen
|
||||
import me.kavishdevar.aln.screens.LongPress
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.ui.theme.ALNTheme
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
|
||||
lateinit var serviceConnection: ServiceConnection
|
||||
lateinit var connectionStatusReceiver: BroadcastReceiver
|
||||
|
||||
@@ -1,463 +0,0 @@
|
||||
//@file:Suppress("unused")
|
||||
//
|
||||
//package me.kavishdevar.aln
|
||||
//
|
||||
//import android.annotation.SuppressLint
|
||||
//import android.app.Notification
|
||||
//import android.app.NotificationChannel
|
||||
//import android.app.NotificationManager
|
||||
//import android.app.Service
|
||||
//import android.bluetooth.BluetoothDevice
|
||||
//import android.bluetooth.BluetoothManager
|
||||
//import android.bluetooth.BluetoothProfile
|
||||
//import android.bluetooth.BluetoothSocket
|
||||
//import android.content.BroadcastReceiver
|
||||
//import android.content.Context
|
||||
//import android.content.Intent
|
||||
//import android.content.IntentFilter
|
||||
//import android.media.AudioManager
|
||||
//import android.os.Binder
|
||||
//import android.os.Build
|
||||
//import android.os.IBinder
|
||||
//import android.os.ParcelUuid
|
||||
//import android.util.Log
|
||||
//import androidx.core.app.NotificationCompat
|
||||
//import kotlinx.coroutines.CoroutineScope
|
||||
//import kotlinx.coroutines.Dispatchers
|
||||
//import kotlinx.coroutines.launch
|
||||
//import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||
//
|
||||
//object ServiceManager {
|
||||
// private var service: OldAirPodsService? = null
|
||||
// @Synchronized
|
||||
// fun getService(): OldAirPodsService? {
|
||||
// return service
|
||||
// }
|
||||
// @Synchronized
|
||||
// fun setService(service: OldAirPodsService?) {
|
||||
// this.service = service
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//class OldAirPodsService : Service() {
|
||||
// inner class LocalBinder : Binder() {
|
||||
// fun getService(): OldAirPodsService = this@OldAirPodsService
|
||||
// }
|
||||
//
|
||||
// override fun onBind(intent: Intent?): IBinder {
|
||||
// return LocalBinder()
|
||||
// }
|
||||
//
|
||||
// var isConnected: Boolean = false
|
||||
// private var socket: BluetoothSocket? = null
|
||||
//
|
||||
// fun sendPacket(packet: String) {
|
||||
// val fromHex = packet.split(" ").map { it.toInt(16).toByte() }
|
||||
// socket?.outputStream?.write(fromHex.toByteArray())
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setANCMode(mode: Int) {
|
||||
// when (mode) {
|
||||
// 1 -> {
|
||||
// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_OFF.value)
|
||||
// }
|
||||
// 2 -> {
|
||||
// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ON.value)
|
||||
// }
|
||||
// 3 -> {
|
||||
// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_TRANSPARENCY.value)
|
||||
// }
|
||||
// 4 -> {
|
||||
// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ADAPTIVE.value)
|
||||
// }
|
||||
// }
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setCAEnabled(enabled: Boolean) {
|
||||
// socket?.outputStream?.write(if (enabled) Enums.SET_CONVERSATION_AWARENESS_ON.value else Enums.SET_CONVERSATION_AWARENESS_OFF.value)
|
||||
// }
|
||||
//
|
||||
// fun setOffListeningMode(enabled: Boolean) {
|
||||
// socket?.outputStream?.write(byteArrayOf(0x04, 0x00 ,0x04, 0x00, 0x09, 0x00, 0x34, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00))
|
||||
// }
|
||||
//
|
||||
// fun setAdaptiveStrength(strength: Int) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x2E, strength.toByte(), 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setPressSpeed(speed: Int) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x17, speed.toByte(), 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setPressAndHoldDuration(speed: Int) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x18, speed.toByte(), 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setNoiseCancellationWithOnePod(enabled: Boolean) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1B, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setVolumeControl(enabled: Boolean) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x25, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setVolumeSwipeSpeed(speed: Int) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x23, speed.toByte(), 0x00, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setToneVolume(volume: Int) {
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1F, volume.toByte(), 0x50, 0x00, 0x00)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// val earDetectionNotification = AirPodsNotifications.EarDetection()
|
||||
// val ancNotification = AirPodsNotifications.ANC()
|
||||
// val batteryNotification = AirPodsNotifications.BatteryNotification()
|
||||
// val conversationAwarenessNotification = AirPodsNotifications.ConversationalAwarenessNotification()
|
||||
//
|
||||
// var earDetectionEnabled = true
|
||||
//
|
||||
// fun setCaseChargingSounds(enabled: Boolean) {
|
||||
// val bytes = byteArrayOf(0x12, 0x3a, 0x00, 0x01, 0x00, 0x08, if (enabled) 0x00 else 0x01)
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// }
|
||||
//
|
||||
// fun setEarDetection(enabled: Boolean) {
|
||||
// earDetectionEnabled = enabled
|
||||
// }
|
||||
//
|
||||
// fun getBattery(): List<Battery> {
|
||||
// return batteryNotification.getBattery()
|
||||
// }
|
||||
//
|
||||
// fun getANC(): Int {
|
||||
// return ancNotification.status
|
||||
// }
|
||||
//
|
||||
// private fun createNotification(): Notification {
|
||||
// val channelId = "battery"
|
||||
// val notificationBuilder = NotificationCompat.Builder(this, channelId)
|
||||
// .setSmallIcon(R.drawable.pro_2_buds)
|
||||
// .setContentTitle("AirPods Connected")
|
||||
// .setOngoing(true)
|
||||
// .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
//
|
||||
// val channel =
|
||||
// NotificationChannel(channelId, "Battery Notification", NotificationManager.IMPORTANCE_LOW)
|
||||
//
|
||||
// val notificationManager = getSystemService(NotificationManager::class.java)
|
||||
// notificationManager.createNotificationChannel(channel)
|
||||
// return notificationBuilder.build()
|
||||
// }
|
||||
//
|
||||
// fun disconnectAudio(context: Context, device: BluetoothDevice?) {
|
||||
// val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
|
||||
//
|
||||
// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
|
||||
// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
|
||||
// if (profile == BluetoothProfile.A2DP) {
|
||||
// try {
|
||||
// val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
|
||||
// method.invoke(proxy, device)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// } finally {
|
||||
// bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(profile: Int) { }
|
||||
// }, BluetoothProfile.A2DP)
|
||||
//
|
||||
// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
|
||||
// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
|
||||
// if (profile == BluetoothProfile.HEADSET) {
|
||||
// try {
|
||||
// val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
|
||||
// method.invoke(proxy, device)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// } finally {
|
||||
// bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(profile: Int) { }
|
||||
// }, BluetoothProfile.HEADSET)
|
||||
// }
|
||||
//
|
||||
// fun connectAudio(context: Context, device: BluetoothDevice?) {
|
||||
// val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
|
||||
//
|
||||
// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
|
||||
// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
|
||||
// if (profile == BluetoothProfile.A2DP) {
|
||||
// try {
|
||||
// val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
|
||||
// method.invoke(proxy, device)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// } finally {
|
||||
// bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(profile: Int) { }
|
||||
// }, BluetoothProfile.A2DP)
|
||||
//
|
||||
// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
|
||||
// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
|
||||
// if (profile == BluetoothProfile.HEADSET) {
|
||||
// try {
|
||||
// val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
|
||||
// method.invoke(proxy, device)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// } finally {
|
||||
// bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(profile: Int) { }
|
||||
// }, BluetoothProfile.HEADSET)
|
||||
// }
|
||||
//
|
||||
// fun setName(name: String) {
|
||||
// val nameBytes = name.toByteArray()
|
||||
// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x01,
|
||||
// nameBytes.size.toByte(), 0x00) + nameBytes
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// socket?.outputStream?.flush()
|
||||
// val hex = bytes.joinToString(" ") { "%02X".format(it) }
|
||||
// Log.d("OldAirPodsService", "setName: $name, sent packet: $hex")
|
||||
// }
|
||||
//
|
||||
// @SuppressLint("MissingPermission", "InlinedApi")
|
||||
// override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
//
|
||||
// val notification = createNotification()
|
||||
// startForeground(1, notification)
|
||||
//
|
||||
// ServiceManager.setService(this)
|
||||
//
|
||||
// if (isConnected) {
|
||||
// return START_STICKY
|
||||
// }
|
||||
// isConnected = true
|
||||
//
|
||||
// @Suppress("DEPRECATION") val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) intent?.getParcelableExtra("device", BluetoothDevice::class.java) else intent?.getParcelableExtra("device")
|
||||
//
|
||||
// HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
|
||||
// val uuid: ParcelUuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
|
||||
//
|
||||
// socket = HiddenApiBypass.newInstance(BluetoothSocket::class.java, 3, true, true, device, 0x1001, uuid) as BluetoothSocket?
|
||||
// try {
|
||||
// socket?.connect()
|
||||
// socket?.let { it ->
|
||||
// it.outputStream.write(Enums.HANDSHAKE.value)
|
||||
// it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
|
||||
// it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED))
|
||||
// it.outputStream.flush()
|
||||
//
|
||||
// CoroutineScope(Dispatchers.IO).launch {
|
||||
// while (socket?.isConnected == true) {
|
||||
// socket?.let {
|
||||
// val audioManager = this@OldAirPodsService.getSystemService(AUDIO_SERVICE) as AudioManager
|
||||
// MediaController.initialize(audioManager)
|
||||
// val buffer = ByteArray(1024)
|
||||
// val bytesRead = it.inputStream.read(buffer)
|
||||
// var data: ByteArray = byteArrayOf()
|
||||
// if (bytesRead > 0) {
|
||||
// data = buffer.copyOfRange(0, bytesRead)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DATA).apply {
|
||||
// putExtra("data", buffer.copyOfRange(0, bytesRead))
|
||||
// })
|
||||
// val bytes = buffer.copyOfRange(0, bytesRead)
|
||||
// val formattedHex = bytes.joinToString(" ") { "%02X".format(it) }
|
||||
// Log.d("AirPods Data", "Data received: $formattedHex")
|
||||
// }
|
||||
// else if (bytesRead == -1) {
|
||||
// Log.d("AirPods Service", "Socket closed (bytesRead = -1)")
|
||||
// this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
// socket?.close()
|
||||
// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
|
||||
// return@launch
|
||||
// }
|
||||
// var inEar = false
|
||||
// var inEarData = listOf<Boolean>()
|
||||
// if (earDetectionNotification.isEarDetectionData(data)) {
|
||||
// earDetectionNotification.setStatus(data)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.EAR_DETECTION_DATA).apply {
|
||||
// val list = earDetectionNotification.status
|
||||
// val bytes = ByteArray(2)
|
||||
// bytes[0] = list[0]
|
||||
// bytes[1] = list[1]
|
||||
// putExtra("data", bytes)
|
||||
// })
|
||||
// Log.d("AirPods Parser", "Ear Detection: ${earDetectionNotification.status[0]} ${earDetectionNotification.status[1]}")
|
||||
// var justEnabledA2dp = false
|
||||
// val earReceiver = object : BroadcastReceiver() {
|
||||
// override fun onReceive(context: Context, intent: Intent) {
|
||||
// val data = intent.getByteArrayExtra("data")
|
||||
// if (data != null && earDetectionEnabled) {
|
||||
// inEar = if (data.find { it == 0x02.toByte() } != null || data.find { it == 0x03.toByte() } != null) {
|
||||
// data[0] == 0x00.toByte() || data[1] == 0x00.toByte()
|
||||
// } else {
|
||||
// data[0] == 0x00.toByte() && data[1] == 0x00.toByte()
|
||||
// }
|
||||
//
|
||||
// val newInEarData = listOf(data[0] == 0x00.toByte(), data[1] == 0x00.toByte())
|
||||
// if (newInEarData.contains(true) && inEarData == listOf(false, false)) {
|
||||
// connectAudio(this@OldAirPodsService, device)
|
||||
// justEnabledA2dp = true
|
||||
// val bluetoothAdapter = this@OldAirPodsService.getSystemService(BluetoothManager::class.java).adapter
|
||||
// bluetoothAdapter.getProfileProxy(
|
||||
// this@OldAirPodsService, object : BluetoothProfile.ServiceListener {
|
||||
// override fun onServiceConnected(
|
||||
// profile: Int,
|
||||
// proxy: BluetoothProfile
|
||||
// ) {
|
||||
// if (profile == BluetoothProfile.A2DP) {
|
||||
// val connectedDevices =
|
||||
// proxy.connectedDevices
|
||||
// if (connectedDevices.isNotEmpty()) {
|
||||
// MediaController.sendPlay()
|
||||
// }
|
||||
// }
|
||||
// bluetoothAdapter.closeProfileProxy(
|
||||
// profile,
|
||||
// proxy
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(
|
||||
// profile: Int
|
||||
// ) {
|
||||
// }
|
||||
// }
|
||||
// ,BluetoothProfile.A2DP
|
||||
// )
|
||||
//
|
||||
// }
|
||||
// else if (newInEarData == listOf(false, false)){
|
||||
// disconnectAudio(this@OldAirPodsService, device)
|
||||
// }
|
||||
//
|
||||
// inEarData = newInEarData
|
||||
//
|
||||
// if (inEar == true) {
|
||||
// if (!justEnabledA2dp) {
|
||||
// justEnabledA2dp = false
|
||||
// MediaController.sendPlay()
|
||||
// }
|
||||
// } else {
|
||||
// MediaController.sendPause()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// val earIntentFilter = IntentFilter(AirPodsNotifications.EAR_DETECTION_DATA)
|
||||
// this@OldAirPodsService.registerReceiver(earReceiver, earIntentFilter,
|
||||
// RECEIVER_EXPORTED
|
||||
// )
|
||||
// }
|
||||
// else if (ancNotification.isANCData(data)) {
|
||||
// ancNotification.setStatus(data)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.ANC_DATA).apply {
|
||||
// putExtra("data", ancNotification.status)
|
||||
// })
|
||||
// Log.d("AirPods Parser", "ANC: ${ancNotification.status}")
|
||||
// }
|
||||
// else if (batteryNotification.isBatteryData(data)) {
|
||||
// batteryNotification.setBattery(data)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.BATTERY_DATA).apply {
|
||||
// putParcelableArrayListExtra("data", ArrayList(batteryNotification.getBattery()))
|
||||
// })
|
||||
// for (battery in batteryNotification.getBattery()) {
|
||||
// Log.d("AirPods Parser", "${battery.getComponentName()}: ${battery.getStatusName()} at ${battery.level}% ")
|
||||
// }
|
||||
//// if both are charging, disconnect audio profiles
|
||||
// if (batteryNotification.getBattery()[0].status == 1 && batteryNotification.getBattery()[1].status == 1) {
|
||||
// disconnectAudio(this@OldAirPodsService, device)
|
||||
// }
|
||||
// else {
|
||||
// connectAudio(this@OldAirPodsService, device)
|
||||
// }
|
||||
//// updatePodsStatus(device!!, batteryNotification.getBattery())
|
||||
// }
|
||||
// else if (conversationAwarenessNotification.isConversationalAwarenessData(data)) {
|
||||
// conversationAwarenessNotification.setData(data)
|
||||
// sendBroadcast(Intent(AirPodsNotifications.CA_DATA).apply {
|
||||
// putExtra("data", conversationAwarenessNotification.status)
|
||||
// })
|
||||
//
|
||||
//
|
||||
// if (conversationAwarenessNotification.status == 1.toByte() || conversationAwarenessNotification.status == 2.toByte()) {
|
||||
// MediaController.startSpeaking()
|
||||
// } else if (conversationAwarenessNotification.status == 8.toByte() || conversationAwarenessNotification.status == 9.toByte()) {
|
||||
// MediaController.stopSpeaking()
|
||||
// }
|
||||
//
|
||||
// Log.d("AirPods Parser", "Conversation Awareness: ${conversationAwarenessNotification.status}")
|
||||
// }
|
||||
// else { }
|
||||
// }
|
||||
// }
|
||||
// Log.d("AirPods Service", "Socket closed")
|
||||
// isConnected = false
|
||||
// this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
// socket?.close()
|
||||
// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (e: Exception) {
|
||||
// Log.e("AirPodsSettingsScreen", "Error connecting to device: ${e.message}")
|
||||
// }
|
||||
// return START_STICKY
|
||||
// }
|
||||
//
|
||||
// override fun onDestroy() {
|
||||
// super.onDestroy()
|
||||
// socket?.close()
|
||||
// isConnected = false
|
||||
// ServiceManager.setService(null)
|
||||
// }
|
||||
//
|
||||
// fun setPVEnabled(enabled: Boolean) {
|
||||
// var hex = "04 00 04 00 09 00 26 ${if (enabled) "01" else "02"} 00 00 00"
|
||||
// var bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// hex = "04 00 04 00 17 00 00 00 10 00 12 00 08 E${if (enabled) "6" else "5"} 05 10 02 42 0B 08 50 10 02 1A 05 02 ${if (enabled) "32" else "00"} 00 00 00"
|
||||
// bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// }
|
||||
//
|
||||
// fun setLoudSoundReduction(enabled: Boolean) {
|
||||
// val hex = "52 1B 00 0${if (enabled) "1" else "0"}"
|
||||
// val bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
|
||||
// socket?.outputStream?.write(bytes)
|
||||
// }
|
||||
//}
|
||||
@@ -18,7 +18,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun AccessibilitySettings(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -32,7 +32,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
@@ -18,7 +18,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun AudioSettings(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -24,11 +24,11 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.imageResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.kavishdevar.aln.AirPodsNotifications
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.Battery
|
||||
import me.kavishdevar.aln.BatteryComponent
|
||||
import me.kavishdevar.aln.BatteryStatus
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.utils.Battery
|
||||
import me.kavishdevar.aln.utils.BatteryComponent
|
||||
import me.kavishdevar.aln.utils.BatteryStatus
|
||||
import me.kavishdevar.aln.R
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -27,7 +27,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun ConversationalAwarenessSwitch(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -24,7 +24,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun IndependentToggle(name: String, service: AirPodsService, functionName: String, sharedPreferences: SharedPreferences, default: Boolean = false) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun LoudSoundReductionSwitch(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package me.kavishdevar.aln.composables
|
||||
|
||||
import me.kavishdevar.aln.R
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
@@ -20,6 +19,7 @@ import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.res.imageResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.kavishdevar.aln.R
|
||||
|
||||
@Composable
|
||||
fun NoiseControlButton(
|
||||
|
||||
@@ -34,9 +34,9 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsNotifications
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.NoiseControlMode
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.utils.NoiseControlMode
|
||||
import me.kavishdevar.aln.R
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
|
||||
@@ -27,7 +27,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun PersonalizedVolumeSwitch(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun SinglePodANCSwitch(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -32,7 +32,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
@Composable
|
||||
fun VolumeControlSwitch(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package me.kavishdevar.aln.receivers
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
|
||||
class BootReceiver: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
|
||||
@@ -14,8 +14,13 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
@@ -33,6 +38,8 @@ import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -46,8 +53,7 @@ import dev.chrisbanes.haze.haze
|
||||
import dev.chrisbanes.haze.hazeChild
|
||||
import dev.chrisbanes.haze.materials.CupertinoMaterials
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
import me.kavishdevar.aln.AirPodsNotifications
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.R
|
||||
import me.kavishdevar.aln.composables.AccessibilitySettings
|
||||
import me.kavishdevar.aln.composables.AudioSettings
|
||||
import me.kavishdevar.aln.composables.BatteryView
|
||||
@@ -56,7 +62,10 @@ import me.kavishdevar.aln.composables.NavigationButton
|
||||
import me.kavishdevar.aln.composables.NoiseControlSettings
|
||||
import me.kavishdevar.aln.composables.PressAndHoldSettings
|
||||
import me.kavishdevar.aln.composables.StyledTextField
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.services.ServiceManager
|
||||
import me.kavishdevar.aln.ui.theme.ALNTheme
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
@@ -88,7 +97,13 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = deviceName.text
|
||||
text = deviceName.text,
|
||||
style = TextStyle(
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = if (darkMode) Color.White else Color.Black,
|
||||
fontFamily = FontFamily(Font(R.font.sf_pro))
|
||||
)
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
@@ -116,23 +131,23 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
|
||||
containerColor = Color.Transparent
|
||||
),
|
||||
// actions = {
|
||||
// val context = LocalContext.current
|
||||
// IconButton(
|
||||
// onClick = {
|
||||
// ServiceManager.restartService(context)
|
||||
// },
|
||||
// colors = IconButtonDefaults.iconButtonColors(
|
||||
// containerColor = Color.Transparent,
|
||||
// contentColor = if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||
// )
|
||||
// ) {
|
||||
// Icon(
|
||||
// imageVector = Icons.Default.Refresh,
|
||||
// contentDescription = "Settings",
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
actions = {
|
||||
val context = LocalContext.current
|
||||
IconButton(
|
||||
onClick = {
|
||||
ServiceManager.restartService(context)
|
||||
},
|
||||
colors = IconButtonDefaults.iconButtonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Refresh,
|
||||
contentDescription = "Settings",
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
@@ -228,7 +243,8 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
style = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||
color = if (isSystemInDarkTheme()) Color.White else Color.Black,
|
||||
fontFamily = FontFamily(Font(R.font.sf_pro))
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
@@ -239,7 +255,8 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
style = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Light,
|
||||
color = if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||
color = if (isSystemInDarkTheme()) Color.White else Color.Black,
|
||||
fontFamily = FontFamily(Font(R.font.sf_pro))
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
@@ -253,9 +270,13 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
@Preview
|
||||
@Composable
|
||||
fun AirPodsSettingsScreenPreview() {
|
||||
ALNTheme (
|
||||
darkTheme = true
|
||||
Column (
|
||||
modifier = Modifier.height(2000.dp)
|
||||
) {
|
||||
AirPodsSettingsScreen(dev = null, service = AirPodsService(), navController = rememberNavController(), isConnected = true)
|
||||
ALNTheme (
|
||||
darkTheme = true
|
||||
) {
|
||||
AirPodsSettingsScreen(dev = null, service = AirPodsService(), navController = rememberNavController(), isConnected = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,8 +61,8 @@ import dev.chrisbanes.haze.haze
|
||||
import dev.chrisbanes.haze.hazeChild
|
||||
import dev.chrisbanes.haze.materials.CupertinoMaterials
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
import me.kavishdevar.aln.AirPodsNotifications
|
||||
import me.kavishdevar.aln.AirPodsService
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
|
||||
@@ -45,7 +45,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import me.kavishdevar.aln.R
|
||||
import me.kavishdevar.aln.ServiceManager
|
||||
import me.kavishdevar.aln.services.ServiceManager
|
||||
|
||||
@Composable()
|
||||
fun RightDivider() {
|
||||
|
||||
@@ -8,9 +8,8 @@ import android.content.IntentFilter
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
import me.kavishdevar.aln.AirPodsNotifications
|
||||
import me.kavishdevar.aln.NoiseControlMode
|
||||
import me.kavishdevar.aln.ServiceManager
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.utils.NoiseControlMode
|
||||
|
||||
class AirPodsQSService: TileService() {
|
||||
private val ancModes = listOf(NoiseControlMode.NOISE_CANCELLATION.name, NoiseControlMode.TRANSPARENCY.name, NoiseControlMode.ADAPTIVE.name)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.kavishdevar.aln
|
||||
package me.kavishdevar.aln.services
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
@@ -25,6 +25,14 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.utils.Battery
|
||||
import me.kavishdevar.aln.utils.BatteryComponent
|
||||
import me.kavishdevar.aln.utils.BatteryStatus
|
||||
import me.kavishdevar.aln.utils.Enums
|
||||
import me.kavishdevar.aln.utils.LongPressPackets
|
||||
import me.kavishdevar.aln.R
|
||||
import me.kavishdevar.aln.utils.Window
|
||||
import me.kavishdevar.aln.utils.MediaController
|
||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||
|
||||
@@ -38,11 +46,11 @@ object ServiceManager {
|
||||
fun setService(service: AirPodsService?) {
|
||||
this.service = service
|
||||
}
|
||||
// @Synchronized
|
||||
// fun restartService(context: Context) {
|
||||
// service?.stopSelf()
|
||||
// context.startService(Intent(context, AirPodsService::class.java))
|
||||
// }
|
||||
@Synchronized
|
||||
fun restartService(context: Context) {
|
||||
service?.stopSelf()
|
||||
context.startService(Intent(context, AirPodsService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -84,7 +92,7 @@ class AirPodsService: Service() {
|
||||
}
|
||||
val uuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
|
||||
if (bluetoothDevice.uuids.contains(uuid)) {
|
||||
val intent = Intent(AirPodsNotifications.AIRPODS_CONNECTION_DETECTED)
|
||||
val intent = Intent(AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED)
|
||||
intent.putExtra("name", name)
|
||||
intent.putExtra("device", bluetoothDevice)
|
||||
context?.sendBroadcast(intent)
|
||||
@@ -94,7 +102,7 @@ class AirPodsService: Service() {
|
||||
|| BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED == action
|
||||
) {
|
||||
context?.sendBroadcast(
|
||||
Intent(AirPodsNotifications.AIRPODS_DISCONNECTED)
|
||||
Intent(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -195,7 +203,6 @@ class AirPodsService: Service() {
|
||||
.build()
|
||||
}
|
||||
|
||||
// Notify the NotificationManager with the same ID
|
||||
notificationManager.notify(1, updatedNotification)
|
||||
}
|
||||
|
||||
@@ -219,11 +226,12 @@ class AirPodsService: Service() {
|
||||
addAction("android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED")
|
||||
addAction("android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED")
|
||||
}
|
||||
|
||||
registerReceiver(bluetoothReceiver, serviceIntentFilter, RECEIVER_EXPORTED)
|
||||
|
||||
connectionReceiver = object: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == AirPodsNotifications.AIRPODS_CONNECTION_DETECTED) {
|
||||
if (intent?.action == AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED) {
|
||||
val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
|
||||
.getString("name", device?.name)
|
||||
Log.d("AirPodsService", "$name connected")
|
||||
@@ -232,7 +240,7 @@ class AirPodsService: Service() {
|
||||
connectToSocket(device!!)
|
||||
updateNotificationContent(true, name.toString(), batteryNotification.getBattery())
|
||||
}
|
||||
else if (intent?.action == AirPodsNotifications.AIRPODS_DISCONNECTED) {
|
||||
else if (intent?.action == AirPodsNotifications.Companion.AIRPODS_DISCONNECTED) {
|
||||
device = null
|
||||
isConnected = false
|
||||
popupShown = false
|
||||
@@ -242,8 +250,8 @@ class AirPodsService: Service() {
|
||||
}
|
||||
|
||||
val deviceIntentFilter = IntentFilter().apply {
|
||||
addAction(AirPodsNotifications.AIRPODS_CONNECTION_DETECTED)
|
||||
addAction(AirPodsNotifications.AIRPODS_DISCONNECTED)
|
||||
addAction(AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED)
|
||||
addAction(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED)
|
||||
}
|
||||
registerReceiver(connectionReceiver, deviceIntentFilter, RECEIVER_EXPORTED)
|
||||
|
||||
@@ -257,7 +265,7 @@ class AirPodsService: Service() {
|
||||
if (connectedDevices.isNotEmpty()) {
|
||||
connectToSocket(device)
|
||||
this@AirPodsService.sendBroadcast(
|
||||
Intent(AirPodsNotifications.AIRPODS_CONNECTED)
|
||||
Intent(AirPodsNotifications.Companion.AIRPODS_CONNECTED)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -348,7 +356,7 @@ class AirPodsService: Service() {
|
||||
it.outputStream.flush()
|
||||
delay(200)
|
||||
sendBroadcast(
|
||||
Intent(AirPodsNotifications.AIRPODS_CONNECTED)
|
||||
Intent(AirPodsNotifications.Companion.AIRPODS_CONNECTED)
|
||||
.putExtra("device", device)
|
||||
)
|
||||
|
||||
@@ -362,7 +370,7 @@ class AirPodsService: Service() {
|
||||
var data: ByteArray = byteArrayOf()
|
||||
if (bytesRead > 0) {
|
||||
data = buffer.copyOfRange(0, bytesRead)
|
||||
sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DATA).apply {
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.AIRPODS_DATA).apply {
|
||||
putExtra("data", buffer.copyOfRange(0, bytesRead))
|
||||
})
|
||||
val bytes = buffer.copyOfRange(0, bytesRead)
|
||||
@@ -371,14 +379,14 @@ class AirPodsService: Service() {
|
||||
} else if (bytesRead == -1) {
|
||||
Log.d("AirPods Service", "Socket closed (bytesRead = -1)")
|
||||
// socket.close()
|
||||
sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED))
|
||||
return@launch
|
||||
}
|
||||
var inEar = false
|
||||
var inEarData = listOf<Boolean>()
|
||||
if (earDetectionNotification.isEarDetectionData(data)) {
|
||||
earDetectionNotification.setStatus(data)
|
||||
sendBroadcast(Intent(AirPodsNotifications.EAR_DETECTION_DATA).apply {
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.EAR_DETECTION_DATA).apply {
|
||||
val list = earDetectionNotification.status
|
||||
val bytes = ByteArray(2)
|
||||
bytes[0] = list[0]
|
||||
@@ -463,7 +471,7 @@ class AirPodsService: Service() {
|
||||
}
|
||||
|
||||
val earIntentFilter =
|
||||
IntentFilter(AirPodsNotifications.EAR_DETECTION_DATA)
|
||||
IntentFilter(AirPodsNotifications.Companion.EAR_DETECTION_DATA)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
this@AirPodsService.registerReceiver(
|
||||
earReceiver, earIntentFilter,
|
||||
@@ -477,13 +485,13 @@ class AirPodsService: Service() {
|
||||
}
|
||||
} else if (ancNotification.isANCData(data)) {
|
||||
ancNotification.setStatus(data)
|
||||
sendBroadcast(Intent(AirPodsNotifications.ANC_DATA).apply {
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.ANC_DATA).apply {
|
||||
putExtra("data", ancNotification.status)
|
||||
})
|
||||
Log.d("AirPods Parser", "ANC: ${ancNotification.status}")
|
||||
} else if (batteryNotification.isBatteryData(data)) {
|
||||
batteryNotification.setBattery(data)
|
||||
sendBroadcast(Intent(AirPodsNotifications.BATTERY_DATA).apply {
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.BATTERY_DATA).apply {
|
||||
putParcelableArrayListExtra(
|
||||
"data",
|
||||
ArrayList(batteryNotification.getBattery())
|
||||
@@ -513,7 +521,7 @@ class AirPodsService: Service() {
|
||||
)
|
||||
) {
|
||||
conversationAwarenessNotification.setData(data)
|
||||
sendBroadcast(Intent(AirPodsNotifications.CA_DATA).apply {
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.CA_DATA).apply {
|
||||
putExtra("data", conversationAwarenessNotification.status)
|
||||
})
|
||||
|
||||
@@ -535,7 +543,7 @@ class AirPodsService: Service() {
|
||||
Log.d("AirPods Service", "Socket closed")
|
||||
isConnected = false
|
||||
socket.close()
|
||||
sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
|
||||
sendBroadcast(Intent(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -1,6 +1,6 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package me.kavishdevar.aln
|
||||
package me.kavishdevar.aln.utils
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.kavishdevar.aln
|
||||
package me.kavishdevar.aln.utils
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
@@ -22,7 +22,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Exception
|
||||
import me.kavishdevar.aln.R
|
||||
|
||||
@SuppressLint("InflateParams", "ClickableViewAccessibility")
|
||||
class Window (context: Context) {
|
||||
@@ -4,7 +4,6 @@ appWidgetInnerRadius attribute value
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners android:radius="?attr/appWidgetInnerRadius" />
|
||||
<solid android:color="?android:attr/colorAccent" />
|
||||
</shape>
|
||||
72
android/app/src/main/res/layout-v31/battery_widget.xml
Normal file
72
android/app/src/main/res/layout-v31/battery_widget.xml
Normal file
@@ -0,0 +1,72 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/Widget.ALN.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/Theme.ALN.AppWidgetContainer">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="0dp"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:contentDescription="something"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:src="@drawable/airpods_pro_left_notification"
|
||||
android:tint="@android:color/system_accent2_400"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/left_battery_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@android:color/system_accent2_400"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Left"
|
||||
tools:ignore="HardcodedText" />
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/airpods_pro_right_notification"
|
||||
android:tint="@android:color/system_accent2_400"
|
||||
android:layout_margin="0dp"
|
||||
android:contentDescription="something"
|
||||
android:gravity="center_vertical"
|
||||
tools:ignore="HardcodedText" />
|
||||
<TextView
|
||||
android:id="@+id/right_battery_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@android:color/system_accent2_400"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Right"
|
||||
tools:ignore="HardcodedText" />
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/airpods_pro_case_notification"
|
||||
android:tint="@android:color/system_accent2_400"
|
||||
android:contentDescription="something"
|
||||
android:layout_margin="0dp"
|
||||
android:gravity="center_vertical"
|
||||
tools:ignore="HardcodedText" />
|
||||
<TextView
|
||||
android:id="@+id/case_battery_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@android:color/system_accent2_400"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Case"
|
||||
tools:ignore="HardcodedText" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@@ -1,19 +1,74 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/Widget.ALN.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/Theme.ALN.AppWidgetContainer">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="0dp"
|
||||
android:gravity="center">
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:contentDescription="something"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:src="@drawable/airpods_pro_left_notification"
|
||||
android:tint="@color/popup_text"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/appwidget_text"
|
||||
style="@style/Widget.ALN.AppWidget.InnerView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_margin="8dp"
|
||||
android:contentDescription="@string/appwidget_text"
|
||||
android:text="@string/appwidget_text"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold|italic" />
|
||||
<TextView
|
||||
android:id="@+id/left_battery_widget"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/popup_text"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Left"
|
||||
tools:ignore="HardcodedText" />
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/airpods_pro_right_notification"
|
||||
android:tint="@color/popup_text"
|
||||
android:layout_margin="0dp"
|
||||
android:contentDescription="something"
|
||||
android:gravity="center_vertical"
|
||||
tools:ignore="HardcodedText" />
|
||||
<TextView
|
||||
android:id="@+id/right_battery_widget"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/popup_text"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Right"
|
||||
tools:ignore="HardcodedText" />
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/airpods_pro_case_notification"
|
||||
android:tint="@color/popup_text"
|
||||
android:contentDescription="something"
|
||||
android:layout_margin="0dp"
|
||||
android:gravity="center_vertical"
|
||||
tools:ignore="HardcodedText" />
|
||||
<TextView
|
||||
android:id="@+id/case_battery_widget"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/popup_text"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Case"
|
||||
tools:ignore="HardcodedText" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@@ -2,4 +2,6 @@
|
||||
<resources>
|
||||
<color name="popup_background">#1C1B1E</color>
|
||||
<color name="popup_text">@color/white</color>
|
||||
<color name="widget_background">#1C1B1E</color>
|
||||
<color name="widget_text">@color/white</color>
|
||||
</resources>
|
||||
@@ -4,8 +4,6 @@
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="popup_background">#FFFFFF</color>
|
||||
<color name="popup_text">@color/black</color>
|
||||
<color name="light_blue_50">#FFE1F5FE</color>
|
||||
<color name="light_blue_200">#FF81D4FA</color>
|
||||
<color name="light_blue_600">#FF039BE5</color>
|
||||
<color name="light_blue_900">#FF01579B</color>
|
||||
<color name="widget_background">#87FFFFFF</color>
|
||||
<color name="widget_text">@color/black</color>
|
||||
</resources>
|
||||
@@ -1,7 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">ALN</string>
|
||||
<string name="title_activity_custom_device">GATT Testing</string>
|
||||
<string name="appwidget_text">EXAMPLE</string>
|
||||
<string name="add_widget">Add widget</string>
|
||||
<string name="app_widget_description">This is an app widget description</string>
|
||||
<string name="app_widget_description">See your AirPods battery status right from your home screen!</string>
|
||||
</resources>
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<style name="Theme.ALN.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
|
||||
<!-- Radius of the outer bound of widgets to make the rounded corners -->
|
||||
<item name="appWidgetRadius">16dp</item>
|
||||
<item name="appWidgetRadius">24dp</item>
|
||||
<!--
|
||||
Radius of the inner view's bound of widgets to make the rounded corners.
|
||||
It needs to be 8dp or less than the value of appWidgetRadius
|
||||
-->
|
||||
<item name="appWidgetInnerRadius">8dp</item>
|
||||
<item name="appWidgetInnerRadius">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.ALN.AppWidgetContainer" parent="Theme.ALN.AppWidgetContainerParent">
|
||||
|
||||
14
android/app/src/main/res/xml-v31/battery_widget_info.xml
Normal file
14
android/app/src/main/res/xml-v31/battery_widget_info.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:description="@string/app_widget_description"
|
||||
android:initialKeyguardLayout="@layout/battery_widget"
|
||||
android:initialLayout="@layout/battery_widget"
|
||||
android:minWidth="40dp"
|
||||
android:minHeight="40dp"
|
||||
android:previewImage="@drawable/example_appwidget_preview"
|
||||
android:previewLayout="@layout/battery_widget"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:targetCellWidth="1"
|
||||
android:targetCellHeight="1"
|
||||
android:updatePeriodMillis="86400000"
|
||||
android:widgetCategory="home_screen|keyguard" />
|
||||
Reference in New Issue
Block a user