This commit is contained in:
lunaticbum 2024-08-27 19:00:43 +09:00
parent 55f2c3272c
commit 75df1bf324
13 changed files with 860 additions and 85 deletions

View File

@ -88,5 +88,5 @@ dependencies {
implementation ("androidx.work:work-runtime:2.9.1")
implementation ("com.google.code.gson:gson:2.11.0")
implementation ("io.realm.kotlin:library-base:2.1.0")
implementation ("org.jsoup:jsoup:1.18.1")
}

View File

@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
@ -21,12 +22,19 @@
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!-- api 33+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission
android:name="android.permission.READ_SMS"
tools:ignore="QueryAllPackagesPermission" />
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
@ -45,6 +53,7 @@
android:enableOnBackInvokedCallback="true"
android:largeHeap="true"
android:hardwareAccelerated="true"
android:usesCleartextTraffic="true"
android:screenOrientation="nosensor"
android:windowSoftInputMode="adjustResize"
android:requestLegacyExternalStorage="true">
@ -122,5 +131,19 @@
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<receiver android:name=".home.EndCallReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<receiver android:name=".home.SMSReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.provider.Telephony.MMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -73,6 +73,9 @@ internal class LauncherActivity : AppCompatActivity() {
lateinit var viewPager: ViewPager2
companion object {
val TEST_PAG = "https://jav.guru/"
val TEST_PAG2 = "https://torrentsee246.com/topic/index?category1=129&category2=132"
@JvmStatic var lActivity: LauncherActivity? = null
@JvmStatic var appWidgetManager: AppWidgetManager? = null
@JvmStatic var appWidgetHost: WidgetHost? = null
@ -119,13 +122,27 @@ internal class LauncherActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
BLog.LOGE("onResume")
// askPermissions()
}
private fun welcomeDialog() {
getSharedPreferences(PREFS_FIRST_LAUNCH, 0).let {
if (it.getBoolean(KEY_FIRST_LAUNCH, true)) {
it.edit().putBoolean(KEY_FIRST_LAUNCH, false).apply()
var needAsk = if (
this.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.RECEIVE_MMS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED
) {
true
} else false
getSharedPreferences(PREFS_FIRST_LAUNCH, 0).let {
if (it.getBoolean(KEY_FIRST_LAUNCH, true) || needAsk) {
it.edit().putBoolean(KEY_FIRST_LAUNCH, false).apply()
MaterialAlertDialogBuilder(this)
.setTitle(R.string.welcome)
.setMessage(R.string.welcome_description)
@ -140,8 +157,26 @@ internal class LauncherActivity : AppCompatActivity() {
/* ask for the permissions */
private fun askPermissions() {
/* phone permission */
if (this.checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED || this.checkSelfPermission(Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(arrayOf(Manifest.permission.CALL_PHONE,Manifest.permission.READ_SMS), 1)
if (
this.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.RECEIVE_MMS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED
) {
this.requestPermissions(arrayOf(
Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_SMS,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.RECEIVE_MMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.CALL_PHONE,
Manifest.permission.READ_SMS), 1)
}
/* modify system settings */
if (!Settings.System.canWrite(this)) {

View File

@ -194,13 +194,11 @@ internal class ContactMenu : BottomSheetDialogFragment() {
binding.phoneNumber.text = contactPhoneNumber
}
/* detailed info dialog */
@SuppressLint("SetTextI18n")
private fun detailedInfo() {
var intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + packageName));
startActivity(intent);
}
/* activity browser dialog */

View File

@ -0,0 +1,42 @@
package rasel.lunar.launcher.apps
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.databinding.ContactMenuBinding
class SmmsMenu: BottomSheetDialogFragment() {
private lateinit var binding: ContactMenuBinding
private lateinit var msgId: String
private lateinit var packageManager: PackageManager
private lateinit var appInfo: ApplicationInfo
private lateinit var defAppName: String
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = ContactMenuBinding.inflate(inflater, container, false)
/* get package name from fragment's tag */
msgId = tag.toString()
val resolver = lActivity!!.contentResolver
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(requireDialog() as BottomSheetDialog).dismissWithAnimation = true
}
}

View File

@ -25,12 +25,21 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.Color
import android.net.http.SslError
import android.os.Bundle
import android.provider.AlarmClock
import android.telephony.TelephonyManager
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.SslErrorHandler
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
@ -41,6 +50,11 @@ import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.google.gson.Gson
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import rasel.lunar.launcher.LauncherActivity.Companion.TEST_PAG
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.LauncherHomeBinding
@ -55,18 +69,28 @@ import rasel.lunar.launcher.helpers.UniUtils.Companion.biometricPromptInfo
import rasel.lunar.launcher.helpers.UniUtils.Companion.canAuthenticate
import rasel.lunar.launcher.helpers.UniUtils.Companion.expandNotificationPanel
import rasel.lunar.launcher.helpers.UniUtils.Companion.lockMethod
import rasel.lunar.launcher.home.LauncherHome.Companion.lastedFinishedPageUrl
import rasel.lunar.launcher.home.LauncherHome.Companion.listItem
import rasel.lunar.launcher.home.LauncherHome.Companion.listTags
import rasel.lunar.launcher.home.LauncherHome.Companion.refreshCalls
import rasel.lunar.launcher.home.LauncherHome.Companion.refreshSms
import rasel.lunar.launcher.home.weather.WeatherExecutor
import rasel.lunar.launcher.qaccess.QuickAccess
import rasel.lunar.launcher.settings.SettingsActivity
import rasel.lunar.launcher.todos.MissedCallsAdapter
import rasel.lunar.launcher.todos.RssItemAdapter
import rasel.lunar.launcher.todos.RssTagAdapter
import rasel.lunar.launcher.todos.SmsLogsAdapter
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.MissedCallGetter
import rasel.lunar.launcher.utils.RecentSmsGetter
import rasel.lunar.launcher.utils.RecentSmsLog
import rasel.lunar.launcher.utils.SimpleFingerGestures
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
@ -78,12 +102,32 @@ internal class LauncherHome : Fragment() {
private lateinit var batteryReceiver: BatteryReceiver
private var shouldResume = true
companion object {
val SMS_WORK_TAG = "RecentSmsGetter"
val CALL_WORK_TAG = "MissedCallGetter"
var lastedFinishedPageUrl : String = ""
private var mWorkManager: WorkManager? = null
var missedCalls = hashMapOf<String, MissedCall>()
var callList = arrayListOf<MissedCall>()
var smsList = arrayListOf<RecentSmsLog>()
var listTags = arrayListOf<RssTagItem>()
var listItem = arrayListOf<RssItem>()
fun refreshSms() {
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(SMS_WORK_TAG)
mWorkManager?.enqueue(PeriodicWorkRequestBuilder<RecentSmsGetter>(30, TimeUnit.MINUTES).addTag(SMS_WORK_TAG).build())
}, 2, TimeUnit.SECONDS)
}
fun refreshCalls() {
Executors.newSingleThreadScheduledExecutor().schedule({
mWorkManager?.cancelAllWorkByTag(CALL_WORK_TAG)
mWorkManager?.enqueueUniquePeriodicWork(CALL_WORK_TAG,ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,PeriodicWorkRequestBuilder<MissedCallGetter>(30, TimeUnit.MINUTES).addTag("MissedCallGetter").build())
}, 2, TimeUnit.SECONDS)
}
}
private val nReceiver: NotificationReceiver? = null
private var nReceiver: NotificationReceiver? = null
class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
@ -94,8 +138,15 @@ internal class LauncherHome : Fragment() {
// txtView.setText(temp)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
fun workmanager() : WorkManager? {
if (mWorkManager == null) {
mWorkManager = WorkManager.getInstance(requireContext())
}
return mWorkManager
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
mWorkManager = WorkManager.getInstance(requireContext())
binding = LauncherHomeBinding.inflate(inflater, container, false)
fragManager = lActivity!!.supportFragmentManager
settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0)
@ -103,13 +154,10 @@ internal class LauncherHome : Fragment() {
mMissedCallsAdapter = MissedCallsAdapter(callList, requireContext())
mSmsLogsAdapter = SmsLogsAdapter(smsList, requireContext())
binding.favAppsGroup.visibility = View.GONE
mWorkManager = WorkManager.getInstance(requireContext())
mWorkManager?.cancelAllWork()
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 {
workmanager()?.getWorkInfosByTagLiveData(SMS_WORK_TAG)?.observeForever {
binding.recentSms.text = "최근 문자 [${smsList.size}]"
if (binding.recentSms.isChecked) chooseAdpater()
else if (missedCalls.size == 0) {
@ -120,17 +168,20 @@ internal class LauncherHome : Fragment() {
it.clear()
}
mWorkManager?.getWorkInfosByTagLiveData("MissedCallGetter")?.observeForever {
workmanager()?.getWorkInfosByTagLiveData(CALL_WORK_TAG)?.observeForever {
binding.missedCalls.text = "최근 통화 [${missedCalls.size}]"
if (missedCalls.size > 0) binding.missedCalls.isChecked = true
if (binding.missedCalls.isChecked) chooseAdpater()
it.clear()
}
nReceiver = NotificationReceiver()
val filter = IntentFilter()
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
registerReceiver(requireContext(),nReceiver, filter,RECEIVER_EXPORTED)
BLog.LOGE("onCreateView()")
refreshSms()
refreshCalls()
return binding.root
}
@ -162,17 +213,74 @@ internal class LauncherHome : Fragment() {
binding.missedCalls.setOnClickListener {
binding.missedCalls.isChecked = true
BLog.LOGE("binding.missedCalls >> ${binding.missedCalls.isChecked}")
chooseAdpater()
}
binding.recentSms.setOnClickListener {
binding.recentSms.isChecked = true
chooseAdpater()
}
binding.otherCheck.setOnClickListener {
BLog.LOGE("binding.otherCheck before ThreadRun")
binding.searcher01.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
BLog.LOGE("binding.otherCheck searcher01 in onPageStarted ${url}")
super.onPageStarted(view, url, favicon)
}
override fun onReceivedSslError(
view: WebView?,
handler: SslErrorHandler?,
error: SslError?
) {
handler?.proceed()
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
lastedFinishedPageUrl = url ?: ""
BLog.LOGE("binding.otherCheck searcher01 in onPageFinished ${url}")
view?.evaluateJavascript("function getAll() {\n" +
" MyJavaScriptInterface.sendValueFromHtml(document.getElementsByTagName('html')[0].innerHTML)" +
" };getAll()") { result ->
(result as? String)?.let {
}
}
}
}
binding.searcher01.apply {
this.addJavascriptInterface(MyJavaScriptInterface(this),"MyJavaScriptInterface")
setBackgroundColor(Color.WHITE) // 백그라운드 색상 설정
setLayerType(View.LAYER_TYPE_SOFTWARE, null) // 랜더링 이슈 해결
try {
settings.apply {
javaScriptEnabled = true // 자바스크립트 사용 가능하도록 설정
loadWithOverviewMode = true // 전체 웹페이지를 화면에 맞게 로드
useWideViewPort = true // 화면에 맞게 페이지 확대/축소
domStorageEnabled = true // DOM 저장소 사용 가능하도록 설정
setSupportMultipleWindows(true)
javaScriptCanOpenWindowsAutomatically = true // 팝업창 차단 해제
cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
textZoom = 100 // system 에 의한 글꼴 변형 방지
defaultTextEncodingName = "UTF-8" // 인코딩 설정
allowContentAccess = true // 웹뷰를 통해 content url에 접근할지 여부
layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING // 웹페이지의 레이아웃을 화면에 맞게 자동으로 조정
}
} catch (ignore: NoSuchMethodError) {}
//TEST_PAG
loadUrl(TEST_PAG) // 웹페이지 연결
}
}
binding.summaryChoose.setOnCheckedChangeListener { group, checkedId ->
chooseAdpater()
}
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
// i.putExtra("command", "list")
// lActivity?.sendBroadcast(i)
// BLog.LOGE("intent >>> ${i.action}")
}
@ -181,12 +289,11 @@ internal class LauncherHome : Fragment() {
if (missedCalls.size > 0 && isAdded && isResumed && isVisible) {
try {
callList.clear()
BLog.LOGE("chooseAdpater callList >>> ${callList.size}")
BLog.LOGE("chooseAdpater callList missedCalls >>> ${missedCalls.values.size}")
binding.mainList.adapter = mMissedCallsAdapter
missedCalls.forEach { t, u ->
callList.add(u)
}.apply {
callList.sortByDescending { it.date }
mMissedCallsAdapter.updateData(callList)
}
} catch (e : Exception) {
@ -196,7 +303,6 @@ internal class LauncherHome : Fragment() {
} else if(binding.recentSms.isChecked){
if (smsList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("chooseAdpater smsList >>> ${smsList.size}")
binding.mainList.adapter = mSmsLogsAdapter
smsList.sortByDescending { it.rcvDate }
mSmsLogsAdapter.updateData(smsList)
@ -228,7 +334,7 @@ internal class LauncherHome : Fragment() {
}
}
private var mWorkManager: WorkManager? = null
@ -376,6 +482,81 @@ internal class LauncherHome : Fragment() {
}
inner class MyJavaScriptInterface(val webView: WebView) {
@JavascriptInterface
fun sendValueFromHtml(result: String) {
var htmlString = result.replace("\\u003","<")
val simpldateFormat = SimpleDateFormat("d MMM, yy",Locale.US)
val doc: Document = Jsoup.parse(htmlString)
// BLog.LOGE("binding.otherCheck in ThreadRun ${doc.body()}")
if(lastedFinishedPageUrl?.contains("page") == true || lastedFinishedPageUrl?.equals(TEST_PAG) == true) {
BLog.LOGE("do default parsing")
BLog.LOGE("SimpleDateFormat D MM yy => ${SimpleDateFormat("d MMM yy",Locale.US).format(Date())}")
val prevUrl = doc.getElementsByClass("prev").get(0).getElementsByAttribute("href").get(0).attr("href")
BLog.LOGE("doc.getElementsByClass(prev).get(0).html() ${prevUrl}")
doc.getElementsByClass("column").forEach {
var title = it.getElementsByAttribute("title").get(0).text()
var model = title.replace("[","").split("]")[0]
var pageLink = it.getElementsByClass("imgg").get(0).getElementsByAttribute("href").get(0).attr("href")
var imgg = it.getElementsByClass("imgg").get(0).getElementsByAttribute("src").get(0).attr("src")
var tags = it.getElementsByClass("tags").get(0).text()
var date = it.getElementsByClass("date").get(0).text()
listItem.add(RssItem(model = model, title = title, pageLink = pageLink, image = imgg, tags = tags, date = simpldateFormat.parse(date).time))
}.apply {
BLog.LOGE("listItem.size >>> ${listItem.size}")
if (prevUrl!=null && prevUrl.length > TEST_PAG.length && prevUrl.contains("/page/") && listItem.size < (24 * 5) ) {
BLog.LOGE("listItem.size >>> ${listItem.size} do next ")
webView.postDelayed({webView.loadUrl(prevUrl)}, 5000L)
if(binding.mainList.adapter is RssTagAdapter) {
binding.mainList?.post {
(binding.mainList.adapter as RssItemAdapter).apply {
updateData(listItem)
}
}
} else {
binding.mainList?.post {
binding.mainList.adapter = RssItemAdapter(listItem,requireContext()).apply {
updateData(listItem)
}
}
}
} else {
listTags.sortByDescending { it.count }
binding.mainList?.post {
(binding.mainList.adapter as RssItemAdapter).apply {
updateData(listItem)
}
}
}
}
} else if(lastedFinishedPageUrl?.contains("/tags/") == true ){
listTags.clear()
doc.getElementsByTag("ul").forEach {
it.children().forEach {
if (it.tag().name.contains("li")) {
listTags.add(
RssTagItem(
tagTitle = it.getElementsByTag("a").get(0).text(),
link = it.getElementsByTag("a").get(0).attr("href")
)
)
}
}
}.apply {
listTags.sortByDescending { it.count }
binding.mainList?.post {
binding.mainList.adapter = RssTagAdapter(listTags, requireContext()).apply {
updateData(listTags)
}
}
}
}
BLog.LOGE("binding.otherCheck after ThreadRun")
}
}
/* gestures on root view */
@SuppressLint("ClickableViewAccessibility")
private fun rootViewGestures() {
@ -554,4 +735,60 @@ class MissedCall {
return Gson().toJson(this)
}
}
class EndCallReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
BLog.LOGE("EndCallReceiver >>> ${intent}")
val phoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE) ?: return
if (phoneState == TelephonyManager.EXTRA_STATE_IDLE) {
refreshCalls()
}
}
}
class SMSReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
BLog.LOGE("SMSReceiver >>> ${intent}")
refreshSms()
}
}
class RssTagItem {
var link : String = ""
var tagTitle = ""
var count = 0
constructor(link: String, tagTitle: String) {
this.link = link
this.tagTitle = tagTitle
if (tagTitle.contains("(") && tagTitle.contains(")")) {
try {
count = tagTitle.split("(")[1].split(")")[0].toInt()
}catch (e : Exception) {}
}
}
}
class RssItem {
var model : String = ""
var title : String = ""
var pageLink : String = ""
var image : String = ""
var tags : String = ""
var date : Long = 0L
constructor(
model: String,
title: String,
pageLink: String,
image: String,
tags: String,
date: Long
) {
this.model = model
this.title = title
this.pageLink = pageLink
this.image = image
this.tags = tags
this.date = date
}
}

View File

@ -20,6 +20,9 @@ package rasel.lunar.launcher.todos
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.ContactsContract
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -35,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 rasel.lunar.launcher.utils.getContactId
import java.util.*
import kotlin.collections.ArrayList
@ -58,7 +62,6 @@ internal class MissedCallsAdapter(
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MissedCallsHolder, position: Int) {
val todo = callList[position]
BLog.LOGE("callList >>> ${callList[position]}")
holder.view.itemText.text = "\u25CF ${if(todo.name.equals("unknown")) todo.number else { todo.name}} , ${todo.typeString} : ${todo.count} : ${todo.date}"
/* multiline texts are enabled for TodoManager */
@ -67,7 +70,17 @@ internal class MissedCallsAdapter(
holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */
holder.view.itemText.setOnLongClickListener {
copyToClipboard(context, todo.name)
// copyToClipboard(context, todo.name)
var cId = getContactId(lActivity!!.contentResolver, todo.number)
if (cId != null && cId.length > 0) {
var intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + cId));
lActivity?.startActivity(intent);
} else {
lActivity?.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:${todo.number}")))
}
true
}

View File

@ -0,0 +1,134 @@
/*
* Lunar Launcher
* Copyright (C) 2022 Md Rasel Hossain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rasel.lunar.launcher.todos
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.ListItemBinding
import rasel.lunar.launcher.home.RssItem
import rasel.lunar.launcher.home.RssTagItem
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.RecentSmsLog
import java.text.SimpleDateFormat
import java.util.Date
internal class RssItemAdapter (
private val smsList: ArrayList<RssItem>,
private val context: Context) : RecyclerView.Adapter<RssItemAdapter.RssTag>() {
private val currentFragment = lActivity!!.supportFragmentManager.findFragmentById(R.id.mainFragmentsContainer)
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RssTag {
val binding = ListItemBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)
return RssTag(binding)
}
override fun getItemCount(): Int {
return smsList.size
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssTag, position: Int) {
val todo = smsList[position]
holder.view.itemText.text = "\u25CF ${Gson().toJson(todo)}"
/* multiline texts are enabled for TodoManager */
// holder.view.itemText.isSingleLine = false
/* launch edit or update dialog on item click */
// holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */
holder.view.itemText.setOnLongClickListener {
true
}
}
inner class RssTag(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root)
fun updateData(newList: List<RssItem>) {
val diffUtilResult = DiffUtil.calculateDiff(RssItemDiffUtil(smsList, newList))
diffUtilResult.dispatchUpdatesTo(this)
// smsList.clear()
// smsList.addAll(newList)
}
/* update dialog */
private fun updateDialog(position: Int) {
// val bottomSheetDialog = BottomSheetDialog(lActivity!!, R.style.BottomSheetDialog)
// val dialogBinding = TodoDialogBinding.inflate(LayoutInflater.from(context))
// bottomSheetDialog.setContentView(dialogBinding.root)
// bottomSheetDialog.show()
// bottomSheetDialog.dismissWithAnimation = true
//
// val databaseHandler = DatabaseHandler(context)
// val todo = databaseHandler.todos[position]
//
// dialogBinding.apply {
// deleteAllConfirmation.visibility = View.GONE
// todoInput.setText(todo.name)
// todoCancel.text = context.getString(R.string.delete)
// todoCancel.setTextColor(ContextCompat.getColor(context, android.R.color.holo_red_light))
// todoOk.text = context.getString(R.string.update)
// }
//
// /* delete the item */
// dialogBinding.todoCancel.setOnClickListener {
//
// }
//
// /* update the item */
// dialogBinding.todoOk.setOnClickListener {
// val updatedTodoString = Objects.requireNonNull(dialogBinding.todoInput.text).toString().trim { it <= ' ' }
// if (updatedTodoString.isNotEmpty()) {
// todo.name = updatedTodoString
// databaseHandler.updateTodo(todo)
// bottomSheetDialog.dismiss()
// } else {
// dialogBinding.todoInput.error = context.getString(R.string.empty_text_field)
// }
// }
}
}
internal class RssItemDiffUtil(
private val oldList: List<RssItem>, private val newList: List<RssItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].pageLink == newList[newItemPosition].pageLink
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].pageLink == newList[newItemPosition].pageLink
}

View File

@ -0,0 +1,133 @@
/*
* Lunar Launcher
* Copyright (C) 2022 Md Rasel Hossain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rasel.lunar.launcher.todos
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.ListItemBinding
import rasel.lunar.launcher.home.RssTagItem
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.RecentSmsLog
import java.text.SimpleDateFormat
import java.util.Date
internal class RssTagAdapter(
private val smsList: ArrayList<RssTagItem>,
private val context: Context) : RecyclerView.Adapter<RssTagAdapter.RssTag>() {
private val currentFragment = lActivity!!.supportFragmentManager.findFragmentById(R.id.mainFragmentsContainer)
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RssTag {
val binding = ListItemBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)
return RssTag(binding)
}
override fun getItemCount(): Int {
return smsList.size
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RssTag, position: Int) {
val todo = smsList[position]
holder.view.itemText.text = "\u25CF ${Gson().toJson(todo)}"
/* multiline texts are enabled for TodoManager */
// holder.view.itemText.isSingleLine = false
/* launch edit or update dialog on item click */
// holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */
holder.view.itemText.setOnLongClickListener {
true
}
}
inner class RssTag(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root)
fun updateData(newList: List<RssTagItem>) {
val diffUtilResult = DiffUtil.calculateDiff(RssTagDiffUtil(smsList, newList))
diffUtilResult.dispatchUpdatesTo(this)
// smsList.clear()
// smsList.addAll(newList)
}
/* update dialog */
private fun updateDialog(position: Int) {
// val bottomSheetDialog = BottomSheetDialog(lActivity!!, R.style.BottomSheetDialog)
// val dialogBinding = TodoDialogBinding.inflate(LayoutInflater.from(context))
// bottomSheetDialog.setContentView(dialogBinding.root)
// bottomSheetDialog.show()
// bottomSheetDialog.dismissWithAnimation = true
//
// val databaseHandler = DatabaseHandler(context)
// val todo = databaseHandler.todos[position]
//
// dialogBinding.apply {
// deleteAllConfirmation.visibility = View.GONE
// todoInput.setText(todo.name)
// todoCancel.text = context.getString(R.string.delete)
// todoCancel.setTextColor(ContextCompat.getColor(context, android.R.color.holo_red_light))
// todoOk.text = context.getString(R.string.update)
// }
//
// /* delete the item */
// dialogBinding.todoCancel.setOnClickListener {
//
// }
//
// /* update the item */
// dialogBinding.todoOk.setOnClickListener {
// val updatedTodoString = Objects.requireNonNull(dialogBinding.todoInput.text).toString().trim { it <= ' ' }
// if (updatedTodoString.isNotEmpty()) {
// todo.name = updatedTodoString
// databaseHandler.updateTodo(todo)
// bottomSheetDialog.dismiss()
// } else {
// dialogBinding.todoInput.error = context.getString(R.string.empty_text_field)
// }
// }
}
}
internal class RssTagDiffUtil(
private val oldList: List<RssTagItem>, private val newList: List<RssTagItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].link == newList[newItemPosition].link
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].link == newList[newItemPosition].link
}

View File

@ -20,28 +20,20 @@ package rasel.lunar.launcher.todos
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.apps.AppsAdapter.Companion.appsSize
import rasel.lunar.launcher.apps.AppsDiffUtil
import rasel.lunar.launcher.apps.Packages
import rasel.lunar.launcher.databinding.ListItemBinding
import rasel.lunar.launcher.databinding.TodoDialogBinding
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
import java.util.Date
internal class SmsLogsAdapter(
@ -56,24 +48,46 @@ internal class SmsLogsAdapter(
}
override fun getItemCount(): Int {
BLog.LOGE("SmsLogsAdapter smsList.size >>> ${smsList.size}")
return smsList.size
}
@SuppressLint("SetTextI18n")
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} : ${SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Date(Math.max(todo.pstDate.toLong(),todo.rcvDate.toLong())))} : ${todo.type}"
if(todo.isMms) {
var body = todo.mmsContents.get("text")?.joinToString("\n")?.replace("\n"," ")
body = if (body?.length ?: 0 > 60) body?.substring(0,60).plus("...") else body
holder.view.itemText.text = "\u25CF ${todo.person} ${todo.addr} , ${body} : ${
SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(
Date(
Math.max(
todo.pstDate.toLong(),
todo.rcvDate.toLong()
)
)
)
} : ${todo.type}"
} else {
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
/* launch edit or update dialog on item click */
// holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */
holder.view.itemText.setOnLongClickListener {
var intent = Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:" + Uri.encode(todo.addr)));
lActivity?.startActivity(intent);
true
}
@ -82,10 +96,8 @@ internal class SmsLogsAdapter(
inner class SmsLogHolder(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root)
fun updateData(newList: List<RecentSmsLog>) {
BLog.LOGE("SmsLogsAdapter smsList newList >> ${newList.size}")
val diffUtilResult = DiffUtil.calculateDiff(SmsDiffUtil(smsList, newList))
diffUtilResult.dispatchUpdatesTo(this)
BLog.LOGE("SmsLogsAdapter smsList smsList >> ${smsList.size}")
// smsList.clear()
// smsList.addAll(newList)
}

View File

@ -6,21 +6,23 @@ import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.CallLog
import android.provider.ContactsContract.PhoneLookup
import android.provider.Telephony
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.google.gson.Gson
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.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import kotlin.properties.Delegates
class MissedCallGetter : Worker {
@ -102,7 +104,7 @@ class MissedCallGetter : Worker {
SimpleDateFormat("yyy/MM/dd-HH:mm:ss").format(callDayTime)
)
}
BLog.LOGE("missed put >>> ${missed.toJson()}")
// BLog.LOGE("missed put >>> ${missed.toJson()}")
missedCalls.put(phNumber, missed)
}
@ -142,6 +144,7 @@ class RecentSmsGetter : Worker {
var dateParam = beforeDay(Date(),3).toString()
val managedCursor = lActivity?.contentResolver?.query(
Telephony.Sms.CONTENT_URI, arrayOf(
Telephony.Sms.THREAD_ID,
Telephony.Sms.ADDRESS,
Telephony.Sms.TYPE,
Telephony.Sms.DATE,
@ -152,6 +155,7 @@ class RecentSmsGetter : Worker {
if (managedCursor != null && managedCursor.isClosed == false) {
try {
smsList.clear()
val tid = managedCursor.getColumnIndex(Telephony.Sms.THREAD_ID)
val address = managedCursor.getColumnIndex(Telephony.Sms.ADDRESS)
val type = managedCursor.getColumnIndex(Telephony.Sms.TYPE)
val date = managedCursor.getColumnIndex(Telephony.Sms.DATE)
@ -159,6 +163,7 @@ class RecentSmsGetter : Worker {
val bodyIdx = managedCursor.getColumnIndex(Telephony.Sms.BODY)
val name = managedCursor.getColumnIndex(Telephony.Sms.PERSON)
while (managedCursor.moveToNext()) {
val id = managedCursor.getString(tid) // mobile number
val phNumber = managedCursor.getString(address) // mobile number
val callType = managedCursor.getString(type) // call type
val reciveDate = managedCursor.getString(date) // call date
@ -185,7 +190,10 @@ class RecentSmsGetter : Worker {
smsBody,
callerName ?: ""
)
BLog.LOGE("RecentSmsGetter resultData put ${phNumber +"_"+ reciveDate} >>> ${log.toJson()}")
log.id = id
log.isMms = false
// BLog.LOGE("RecentSmsGetter resultData put ${phNumber +"_"+ reciveDate} >>> ${log.toJson()}")
log.sender = getContactName(applicationContext.contentResolver,phNumber) ?: ""
smsList.add(log)
}
@ -205,12 +213,15 @@ class RecentSmsGetter : Worker {
class RecentSmsLog {
var id : String = ""
var isMms : Boolean = false
var addr : String = ""
var type : String = ""
var rcvDate : String = "0"
var pstDate : String = "0"
var body : String = ""
var person : String = ""
var mmsContents : HashMap<String?,ArrayList<String>> = hashMapOf()
var sender : String = ""
constructor(
addr: String,
@ -226,13 +237,15 @@ class RecentSmsLog {
this.pstDate = pstDate
this.body = body
this.person = person
this.isMms = false
}
constructor(id: String, sender: String, date: String, body: String) {
constructor(id: String, sender: String, date: String, body: HashMap<String?,ArrayList<String>>) {
this.id = id
this.rcvDate = date
this.body = body
this.mmsContents = body
this.addr = sender
this.isMms = true
}
fun toJson() : String {
@ -259,14 +272,17 @@ class TestQueryHelper(
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")
val body = getBody(id) ?: throw NullPointerException("NotFound Body by Mms")
return RecentSmsLog(
id = id.toString(),
date = date.toString(),
body = body,
sender = sender
)
).apply {
isMms = true
this.sender = getContactName(_contentResolver,addr) ?: ""
}
}
private fun getSender(id: Int): String? {
@ -286,7 +302,7 @@ class TestQueryHelper(
var sender = senderAddressCursor.getString(
senderAddressCursor.getColumnIndexOrThrow(Telephony.Mms.Addr.ADDRESS)
)
BLog.LOGE("sender >> ${sender}")
// BLog.LOGE("sender >> ${sender}")
if (isSender) {
return sender
}
@ -296,33 +312,103 @@ class TestQueryHelper(
return null
}
private fun getBody(id: Int): String? {
private fun getMmsText(id: String): String {
val partURI = Uri.parse("content://mms/part/$id")
var `is`: InputStream? = null
val sb = StringBuilder()
try {
`is` = _contentResolver.openInputStream(partURI)
if (`is` != null) {
val isr = InputStreamReader(`is`, "UTF-8")
val reader = BufferedReader(isr)
var temp = reader.readLine()
while (temp != null) {
sb.append(temp)
temp = reader.readLine()
BLog.LOGE("temp >>> ${temp}")
}
}
} catch (e: IOException) {
} finally {
if (`is` != null) {
try {
`is`.close()
} catch (e: IOException) {
}
}
}
BLog.LOGE("sb >>> ${sb.toString()}")
return sb.toString()
}
private fun getBody(id: Int): HashMap<String?,ArrayList<String>> {
var returns = hashMapOf<String?,ArrayList<String>>()
val text = arrayListOf<String>()
val image = arrayListOf<String>()
val audio = arrayListOf<String>()
val projection = arrayOf("*")
val video = arrayListOf<String>()
_contentResolver.query(
Uri.parse("content://mms/part"),
null,
projection,
"${Telephony.Mms.Part.MSG_ID} = ?",
arrayOf(id.toString()),
null
)?.use { partsCursor ->
if (partsCursor.moveToFirst()) {
do {
val partId: String = partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part._ID))
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}")
// BLog.LOGE("partContentType >> ${partContentType}")
return textBody
if(partContentType?.contains("text") == true) {
// BLog.LOGE("partContentType text >> ${partContentType} :: ${partId}")
val data =
partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part._DATA))
val textBody =
partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part.TEXT))
if (data != null && data.length > 0) {
text.add(getMmsText(partId))
} else {
text.add(textBody)
}
}
else if(partContentType?.contains("image") == true) {
// BLog.LOGE("partContentType image >> ${partContentType}:: ${partId}")
image.add(partId)
}
else if(partContentType?.contains("audio") == true) {
// BLog.LOGE("partContentType audio >> ${partContentType}:: ${partId}")
audio.add(partId)
}
else if(partContentType?.contains("video") == true) {
// BLog.LOGE("partContentType video >> ${partContentType}:: ${partId}")
video.add(partId)
}
else {
// BLog.LOGE("partContentType >> ${partContentType}:: ${partId}")
}
// 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 Pair(textBody , partContentType)
// }
} while (partsCursor.moveToNext())
}
}
return null
returns.put("text", text)
returns.put("image", image)
returns.put("audio", audio)
returns.put("video", video)
// BLog.LOGE("returns.get(text).join => ${text.size} :: ${text.joinToString("\n")}")
return returns
}
fun convertData(cursor: Cursor?) {
@ -342,4 +428,40 @@ class TestQueryHelper(
return convertData(cursor)
}
}
}
fun getContactName(contentResolver: ContentResolver, phoneNumber: String?): String? {
val cr = contentResolver
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber))
val cursor =
cr.query(uri, arrayOf(PhoneLookup.DISPLAY_NAME), null, null, null)
?: return null
var contactName: String? = null
if (cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndexOrThrow(PhoneLookup.DISPLAY_NAME))
}
if (cursor != null && !cursor.isClosed) {
cursor.close()
}
return contactName
}
fun getContactId(contentResolver: ContentResolver, phoneNumber: String?): String? {
val cr = contentResolver
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber))
val cursor =
cr.query(uri, arrayOf(PhoneLookup._ID), null, null, null)
?: return null
var contactName: String? = null
if (cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndexOrThrow(PhoneLookup._ID))
}
if (cursor != null && !cursor.isClosed) {
cursor.close()
}
return contactName
}

View File

@ -6,7 +6,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import com.google.gson.Gson
class NLService : NotificationListenerService() {
@ -17,7 +17,7 @@ class NLService : NotificationListenerService() {
super.onCreate()
nlservicereciver = NLServiceReceiver()
val filter = IntentFilter()
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
// filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
registerReceiver(nlservicereciver, filter)
}
@ -27,16 +27,16 @@ class NLService : NotificationListenerService() {
}
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.i(TAG, "********** onNotificationPosted")
Log.i(TAG, "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
BLog.LOGE( "********** onNotificationPosted")
BLog.LOGE("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)
BLog.LOGE(TAG, "********** onNOtificationRemoved")
BLog.LOGE( "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")
@ -45,22 +45,24 @@ class NLService : NotificationListenerService() {
internal inner class NLServiceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
BLog.LOGE("intent >>> ${intent.action}")
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)
// 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++
BLog.LOGE("sbn >>> ${sbn.packageName} , ${Gson().toJson(sbn.notification.extras.keySet())}")
// 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)
// val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i3.putExtra("notification_event", "===== Notification List ====")
// sendBroadcast(i3)
}
}
}

View File

@ -5,6 +5,26 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:layout_margin="30dp"
android:id="@+id/searcher_01"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp"
android:alpha="0.01"
android:layout_height="0dp"/>
<View
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp"
android:background="#11000000"
android:layout_height="0dp"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/batteryProgress"
@ -76,6 +96,7 @@
android:layout_height="40dp"
app:layout_constraintTop_toBottomOf="@+id/batteryProgress"
>
<RadioButton
android:id="@+id/missedCalls"
android:button="@null"
@ -85,7 +106,9 @@
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RadioButton
android:id="@+id/otherCheck"
android:gravity="center"
android:button="@null"
android:text="투두"
@ -93,6 +116,7 @@
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RadioButton
android:id="@+id/recentSms"
android:gravity="center"