Skip to content

Commit

Permalink
Refactor, Share Storage Info, Check Relevant Permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
shrimqy committed Sep 16, 2024
1 parent 7009c2c commit 05011b8
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 31 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />

Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/komu/presentation/about/AboutScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ fun AboutScreen(rootNavController: NavController, modifier: Modifier = Modifier)
item {
TextPreferenceWidget(
title = "Version",
subtitle = "0.1, Sep 10, 2024",
subtitle = "0.2.1, Sep 15, 2024",
onPreferenceClick = { uriHandler.openUri("https://github.com/shrimqy/Sekia") },
)
}

item {
TextPreferenceWidget(
title = "What's new",
onPreferenceClick = { },
onPreferenceClick = { uriHandler.openUri("https://github.com/shrimqy/Sekia/releases") },
)
}

Expand Down
64 changes: 51 additions & 13 deletions app/src/main/java/com/komu/sekia/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.komu.sekia

import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
Expand Down Expand Up @@ -33,13 +35,14 @@ class MainActivity : BaseActivity() {
private val viewModel by viewModels<MainViewModel>()


private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
if (permissions.all { it.value }) {
viewModel.startWebSocketService(this)
private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val deniedPermissions = permissions.filter { !it.value }.keys
if (deniedPermissions.isNotEmpty()) {
deniedPermissions.forEach { permission ->
showPermissionExplanationDialog(permission)
}
} else {
showPermissionExplanationDialog()
viewModel.startWebSocketService(this)
}
}

Expand Down Expand Up @@ -69,13 +72,23 @@ class MainActivity : BaseActivity() {
val permissions = mutableListOf(
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.ACCESS_FINE_LOCATION
)

// Add notification permissions for Android 13+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions.add(android.Manifest.permission.POST_NOTIFICATIONS)
}

permissions.add(android.Manifest.permission.ACCESS_FINE_LOCATION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+
if (!Environment.isExternalStorageManager()) {
showPermissionExplanationDialog(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
return
}
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { // Android 10 and below
permissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE)
permissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}

val permissionsToRequest = permissions.filter {
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
Expand All @@ -88,14 +101,39 @@ class MainActivity : BaseActivity() {
}
}

private fun showPermissionExplanationDialog() {
@SuppressLint("InlinedApi")
private fun showPermissionExplanationDialog(permission: String) {
val title: String
val message: String
val settingsIntent: Intent

when (permission) {
android.Manifest.permission.MANAGE_EXTERNAL_STORAGE -> {
title = "Storage Access Required"
message = "This app needs access to manage all files on your device. Please grant this permission in your device's settings."
settingsIntent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
}
android.Manifest.permission.POST_NOTIFICATIONS -> {
title = "Notification Access Required"
message = "This app needs access to notifications. Please grant this permission in your device's settings."
settingsIntent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
}
}
else -> {
title = "Permissions Required"
message = "This app requires access to some permissions to function properly. Please grant the necessary permissions."
settingsIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
}
}

AlertDialog.Builder(this)
.setTitle("Permissions Required")
.setMessage("This app requires access to Wi-Fi and location information to function properly. Please grant the necessary permissions.")
.setTitle(title)
.setMessage(message)
.setPositiveButton("Open Settings") { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.fromParts("package", packageName, null)
startActivity(intent)
startActivity(settingsIntent)
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/com/komu/sekia/services/NetworkService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ import androidx.work.WorkManager
import androidx.work.workDataOf
import com.komu.sekia.MainActivity
import com.komu.sekia.R
import com.komu.sekia.utils.getStorageInfo
import dagger.hilt.android.AndroidEntryPoint
import komu.seki.data.repository.AppRepository
import komu.seki.data.services.NsdService
import komu.seki.domain.models.DeviceInfo
import komu.seki.domain.models.DeviceStatus
import komu.seki.domain.models.SocketMessage
import komu.seki.domain.models.StorageInfo
import komu.seki.domain.repository.PreferencesRepository
import komu.seki.domain.repository.WebSocketRepository
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -197,7 +199,6 @@ class NetworkService : Service() {
while (attempt < maxRetries && !connected) {
try {
attempt++
val deviceStatus = getDeviceStatus()
Log.d("WebSocketService", "Attempt $attempt: Trying to connect")

// Try to connect, passing deviceInfo if it's a new device
Expand All @@ -210,9 +211,8 @@ class NetworkService : Service() {
connected = true
startListening()
preferencesRepository.saveSynStatus(true)
// Send device status and notifications
Log.d("service", deviceStatus.toString())
sendMessage(deviceStatus)
sendMessage(getStorageInfo())
sendMessage(getDeviceStatus())
sendActiveNotifications()
break
} else {
Expand Down
28 changes: 18 additions & 10 deletions app/src/main/java/com/komu/sekia/services/NotificationService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,6 @@ class NotificationService : NotificationListenerService() {
bitmapToBase64(pictureBitmap as Bitmap)
}

val extras = notification.extras

// Use the utility function to get text from SpannableString
val title = getSpannableText(notification.extras.getCharSequence(Notification.EXTRA_TITLE))
?: getSpannableText(notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG))
Expand All @@ -191,9 +189,6 @@ class NotificationService : NotificationListenerService() {
// Convert timestamp to a human-readable format if needed
val formattedTimestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", getDefault()).format(Date(timestamp))

val id = notification.extras.getString(Notification.EXTRA_NOTIFICATION_ID)
val tag = notification.extras.getString(Notification.EXTRA_NOTIFICATION_TAG)

Log.d("message", "$appName $title $text messages: $messages $formattedTimestamp")
Log.d("NotificationService", notification.toString())

Expand All @@ -207,11 +202,24 @@ class NotificationService : NotificationListenerService() {

// Retrieve the actions from the notification
val actions = notification.actions?.map { action ->
NotificationAction(
label = action.title.toString(),
actionId = action.actionIntent.toString()
)
}
try {
// Extract action label and intent if they exist
val actionLabel = action.title?.toString() ?: "Unknown Action"
val actionIntent = action.actionIntent?.toString() ?: "No Action Intent"

Log.d("NotificationService", "Found action: $actionLabel with intent: $actionIntent")

// Return a new NotificationAction object with the label and intent
NotificationAction(
label = actionLabel,
actionId = actionIntent
)
} catch (e: Exception) {
// Log any error that occurs while processing the actions
Log.e("NotificationService", "Error retrieving action: ${e.localizedMessage}")
null
}
} ?: emptyList()

val notificationMessage = NotificationMessage(
notificationKey = notificationKey,
Expand Down
76 changes: 76 additions & 0 deletions app/src/main/java/com/komu/sekia/utils/StorageUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.komu.sekia.utils

import android.os.Environment
import android.os.StatFs
import komu.seki.domain.models.DirectoryInfo
import komu.seki.domain.models.StorageInfo
import java.io.File
import java.text.DecimalFormat

fun getStorageInfo(): StorageInfo {
val externalStorage = Environment.getExternalStorageDirectory()
val stat = StatFs(externalStorage.path)

val blockSize = stat.blockSizeLong
val totalBlocks = stat.blockCountLong
val availableBlocks = stat.availableBlocksLong

val totalSpace = totalBlocks * blockSize // Total storage space in bytes
val availableSpace = availableBlocks * blockSize // Available storage space in bytes
val usedSpace = totalSpace - availableSpace // Used storage space in bytes

// Return the formatted storage info as a StorageInfo object
return StorageInfo(
totalSpace = totalSpace,
freeSpace = availableSpace,
usedSpace = usedSpace
)
}

fun formatSize(size: Long): String {
val kilo = 1024.0
val mega = kilo * 1024
val giga = mega * 1024

val formatter = DecimalFormat("#.##")

return when {
size >= giga -> {formatter.format(size / giga)}
size >= mega -> {formatter.format(size / mega)}
else -> {formatter.format(size / kilo)}
}
}

fun getRootDirectory(): List<DirectoryInfo> {
val rootDirectory = Environment.getExternalStorageDirectory()
return listFilesInDirectory(rootDirectory)
}


// Function to retrieve files and folders in a given directory
fun listFilesInDirectory(directory: File): List<DirectoryInfo> {
val fileList = mutableListOf<DirectoryInfo>()

// Get list of files and folders in the directory
val files = directory.listFiles() ?: return emptyList()

for (file in files) {
fileList.add(
DirectoryInfo(
path = file.absolutePath,
name = file.name,
isDirectory = file.isDirectory,
size = if (file.isFile) formatSize(file.length()) else formatSize(file.totalSpace) // Get size only for files
)
)
}
return fileList
}

fun getDirectoryStructure(path: String): List<DirectoryInfo> {
val directory = File(path)
if (directory.exists() && directory.isDirectory) {
return listFilesInDirectory(directory)
}
return emptyList() // Return an empty list if the directory doesn't exist
}
19 changes: 17 additions & 2 deletions core/domain/src/main/java/komu/seki/domain/models/SocketMessage.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package komu.seki.domain.models

import android.os.Parcelable
import android.util.Base64
import komu.seki.common.models.FileMetadata
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.SerialName
Expand Down Expand Up @@ -73,7 +72,7 @@ data class NotificationMessage(
val appIcon: String? = null,
val largeIcon: String? = null,
val bigPicture: String? = null,
val actions: List<NotificationAction>? = emptyList(),
val actions: List<NotificationAction?> = emptyList(),
) : SocketMessage()

@Serializable
Expand Down Expand Up @@ -134,3 +133,19 @@ data class FileTransfer(
val chunkData: String? = null,
) : SocketMessage()

@Serializable
@SerialName("8")
data class StorageInfo(
val totalSpace: Long,
val freeSpace: Long,
val usedSpace: Long,
) : SocketMessage()

@Serializable
@SerialName("9")
data class DirectoryInfo(
val path: String,
val name: String,
val isDirectory: Boolean,
val size: String?
) : SocketMessage()

0 comments on commit 05011b8

Please sign in to comment.