mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-04-10 13:25:24 +00:00
add iOS style battery widget
This commit is contained in:
@@ -11,8 +11,9 @@
|
|||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.BLUETOOTH_PRIVILEGED"
|
android:name="android.permission.BLUETOOTH_PRIVILEGED"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.BATTERY_STATS"
|
||||||
android:name="android.permission.BLUETOOTH_ADMIN"
|
tools:ignore="ProtectedPermissions"/>
|
||||||
|
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
tools:ignore="UnusedAttribute"
|
tools:ignore="UnusedAttribute"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".BatteryWidget"
|
android:name=".widgets.BatteryWidget"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
|||||||
@@ -321,8 +321,8 @@ fun NoiseControlSettings(service: AirPodsService) {
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(4.dp)
|
.padding(3.dp)
|
||||||
.background(selectedBackground, RoundedCornerShape(11.dp))
|
.background(selectedBackground, RoundedCornerShape(12.dp))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import me.kavishdevar.aln.R
|
import me.kavishdevar.aln.R
|
||||||
|
import me.kavishdevar.aln.composables.IndependentToggle
|
||||||
import me.kavishdevar.aln.composables.StyledSwitch
|
import me.kavishdevar.aln.composables.StyledSwitch
|
||||||
|
import me.kavishdevar.aln.services.ServiceManager
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -130,6 +132,8 @@ fun AppSettingsScreen(navController: NavController) {
|
|||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
|
||||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
|
|
||||||
|
IndependentToggle("Show phone battery in widget", ServiceManager.getService()!!, "setPhoneBatteryInWidget", sharedPreferences)
|
||||||
|
|
||||||
Column (
|
Column (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.app.Service
|
|||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.bluetooth.BluetoothDevice
|
import android.bluetooth.BluetoothDevice
|
||||||
|
import android.bluetooth.BluetoothHeadset
|
||||||
import android.bluetooth.BluetoothManager
|
import android.bluetooth.BluetoothManager
|
||||||
import android.bluetooth.BluetoothProfile
|
import android.bluetooth.BluetoothProfile
|
||||||
import android.bluetooth.BluetoothSocket
|
import android.bluetooth.BluetoothSocket
|
||||||
@@ -42,6 +43,7 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
import android.os.BatteryManager
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@@ -49,10 +51,12 @@ import android.os.IBinder
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.ParcelUuid
|
import android.os.ParcelUuid
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import androidx.annotation.RequiresPermission
|
import androidx.annotation.RequiresPermission
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.edit
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
@@ -62,7 +66,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.kavishdevar.aln.BatteryWidget
|
|
||||||
import me.kavishdevar.aln.MainActivity
|
import me.kavishdevar.aln.MainActivity
|
||||||
import me.kavishdevar.aln.R
|
import me.kavishdevar.aln.R
|
||||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||||
@@ -75,6 +78,7 @@ import me.kavishdevar.aln.utils.Enums
|
|||||||
import me.kavishdevar.aln.utils.LongPressPackets
|
import me.kavishdevar.aln.utils.LongPressPackets
|
||||||
import me.kavishdevar.aln.utils.MediaController
|
import me.kavishdevar.aln.utils.MediaController
|
||||||
import me.kavishdevar.aln.utils.Window
|
import me.kavishdevar.aln.utils.Window
|
||||||
|
import me.kavishdevar.aln.widgets.BatteryWidget
|
||||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||||
|
|
||||||
object ServiceManager {
|
object ServiceManager {
|
||||||
@@ -103,7 +107,7 @@ object ServiceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Suppress("unused")
|
// @Suppress("unused")
|
||||||
class AirPodsService: Service() {
|
class AirPodsService: Service() {
|
||||||
private var macAddress = ""
|
private var macAddress = ""
|
||||||
inner class LocalBinder : Binder() {
|
inner class LocalBinder : Binder() {
|
||||||
@@ -115,7 +119,6 @@ class AirPodsService: Service() {
|
|||||||
private val _packetLogsFlow = MutableStateFlow<Set<String>>(emptySet())
|
private val _packetLogsFlow = MutableStateFlow<Set<String>>(emptySet())
|
||||||
val packetLogsFlow: StateFlow<Set<String>> get() = _packetLogsFlow
|
val packetLogsFlow: StateFlow<Set<String>> get() = _packetLogsFlow
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
sharedPreferences = getSharedPreferences("packet_logs", MODE_PRIVATE)
|
sharedPreferences = getSharedPreferences("packet_logs", MODE_PRIVATE)
|
||||||
@@ -127,7 +130,7 @@ class AirPodsService: Service() {
|
|||||||
val logs = sharedPreferences.getStringSet(packetLogKey, mutableSetOf())?.toMutableSet() ?: mutableSetOf()
|
val logs = sharedPreferences.getStringSet(packetLogKey, mutableSetOf())?.toMutableSet() ?: mutableSetOf()
|
||||||
logs.add(logEntry)
|
logs.add(logEntry)
|
||||||
_packetLogsFlow.value = logs
|
_packetLogsFlow.value = logs
|
||||||
sharedPreferences.edit().putStringSet(packetLogKey, logs).apply()
|
sharedPreferences.edit { putStringSet(packetLogKey, logs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPacketLogs(): Set<String> {
|
fun getPacketLogs(): Set<String> {
|
||||||
@@ -135,7 +138,8 @@ class AirPodsService: Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun clearPacketLogs() {
|
private fun clearPacketLogs() {
|
||||||
sharedPreferences.edit().remove(packetLogKey).apply()
|
sharedPreferences.edit { remove(packetLogKey).apply() }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearLogs() {
|
fun clearLogs() {
|
||||||
@@ -198,7 +202,148 @@ class AirPodsService: Service() {
|
|||||||
var device: BluetoothDevice? = null
|
var device: BluetoothDevice? = null
|
||||||
|
|
||||||
private lateinit var earReceiver: BroadcastReceiver
|
private lateinit var earReceiver: BroadcastReceiver
|
||||||
|
var widgetMobileBatteryEnabled = false
|
||||||
|
|
||||||
|
val METADATA_UNTETHERED_LEFT_CHARGING = 13
|
||||||
|
val METADATA_UNTETHERED_LEFT_BATTERY = 10
|
||||||
|
val METADATA_UNTETHERED_RIGHT_CHARGING = 14
|
||||||
|
val METADATA_UNTETHERED_RIGHT_BATTERY = 11
|
||||||
|
val METADATA_UNTETHERED_CASE_CHARGING = 15
|
||||||
|
val METADATA_UNTETHERED_CASE_BATTERY = 12
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
fun setBatteryLevels(
|
||||||
|
leftStatus: Boolean, leftLevel: Int,
|
||||||
|
rightStatus: Boolean, rightLevel: Int,
|
||||||
|
caseStatus: Boolean, caseLevel: Int,
|
||||||
|
device: BluetoothDevice
|
||||||
|
) {
|
||||||
|
HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothDevice;")
|
||||||
|
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_LEFT_CHARGING,
|
||||||
|
leftStatus.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_LEFT_BATTERY,
|
||||||
|
leftLevel.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_RIGHT_CHARGING,
|
||||||
|
rightStatus.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_RIGHT_BATTERY,
|
||||||
|
rightLevel.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_CASE_CHARGING,
|
||||||
|
caseStatus.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"setMetadata",
|
||||||
|
METADATA_UNTETHERED_CASE_BATTERY,
|
||||||
|
caseLevel.toString().toByteArray()
|
||||||
|
)
|
||||||
|
HiddenApiBypass.invoke(
|
||||||
|
BluetoothDevice::class.java,
|
||||||
|
device,
|
||||||
|
"sendVendorSpecificHeadsetEvent",
|
||||||
|
"+IPHONEACCEV",
|
||||||
|
BluetoothHeadset.AT_CMD_TYPE_SET,
|
||||||
|
1,
|
||||||
|
leftLevel,
|
||||||
|
2,
|
||||||
|
rightLevel,
|
||||||
|
3,
|
||||||
|
caseLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prepare the intent to broadcast vendor-specific headset event
|
||||||
|
val intent = Intent(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT).apply {
|
||||||
|
putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD, "+IPHONEACCEV")
|
||||||
|
putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, BluetoothHeadset.AT_CMD_TYPE_SET)
|
||||||
|
putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS, arrayOf(
|
||||||
|
1, leftLevel,
|
||||||
|
2, rightLevel,
|
||||||
|
3, caseLevel
|
||||||
|
))
|
||||||
|
putExtra(BluetoothDevice.EXTRA_DEVICE, device)
|
||||||
|
putExtra(BluetoothDevice.EXTRA_NAME, device.name)
|
||||||
|
addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." + 76)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the broadcast to update the battery levels
|
||||||
|
sendBroadcast(intent)
|
||||||
|
|
||||||
|
// Broadcast battery level changes
|
||||||
|
val batteryIntent = Intent("android.bluet9ooth.device.action.BATTERY_LEVEL_CHANGED").apply {
|
||||||
|
putExtra(BluetoothDevice.EXTRA_DEVICE, device)
|
||||||
|
putExtra("android.bluetooth.device.extra.BATTERY_LEVEL", leftLevel) // Update with appropriate levels
|
||||||
|
}
|
||||||
|
sendBroadcast(batteryIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
object PhoneBatteryReceiver: BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
|
if (intent.action == Intent.ACTION_BATTERY_CHANGED) {
|
||||||
|
ServiceManager.getService()?.updateBatteryWidget()
|
||||||
|
}
|
||||||
|
else if (intent.action == AirPodsNotifications.DISCONNECT_RECEIVERS) {
|
||||||
|
try {
|
||||||
|
context?.unregisterReceiver(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val phoneBatteryIntentFilter = IntentFilter().apply {
|
||||||
|
addAction(Intent.ACTION_BATTERY_CHANGED)
|
||||||
|
addAction(AirPodsNotifications.DISCONNECT_RECEIVERS)
|
||||||
|
}
|
||||||
|
fun setPhoneBatteryInWidget(enabled: Boolean) {
|
||||||
|
widgetMobileBatteryEnabled = enabled
|
||||||
|
if (enabled) {
|
||||||
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
registerReceiver(
|
||||||
|
PhoneBatteryReceiver,
|
||||||
|
phoneBatteryIntentFilter,
|
||||||
|
RECEIVER_EXPORTED
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
registerReceiver(PhoneBatteryReceiver, phoneBatteryIntentFilter)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
unregisterReceiver(PhoneBatteryReceiver)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateBatteryWidget()
|
||||||
|
}
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
fun scanForAirPods(bluetoothAdapter: BluetoothAdapter): Flow<List<ScanResult>> = callbackFlow {
|
fun scanForAirPods(bluetoothAdapter: BluetoothAdapter): Flow<List<ScanResult>> = callbackFlow {
|
||||||
val bluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner
|
val bluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner
|
||||||
@@ -295,44 +440,85 @@ class AirPodsService: Service() {
|
|||||||
val widgetIds = appWidgetManager.getAppWidgetIds(componentName)
|
val widgetIds = appWidgetManager.getAppWidgetIds(componentName)
|
||||||
|
|
||||||
val remoteViews = RemoteViews(packageName, R.layout.battery_widget).also {
|
val remoteViews = RemoteViews(packageName, R.layout.battery_widget).also {
|
||||||
|
val leftBattery = batteryNotification.getBattery().find { it.component == BatteryComponent.LEFT }
|
||||||
|
val rightBattery = batteryNotification.getBattery().find { it.component == BatteryComponent.RIGHT }
|
||||||
|
val caseBattery = batteryNotification.getBattery().find { it.component == BatteryComponent.CASE }
|
||||||
|
|
||||||
it.setTextViewText(
|
it.setTextViewText(
|
||||||
R.id.left_battery_widget,
|
R.id.left_battery_widget,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.LEFT }?.let {
|
leftBattery?.let {
|
||||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
"${it.level}%"
|
||||||
} ?: ""
|
} ?: ""
|
||||||
)
|
)
|
||||||
it.setProgressBar(
|
it.setProgressBar(
|
||||||
R.id.left_battery_progress,
|
R.id.left_battery_progress,
|
||||||
100,
|
100,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.LEFT }?.level ?: 0,
|
leftBattery?.level ?: 0,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
it.setViewVisibility(
|
||||||
|
R.id.left_charging_icon,
|
||||||
|
if (leftBattery?.status == BatteryStatus.CHARGING) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
|
||||||
it.setTextViewText(
|
it.setTextViewText(
|
||||||
R.id.right_battery_widget,
|
R.id.right_battery_widget,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.RIGHT }?.let {
|
rightBattery?.let {
|
||||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
"${it.level}%"
|
||||||
} ?: ""
|
} ?: ""
|
||||||
)
|
)
|
||||||
it.setProgressBar(
|
it.setProgressBar(
|
||||||
R.id.right_battery_progress,
|
R.id.right_battery_progress,
|
||||||
100,
|
100,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.RIGHT }?.level ?: 0,
|
rightBattery?.level ?: 0,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
it.setViewVisibility(
|
||||||
|
R.id.right_charging_icon,
|
||||||
|
if (rightBattery?.status == BatteryStatus.CHARGING) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
|
||||||
it.setTextViewText(
|
it.setTextViewText(
|
||||||
R.id.case_battery_widget,
|
R.id.case_battery_widget,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.CASE }?.let {
|
caseBattery?.let {
|
||||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
"${it.level}%"
|
||||||
} ?: ""
|
} ?: ""
|
||||||
)
|
)
|
||||||
it.setProgressBar(
|
it.setProgressBar(
|
||||||
R.id.case_battery_progress,
|
R.id.case_battery_progress,
|
||||||
100,
|
100,
|
||||||
batteryNotification.getBattery().find { it.component == BatteryComponent.CASE }?.level ?: 0,
|
caseBattery?.level ?: 0,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
it.setViewVisibility(
|
||||||
|
R.id.case_charging_icon,
|
||||||
|
if (caseBattery?.status == BatteryStatus.CHARGING) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
|
||||||
|
it.setViewVisibility(
|
||||||
|
R.id.phone_battery_widget_container,
|
||||||
|
if (widgetMobileBatteryEnabled) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
if (widgetMobileBatteryEnabled) {
|
||||||
|
val batteryManager = getSystemService<BatteryManager>(BatteryManager::class.java)
|
||||||
|
val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
|
||||||
|
val charging = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS) == BatteryManager.BATTERY_STATUS_CHARGING
|
||||||
|
it.setTextViewText(
|
||||||
|
R.id.phone_battery_widget,
|
||||||
|
"$batteryLevel%"
|
||||||
|
)
|
||||||
|
it.setViewVisibility(
|
||||||
|
R.id.phone_charging_icon,
|
||||||
|
if (charging) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
it.setProgressBar(
|
||||||
|
R.id.phone_battery_progress,
|
||||||
|
100,
|
||||||
|
batteryLevel,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Log.d("AirPodsService", "Updating battery widget")
|
|
||||||
appWidgetManager.updateAppWidget(widgetIds, remoteViews)
|
appWidgetManager.updateAppWidget(widgetIds, remoteViews)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,12 +601,6 @@ class AirPodsService: Service() {
|
|||||||
addAction("android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED")
|
addAction("android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
registerReceiver(bluetoothReceiver, serviceIntentFilter, RECEIVER_EXPORTED)
|
|
||||||
} else {
|
|
||||||
registerReceiver(bluetoothReceiver, serviceIntentFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
connectionReceiver = object: BroadcastReceiver() {
|
connectionReceiver = object: BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent?.action == AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED) {
|
if (intent?.action == AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED) {
|
||||||
@@ -432,8 +612,8 @@ class AirPodsService: Service() {
|
|||||||
val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
|
val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
|
||||||
.getString("name", device?.name)
|
.getString("name", device?.name)
|
||||||
if (this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).getString("name", null) == null) {
|
if (this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).getString("name", null) == null) {
|
||||||
this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).edit()
|
this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).edit {
|
||||||
.putString("name", name).apply()
|
putString("name", name)}
|
||||||
}
|
}
|
||||||
Log.d("AirPodsQuickSwitchServices", CrossDevice.isAvailable.toString())
|
Log.d("AirPodsQuickSwitchServices", CrossDevice.isAvailable.toString())
|
||||||
if (!CrossDevice.checkAirPodsConnectionStatus()) {
|
if (!CrossDevice.checkAirPodsConnectionStatus()) {
|
||||||
@@ -444,8 +624,7 @@ class AirPodsService: Service() {
|
|||||||
macAddress = device!!.address
|
macAddress = device!!.address
|
||||||
updateNotificationContent(true, name.toString(), batteryNotification.getBattery())
|
updateNotificationContent(true, name.toString(), batteryNotification.getBattery())
|
||||||
}
|
}
|
||||||
}
|
} else if (intent?.action == AirPodsNotifications.Companion.AIRPODS_DISCONNECTED) {
|
||||||
else if (intent?.action == AirPodsNotifications.Companion.AIRPODS_DISCONNECTED) {
|
|
||||||
device = null
|
device = null
|
||||||
isConnectedLocally = false
|
isConnectedLocally = false
|
||||||
popupShown = false
|
popupShown = false
|
||||||
@@ -454,16 +633,28 @@ class AirPodsService: Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val deviceIntentFilter = IntentFilter().apply {
|
val deviceIntentFilter = IntentFilter().apply {
|
||||||
addAction(AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED)
|
addAction(AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED)
|
||||||
addAction(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED)
|
addAction(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
registerReceiver(connectionReceiver, deviceIntentFilter, RECEIVER_EXPORTED)
|
registerReceiver(connectionReceiver, deviceIntentFilter, RECEIVER_EXPORTED)
|
||||||
|
registerReceiver(bluetoothReceiver, serviceIntentFilter, RECEIVER_EXPORTED)
|
||||||
} else {
|
} else {
|
||||||
registerReceiver(connectionReceiver, deviceIntentFilter)
|
registerReceiver(connectionReceiver, deviceIntentFilter)
|
||||||
|
registerReceiver(bluetoothReceiver, serviceIntentFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
widgetMobileBatteryEnabled = getSharedPreferences("settings", MODE_PRIVATE).getBoolean("show_phone_battery_in_widget", true)
|
||||||
|
if (widgetMobileBatteryEnabled) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
registerReceiver(PhoneBatteryReceiver, phoneBatteryIntentFilter, RECEIVER_EXPORTED)
|
||||||
|
} else {
|
||||||
|
registerReceiver(PhoneBatteryReceiver, phoneBatteryIntentFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
|
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
|
||||||
if (bluetoothAdapter.isEnabled) {
|
if (bluetoothAdapter.isEnabled) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
@@ -801,6 +992,15 @@ class AirPodsService: Service() {
|
|||||||
} else {
|
} else {
|
||||||
connectAudio(this@AirPodsService, device)
|
connectAudio(this@AirPodsService, device)
|
||||||
}
|
}
|
||||||
|
// setBatteryLevels(
|
||||||
|
// batteryNotification.getBattery()[0].status == 1,
|
||||||
|
// batteryNotification.getBattery()[0].level,
|
||||||
|
// batteryNotification.getBattery()[1].status == 1,
|
||||||
|
// batteryNotification.getBattery()[1].level,
|
||||||
|
// batteryNotification.getBattery()[2].status == 1,
|
||||||
|
// batteryNotification.getBattery()[2].level,
|
||||||
|
// device
|
||||||
|
// )
|
||||||
} else if (conversationAwarenessNotification.isConversationalAwarenessData(
|
} else if (conversationAwarenessNotification.isConversationalAwarenessData(
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,15 +17,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package me.kavishdevar.aln
|
package me.kavishdevar.aln.widgets
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetProvider
|
import android.appwidget.AppWidgetProvider
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.util.Log
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.core.graphics.createBitmap
|
||||||
|
import me.kavishdevar.aln.MainActivity
|
||||||
|
import me.kavishdevar.aln.R
|
||||||
import me.kavishdevar.aln.services.ServiceManager
|
import me.kavishdevar.aln.services.ServiceManager
|
||||||
import me.kavishdevar.aln.utils.BatteryComponent
|
|
||||||
import me.kavishdevar.aln.utils.BatteryStatus
|
|
||||||
|
|
||||||
class BatteryWidget : AppWidgetProvider() {
|
class BatteryWidget : AppWidgetProvider() {
|
||||||
override fun onUpdate(
|
override fun onUpdate(
|
||||||
@@ -33,7 +39,6 @@ class BatteryWidget : AppWidgetProvider() {
|
|||||||
appWidgetManager: AppWidgetManager,
|
appWidgetManager: AppWidgetManager,
|
||||||
appWidgetIds: IntArray
|
appWidgetIds: IntArray
|
||||||
) {
|
) {
|
||||||
// There may be multiple widgets active, so update all of them
|
|
||||||
for (appWidgetId in appWidgetIds) {
|
for (appWidgetId in appWidgetIds) {
|
||||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||||
}
|
}
|
||||||
@@ -44,40 +49,19 @@ class BatteryWidget : AppWidgetProvider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
internal fun updateAppWidget(
|
internal fun updateAppWidget(
|
||||||
context: Context,
|
context: Context,
|
||||||
appWidgetManager: AppWidgetManager,
|
appWidgetManager: AppWidgetManager,
|
||||||
appWidgetId: Int
|
appWidgetId: Int
|
||||||
) {
|
) {
|
||||||
val service = ServiceManager.getService()
|
val service = ServiceManager.getService()
|
||||||
val batteryList = service?.batteryNotification?.getBattery()
|
|
||||||
|
|
||||||
val views = RemoteViews(context.packageName, R.layout.battery_widget)
|
val views = RemoteViews(context.packageName, R.layout.battery_widget)
|
||||||
|
|
||||||
views.setTextViewText(R.id.left_battery_widget,
|
service?.updateBatteryWidget()
|
||||||
batteryList?.find { it.component == BatteryComponent.LEFT }?.let {
|
|
||||||
// if (it.status != BatteryStatus.DISCONNECTED) {
|
val openActivityIntent = PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||||
"${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
|
views.setOnClickPendingIntent(R.id.battery_widget, openActivityIntent)
|
||||||
// } 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 {
|
|
||||||
// ""
|
|
||||||
// }
|
|
||||||
} ?: "")
|
|
||||||
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item>
|
|
||||||
<shape android:shape="rectangle">
|
|
||||||
<solid android:color="#DA000000" />
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
||||||
14
android/app/src/main/res/drawable/button_background.xml
Normal file
14
android/app/src/main/res/drawable/button_background.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#121212" />
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#404040" />
|
||||||
|
<corners android:radius="12dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
<rotate
|
||||||
android:fromDegrees="-90"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fromDegrees="270"
|
||||||
android:toDegrees="270">
|
android:toDegrees="270">
|
||||||
<shape
|
<shape
|
||||||
android:shape="ring"
|
android:shape="ring"
|
||||||
android:innerRadiusRatio="3"
|
android:innerRadiusRatio="3.0"
|
||||||
android:thicknessRatio="8"
|
android:thickness="6dp"
|
||||||
android:useLevel="true">
|
android:useLevel="true">
|
||||||
<gradient
|
<solid android:color="#00D85B" />
|
||||||
android:type="sweep"
|
<corners android:radius="10dp" />
|
||||||
android:useLevel="true"
|
|
||||||
android:startColor="#00ff00"
|
|
||||||
android:endColor="#00ff00" />
|
|
||||||
</shape>
|
</shape>
|
||||||
</rotate>
|
</rotate>
|
||||||
15
android/app/src/main/res/drawable/ic_power.xml
Normal file
15
android/app/src/main/res/drawable/ic_power.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="88.06dp"
|
||||||
|
android:height="140.66dp"
|
||||||
|
android:viewportWidth="88.06"
|
||||||
|
android:viewportHeight="140.66">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M0,0h88.06v140.66h-88.06z"
|
||||||
|
android:strokeAlpha="0"
|
||||||
|
android:fillAlpha="0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,77.55C0,79.99 1.88,81.8 4.5,81.8L39.81,81.8L21.19,132.42C18.75,138.86 25.44,142.3 29.63,137.05L86.44,66.05C87.5,64.74 88.06,63.49 88.06,62.05C88.06,59.67 86.19,57.8 83.56,57.8L48.25,57.8L66.88,7.17C69.31,0.74 62.63,-2.7 58.44,2.61L1.63,73.55C0.56,74.92 0,76.17 0,77.55Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillAlpha="0.85"/>
|
||||||
|
</vector>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape
|
<shape
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle" >
|
android:shape="rectangle">
|
||||||
|
|
||||||
<solid
|
<solid
|
||||||
android:color="@color/popup_background" >
|
android:color="@color/popup_background">
|
||||||
</solid>
|
</solid>
|
||||||
|
|
||||||
<padding
|
<padding
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape
|
||||||
|
android:shape="ring"
|
||||||
|
android:innerRadiusRatio="3.0"
|
||||||
|
android:thickness="6dp">
|
||||||
|
<solid android:color="#49474E" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
19
android/app/src/main/res/drawable/smartphone.xml
Normal file
19
android/app/src/main/res/drawable/smartphone.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="80.31dp"
|
||||||
|
android:height="132.44dp"
|
||||||
|
android:viewportWidth="80.31"
|
||||||
|
android:viewportHeight="132.44">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M0,0h80.31v132.44h-80.31z"
|
||||||
|
android:strokeAlpha="0"
|
||||||
|
android:fillAlpha="0"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12.44,114.31C11.06,114.31 10.06,113.31 10.06,111.94L10.06,12.44C10.06,11 11,10.06 12.44,10.06L67.88,10.06C69.31,10.06 70.25,11 70.25,12.44L70.25,111.94C70.25,113.31 69.31,114.31 67.88,114.31Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillAlpha="0.2125"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M7.75,132.31L72.56,132.31C77.13,132.31 80.31,129.13 80.31,124.56L80.31,7.75C80.31,3.19 77.13,0 72.56,0L7.75,0C3.19,0 0,3.19 0,7.75L0,124.56C0,129.13 3.25,132.31 7.75,132.31ZM12.44,114.31C11.06,114.31 10.06,113.31 10.06,111.94L10.06,12.44C10.06,11 11,10.06 12.44,10.06L67.88,10.06C69.31,10.06 70.25,11 70.25,12.44L70.25,111.94C70.25,113.31 69.31,114.31 67.88,114.31Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillAlpha="0.85"/>
|
||||||
|
</vector>
|
||||||
9
android/app/src/main/res/drawable/widget_background.xml
Normal file
9
android/app/src/main/res/drawable/widget_background.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<padding android:bottom="0dp" android:left="0dp" android:right="0dp" android:top="0dp" />
|
||||||
|
<solid android:color="#222222" />
|
||||||
|
<corners android:radius="32dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
@@ -2,28 +2,106 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="@style/Widget.ALN.AppWidget.Container"
|
style="@style/Widget.ALN.AppWidget.Container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
android:id="@+id/battery_widget"
|
android:id="@+id/battery_widget"
|
||||||
android:theme="@style/Theme.ALN.AppWidgetContainer"
|
android:theme="@style/Theme.ALN.AppWidgetContainer"
|
||||||
android:background="@drawable/blur_background">
|
android:background="@drawable/widget_background">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
android:layout_margin="0dp"
|
android:layout_margin="0dp"
|
||||||
android:gravity="center"
|
android:id="@android:id/background"
|
||||||
android:orientation="horizontal">
|
android:layout_gravity="center">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:id="@+id/phone_battery_widget_container"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="90dp"
|
||||||
|
android:layout_height="90dp"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/phone_battery_progress_background"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"
|
||||||
|
android:progressDrawable="@drawable/progress_bar_background" />
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/phone_battery_progress"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="50"
|
||||||
|
android:progressDrawable="@drawable/circular_progress_bar" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/phone_charging_icon"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="top|center_horizontal"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_power"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:tint="@color/white"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@drawable/smartphone"
|
||||||
|
android:tint="@color/white"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
</FrameLayout>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/phone_battery_widget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:fontFamily="@font/sf_pro"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textFontWeight="300"
|
||||||
|
android:text="Phone"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="64dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="90dp"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:padding="6dp"
|
||||||
android:layout_gravity="center">
|
android:layout_gravity="center">
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/left_battery_progress_background"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"
|
||||||
|
android:progressDrawable="@drawable/progress_bar_background" />
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/left_battery_progress"
|
android:id="@+id/left_battery_progress"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
@@ -31,22 +109,36 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:indeterminate="false"
|
android:indeterminate="false"
|
||||||
android:max="100"
|
android:max="100"
|
||||||
|
android:progress="50"
|
||||||
android:progressDrawable="@drawable/circular_progress_bar" />
|
android:progressDrawable="@drawable/circular_progress_bar" />
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="32dp"
|
android:id="@+id/left_charging_icon"
|
||||||
android:layout_height="32dp"
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="top|center_horizontal"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_power"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:tint="@color/white"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
android:src="@drawable/airpods_pro_left_notification"
|
android:src="@drawable/airpods_pro_left_notification"
|
||||||
android:tint="@color/popup_text"
|
android:tint="@color/white"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/left_battery_widget"
|
android:id="@+id/left_battery_widget"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="16sp"
|
android:textSize="24sp"
|
||||||
android:textColor="@color/popup_text"
|
android:textColor="@color/white"
|
||||||
|
android:fontFamily="@font/sf_pro"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:textFontWeight="300"
|
||||||
android:text="Left"
|
android:text="Left"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -54,13 +146,24 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="64dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="90dp"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:padding="6dp"
|
||||||
android:layout_gravity="center">
|
android:layout_gravity="center">
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/right_battery_progress_background"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"
|
||||||
|
android:progressDrawable="@drawable/progress_bar_background" />
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/right_battery_progress"
|
android:id="@+id/right_battery_progress"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
@@ -70,10 +173,21 @@
|
|||||||
android:max="100"
|
android:max="100"
|
||||||
android:progressDrawable="@drawable/circular_progress_bar" />
|
android:progressDrawable="@drawable/circular_progress_bar" />
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="32dp"
|
android:id="@+id/right_charging_icon"
|
||||||
android:layout_height="32dp"
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="top|center_horizontal"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_power"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:tint="@color/white"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
android:src="@drawable/airpods_pro_right_notification"
|
android:src="@drawable/airpods_pro_right_notification"
|
||||||
android:tint="@color/popup_text"
|
android:tint="@color/white"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
@@ -81,8 +195,10 @@
|
|||||||
android:id="@+id/right_battery_widget"
|
android:id="@+id/right_battery_widget"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="16sp"
|
android:textSize="24sp"
|
||||||
android:textColor="@color/popup_text"
|
android:textFontWeight="300"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:fontFamily="@font/sf_pro"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="Right"
|
android:text="Right"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
@@ -91,13 +207,24 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="64dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="90dp"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:padding="6dp"
|
||||||
android:layout_gravity="center">
|
android:layout_gravity="center">
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/case_battery_progress_background"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"
|
||||||
|
android:progressDrawable="@drawable/progress_bar_background" />
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/case_battery_progress"
|
android:id="@+id/case_battery_progress"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
@@ -107,10 +234,21 @@
|
|||||||
android:max="100"
|
android:max="100"
|
||||||
android:progressDrawable="@drawable/circular_progress_bar" />
|
android:progressDrawable="@drawable/circular_progress_bar" />
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="32dp"
|
android:id="@+id/case_charging_icon"
|
||||||
android:layout_height="32dp"
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:layout_gravity="top|center_horizontal"
|
||||||
|
android:src="@drawable/ic_power"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:tint="@color/white"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
android:src="@drawable/airpods_pro_case_notification"
|
android:src="@drawable/airpods_pro_case_notification"
|
||||||
android:tint="@color/popup_text"
|
android:tint="@color/white"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
@@ -118,9 +256,11 @@
|
|||||||
android:id="@+id/case_battery_widget"
|
android:id="@+id/case_battery_widget"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="16sp"
|
android:textSize="24sp"
|
||||||
android:textColor="@color/popup_text"
|
android:textColor="@color/white"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:fontFamily="@font/sf_pro"
|
||||||
|
android:textFontWeight="300"
|
||||||
android:text="Case"
|
android:text="Case"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
android:layout_margin="16.dp"
|
android:layout_margin="16.dp"
|
||||||
android:id="@+id/linear_layout"
|
android:id="@+id/linear_layout"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="@drawable/shape">
|
android:background="@drawable/popup_shape">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -4,17 +4,11 @@
|
|||||||
<style name="Theme.ALN" parent="android:Theme.Material.Light.NoActionBar" />
|
<style name="Theme.ALN" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
|
|
||||||
<style name="Theme.ALN.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
|
<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">32dp</item>
|
||||||
<item name="appWidgetRadius">24dp</item>
|
<item name="appWidgetPadding">0dp</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">24dp</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.ALN.AppWidgetContainer" parent="Theme.ALN.AppWidgetContainerParent">
|
<style name="Theme.ALN.AppWidgetContainer" parent="Theme.ALN.AppWidgetContainerParent">
|
||||||
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
|
<item name="appWidgetPadding">0dp</item>
|
||||||
<item name="appWidgetPadding">16dp</item>
|
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:description="@string/app_widget_description"
|
android:description="@string/app_widget_description"
|
||||||
android:initialKeyguardLayout="@layout/battery_widget"
|
android:initialKeyguardLayout="@layout/battery_widget"
|
||||||
android:initialLayout="@layout/battery_widget"
|
android:initialLayout="@layout/battery_widget"
|
||||||
android:minWidth="40dp"
|
android:minWidth="180dp"
|
||||||
android:minHeight="40dp"
|
android:minHeight="40dp"
|
||||||
android:previewImage="@drawable/example_appwidget_preview"
|
android:previewImage="@drawable/example_appwidget_preview"
|
||||||
android:previewLayout="@layout/battery_widget"
|
android:previewLayout="@layout/battery_widget"
|
||||||
android:resizeMode="horizontal|vertical"
|
android:resizeMode="horizontal|vertical"
|
||||||
android:targetCellWidth="1"
|
android:targetCellWidth="3"
|
||||||
android:targetCellHeight="1"
|
android:targetCellHeight="1"
|
||||||
android:updatePeriodMillis="300000"
|
android:updatePeriodMillis="300000"
|
||||||
android:widgetCategory="home_screen|keyguard" />
|
android:widgetCategory="home_screen|keyguard"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
Reference in New Issue
Block a user