...
This commit is contained in:
parent
e1ec3c12d2
commit
55f2c3272c
@ -40,7 +40,7 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.LunarLauncher"
|
||||
android:excludeFromRecents="true"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:largeHeap="true"
|
||||
@ -52,7 +52,7 @@
|
||||
<activity
|
||||
android:name=".LauncherActivity"
|
||||
android:theme="@style/Theme.LunarLauncher.Starting"
|
||||
android:launchMode="singleInstance"
|
||||
android:launchMode="singleInstance"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@ -113,6 +113,14 @@
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<service android:name=".utils.NLService"
|
||||
android:label="@string/app_name"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
||||
@ -19,7 +19,9 @@
|
||||
package rasel.lunar.launcher.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
@ -31,15 +33,12 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
|
||||
import androidx.core.content.ContextCompat.registerReceiver
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.google.gson.Gson
|
||||
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
||||
@ -84,6 +83,17 @@ internal class LauncherHome : Fragment() {
|
||||
var smsList = arrayListOf<RecentSmsLog>()
|
||||
}
|
||||
|
||||
private val nReceiver: NotificationReceiver? = null
|
||||
|
||||
class NotificationReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
// val temp = """
|
||||
// ${intent.getStringExtra("notification_event")}
|
||||
//// ${txtView.getText()}
|
||||
// """.trimIndent()
|
||||
// txtView.setText(temp)
|
||||
}
|
||||
}
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
||||
binding = LauncherHomeBinding.inflate(inflater, container, false)
|
||||
@ -100,16 +110,26 @@ internal class LauncherHome : Fragment() {
|
||||
mWorkManager?.enqueue(PeriodicWorkRequestBuilder<RecentSmsGetter>(30, TimeUnit.SECONDS).addTag("RecentSmsGetter").build())
|
||||
mWorkManager?.enqueueUniquePeriodicWork("MissedCallGetter",ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,PeriodicWorkRequestBuilder<MissedCallGetter>(30, TimeUnit.SECONDS).addTag("MissedCallGetter").build())
|
||||
mWorkManager?.getWorkInfosByTagLiveData("RecentSmsGetter")?.observeForever {
|
||||
binding.recentSms.text = "최근 문자 [${smsList.size}]"
|
||||
if (binding.recentSms.isChecked) chooseAdpater()
|
||||
else if (missedCalls.size == 0) {
|
||||
binding.recentSms.isChecked = true
|
||||
chooseAdpater()
|
||||
}
|
||||
BLog.LOGE("smsList.size >>> ${smsList.size}")
|
||||
it.clear()
|
||||
it.clear()
|
||||
}
|
||||
|
||||
mWorkManager?.getWorkInfosByTagLiveData("MissedCallGetter")?.observeForever {
|
||||
binding.missedCalls.text = "최근 통화 [${missedCalls.size}]"
|
||||
if (binding.missedCalls.isChecked) chooseAdpater()
|
||||
it.clear()
|
||||
}
|
||||
|
||||
val filter = IntentFilter()
|
||||
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
registerReceiver(requireContext(),nReceiver, filter,RECEIVER_EXPORTED)
|
||||
|
||||
BLog.LOGE("onCreateView()")
|
||||
return binding.root
|
||||
}
|
||||
@ -178,6 +198,7 @@ internal class LauncherHome : Fragment() {
|
||||
try {
|
||||
BLog.LOGE("chooseAdpater smsList >>> ${smsList.size}")
|
||||
binding.mainList.adapter = mSmsLogsAdapter
|
||||
smsList.sortByDescending { it.rcvDate }
|
||||
mSmsLogsAdapter.updateData(smsList)
|
||||
} catch (e : Exception) {
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard
|
||||
import rasel.lunar.launcher.home.MissedCall
|
||||
import rasel.lunar.launcher.utils.BLog
|
||||
import rasel.lunar.launcher.utils.RecentSmsLog
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.List
|
||||
@ -63,7 +64,8 @@ internal class SmsLogsAdapter(
|
||||
override fun onBindViewHolder(holder: SmsLogHolder, position: Int) {
|
||||
val todo = smsList[position]
|
||||
BLog.LOGE("SmsLogsAdapter smsList >>> ${smsList[position]}")
|
||||
holder.view.itemText.text = "\u25CF ${todo.person} ${todo.addr} , ${todo.body} : ${todo.pstDate} : ${todo.type}"
|
||||
|
||||
holder.view.itemText.text = "\u25CF ${todo.person} ${todo.addr} , ${todo.body} : ${SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Date(Math.max(todo.pstDate.toLong(),todo.rcvDate.toLong())))} : ${todo.type}"
|
||||
|
||||
/* multiline texts are enabled for TodoManager */
|
||||
// holder.view.itemText.isSingleLine = false
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package rasel.lunar.launcher.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.CallLog
|
||||
import android.provider.Telephony
|
||||
import androidx.work.Data
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
@ -13,8 +15,12 @@ import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
|
||||
import rasel.lunar.launcher.home.LauncherHome.Companion.missedCalls
|
||||
import rasel.lunar.launcher.home.LauncherHome.Companion.smsList
|
||||
import rasel.lunar.launcher.home.MissedCall
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class MissedCallGetter : Worker {
|
||||
|
||||
@ -24,7 +30,7 @@ class MissedCallGetter : Worker {
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun doWork(): Result {
|
||||
|
||||
var dateParam = Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24)).time.toString()
|
||||
var dateParam = beforeDay(Date(),3).toString()
|
||||
var managedCursor =lActivity?.contentResolver?.query(
|
||||
CallLog.Calls.CONTENT_URI, arrayOf(
|
||||
CallLog.Calls.NUMBER,
|
||||
@ -32,7 +38,9 @@ class MissedCallGetter : Worker {
|
||||
CallLog.Calls.DATE,
|
||||
CallLog.Calls.DURATION,
|
||||
CallLog.Calls.CACHED_NAME,
|
||||
), CallLog.Calls.DATE + "> ? AND " + CallLog.Calls.TYPE + " > ?", arrayOf<String>(dateParam, "2"), CallLog.Calls.DATE + " desc")
|
||||
), CallLog.Calls.DATE + " >= ? " , arrayOf<String>(dateParam), CallLog.Calls.DATE + " desc")
|
||||
//+ CallLog.Calls.TYPE + " > ?"
|
||||
//, "2"
|
||||
if(managedCursor != null && managedCursor.isClosed == false) {
|
||||
try {
|
||||
val number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER)
|
||||
@ -94,6 +102,7 @@ class MissedCallGetter : Worker {
|
||||
SimpleDateFormat("yyy/MM/dd-HH:mm:ss").format(callDayTime)
|
||||
)
|
||||
}
|
||||
BLog.LOGE("missed put >>> ${missed.toJson()}")
|
||||
missedCalls.put(phNumber, missed)
|
||||
}
|
||||
|
||||
@ -111,6 +120,12 @@ class MissedCallGetter : Worker {
|
||||
|
||||
}
|
||||
|
||||
fun beforeDay(date: Date?, day: Int): Long {
|
||||
val cal: Calendar = Calendar.getInstance()
|
||||
cal.setTime(date)
|
||||
cal.add(Calendar.DAY_OF_YEAR, Math.abs(day) * -1)
|
||||
return cal.timeInMillis
|
||||
}
|
||||
|
||||
class RecentSmsGetter : Worker {
|
||||
|
||||
@ -120,11 +135,11 @@ class RecentSmsGetter : Worker {
|
||||
|
||||
|
||||
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun doWork(): Result {
|
||||
BLog.LOGE("phNumber == onStart")
|
||||
var resultData = workDataOf("" to "")
|
||||
var dateParam = Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24 * 3)).time.toString()
|
||||
var dateParam = beforeDay(Date(),3).toString()
|
||||
val managedCursor = lActivity?.contentResolver?.query(
|
||||
Telephony.Sms.CONTENT_URI, arrayOf(
|
||||
Telephony.Sms.ADDRESS,
|
||||
@ -133,9 +148,10 @@ class RecentSmsGetter : Worker {
|
||||
Telephony.Sms.DATE_SENT,
|
||||
Telephony.Sms.BODY,
|
||||
Telephony.Sms.PERSON,
|
||||
), Telephony.Sms.DATE + ">= ? OR " + Telephony.Sms.DATE_SENT + " >= ?", arrayOf<String>(dateParam, dateParam), Telephony.Sms.DEFAULT_SORT_ORDER)
|
||||
), Telephony.Sms.DATE + "> ${dateParam}", null, Telephony.Sms.DEFAULT_SORT_ORDER)
|
||||
if (managedCursor != null && managedCursor.isClosed == false) {
|
||||
try {
|
||||
smsList.clear()
|
||||
val address = managedCursor.getColumnIndex(Telephony.Sms.ADDRESS)
|
||||
val type = managedCursor.getColumnIndex(Telephony.Sms.TYPE)
|
||||
val date = managedCursor.getColumnIndex(Telephony.Sms.DATE)
|
||||
@ -179,16 +195,20 @@ class RecentSmsGetter : Worker {
|
||||
managedCursor.close()
|
||||
}
|
||||
}
|
||||
if (lActivity?.contentResolver != null) {
|
||||
TestQueryHelper(lActivity?.contentResolver!!).query()
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RecentSmsLog {
|
||||
var id : String = ""
|
||||
var addr : String = ""
|
||||
var type : String = ""
|
||||
var rcvDate : String = ""
|
||||
var pstDate : String = ""
|
||||
var rcvDate : String = "0"
|
||||
var pstDate : String = "0"
|
||||
var body : String = ""
|
||||
var person : String = ""
|
||||
|
||||
@ -208,7 +228,118 @@ class RecentSmsLog {
|
||||
this.person = person
|
||||
}
|
||||
|
||||
constructor(id: String, sender: String, date: String, body: String) {
|
||||
this.id = id
|
||||
this.rcvDate = date
|
||||
this.body = body
|
||||
this.addr = sender
|
||||
}
|
||||
|
||||
fun toJson() : String {
|
||||
return Gson().toJson(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TestQueryHelper(
|
||||
private val _contentResolver: ContentResolver
|
||||
) {
|
||||
|
||||
private val mmsUri: Uri = Telephony.Mms.CONTENT_URI
|
||||
private val cursor: Cursor?
|
||||
get() =
|
||||
_contentResolver.query(
|
||||
mmsUri,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
fun dataMapper(cursor: Cursor): RecentSmsLog {
|
||||
val id = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Mms._ID))
|
||||
val date = cursor.getLong(cursor.getColumnIndexOrThrow(Telephony.Mms.DATE)) * 1000
|
||||
val sender : String = getSender(id) ?: throw NullPointerException("NotFound Sender For Mms")
|
||||
val body: String = getBody(id) ?: throw NullPointerException("NotFound Body by Mms")
|
||||
|
||||
return RecentSmsLog(
|
||||
id = id.toString(),
|
||||
date = date.toString(),
|
||||
body = body,
|
||||
sender = sender
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSender(id: Int): String? {
|
||||
_contentResolver.query(
|
||||
Uri.parse("content://mms/$id/addr"),
|
||||
null,
|
||||
"${Telephony.Mms.Addr.MSG_ID} = ?",
|
||||
arrayOf(id.toString()),
|
||||
null
|
||||
)?.use { senderAddressCursor ->
|
||||
if (senderAddressCursor.moveToFirst()) {
|
||||
do {
|
||||
// 137 수신, 151 발신 타입 값이다. Telephony.Mms.Addr.Type 의 주석 참고.
|
||||
val isSender = senderAddressCursor.getInt(
|
||||
senderAddressCursor.getColumnIndexOrThrow(Telephony.Mms.Addr.TYPE)
|
||||
) == 137
|
||||
var sender = senderAddressCursor.getString(
|
||||
senderAddressCursor.getColumnIndexOrThrow(Telephony.Mms.Addr.ADDRESS)
|
||||
)
|
||||
BLog.LOGE("sender >> ${sender}")
|
||||
if (isSender) {
|
||||
return sender
|
||||
}
|
||||
} while (senderAddressCursor.moveToNext())
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getBody(id: Int): String? {
|
||||
_contentResolver.query(
|
||||
Uri.parse("content://mms/part"),
|
||||
null,
|
||||
"${Telephony.Mms.Part.MSG_ID} = ?",
|
||||
arrayOf(id.toString()),
|
||||
null
|
||||
)?.use { partsCursor ->
|
||||
if (partsCursor.moveToFirst()) {
|
||||
do {
|
||||
val partContentType =
|
||||
partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part.CONTENT_TYPE))
|
||||
if (partContentType == "text/plain") {
|
||||
var textBody =
|
||||
partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part.TEXT))
|
||||
.replace("\n\n", "\n").replace("\n", " ")
|
||||
if (textBody.length > 60) {
|
||||
textBody = textBody.substring(0, Math.min(textBody.length, 60)).plus(" ... ")
|
||||
}
|
||||
BLog.LOGE("textBody >>> ${textBody}")
|
||||
|
||||
return textBody
|
||||
}
|
||||
} while (partsCursor.moveToNext())
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun convertData(cursor: Cursor?) {
|
||||
cursor ?: return
|
||||
cursor.use {
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
val data = kotlin.runCatching {
|
||||
dataMapper(cursor)
|
||||
}.getOrNull()
|
||||
data?.let { smsList.add(it) }
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
}
|
||||
}
|
||||
fun query() {
|
||||
return convertData(cursor)
|
||||
}
|
||||
|
||||
}
|
||||
67
app/src/main/kotlin/rasel/lunar/launcher/utils/PLService.kt
Normal file
67
app/src/main/kotlin/rasel/lunar/launcher/utils/PLService.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package rasel.lunar.launcher.utils
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.Log
|
||||
|
||||
|
||||
class NLService : NotificationListenerService() {
|
||||
private val TAG: String = this.javaClass.simpleName
|
||||
private var nlservicereciver: NLServiceReceiver? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
nlservicereciver = NLServiceReceiver()
|
||||
val filter = IntentFilter()
|
||||
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
|
||||
registerReceiver(nlservicereciver, filter)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unregisterReceiver(nlservicereciver)
|
||||
}
|
||||
|
||||
override fun onNotificationPosted(sbn: StatusBarNotification) {
|
||||
Log.i(TAG, "********** onNotificationPosted")
|
||||
Log.i(TAG, "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
|
||||
val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
|
||||
sendBroadcast(i)
|
||||
}
|
||||
|
||||
override fun onNotificationRemoved(sbn: StatusBarNotification) {
|
||||
Log.i(TAG, "********** onNOtificationRemoved")
|
||||
Log.i(TAG, "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
|
||||
val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
|
||||
|
||||
sendBroadcast(i)
|
||||
}
|
||||
|
||||
internal inner class NLServiceReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
if (intent.getStringExtra("command") == "clearall") {
|
||||
this@NLService.cancelAllNotifications()
|
||||
} else if (intent.getStringExtra("command") == "list") {
|
||||
val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
i1.putExtra("notification_event", "=====================")
|
||||
sendBroadcast(i1)
|
||||
var i = 1
|
||||
for (sbn in this@NLService.activeNotifications) {
|
||||
val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n")
|
||||
sendBroadcast(i2)
|
||||
i++
|
||||
}
|
||||
val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
|
||||
i3.putExtra("notification_event", "===== Notification List ====")
|
||||
sendBroadcast(i3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user