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 ("androidx.work:work-runtime:2.9.1")
implementation ("com.google.code.gson:gson:2.11.0") implementation ("com.google.code.gson:gson:2.11.0")
implementation ("io.realm.kotlin:library-base:2.1.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.CALL_PHONE" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
@ -21,12 +22,19 @@
<uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!-- api 33+ --> <!-- api 33+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <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 <uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES" android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />
<uses-permission <uses-permission
android:name="android.permission.READ_SMS" android:name="android.permission.READ_SMS"
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />
<queries> <queries>
<intent> <intent>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -45,6 +53,7 @@
android:enableOnBackInvokedCallback="true" android:enableOnBackInvokedCallback="true"
android:largeHeap="true" android:largeHeap="true"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:usesCleartextTraffic="true"
android:screenOrientation="nosensor" android:screenOrientation="nosensor"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
@ -122,5 +131,19 @@
<action android:name="android.service.notification.NotificationListenerService" /> <action android:name="android.service.notification.NotificationListenerService" />
</intent-filter> </intent-filter>
</service> </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> </application>
</manifest> </manifest>

View File

@ -73,6 +73,9 @@ internal class LauncherActivity : AppCompatActivity() {
lateinit var viewPager: ViewPager2 lateinit var viewPager: ViewPager2
companion object { 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 lActivity: LauncherActivity? = null
@JvmStatic var appWidgetManager: AppWidgetManager? = null @JvmStatic var appWidgetManager: AppWidgetManager? = null
@JvmStatic var appWidgetHost: WidgetHost? = null @JvmStatic var appWidgetHost: WidgetHost? = null
@ -119,13 +122,27 @@ internal class LauncherActivity : AppCompatActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
BLog.LOGE("onResume") BLog.LOGE("onResume")
// askPermissions()
} }
private fun welcomeDialog() { 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) MaterialAlertDialogBuilder(this)
.setTitle(R.string.welcome) .setTitle(R.string.welcome)
.setMessage(R.string.welcome_description) .setMessage(R.string.welcome_description)
@ -140,8 +157,26 @@ internal class LauncherActivity : AppCompatActivity() {
/* ask for the permissions */ /* ask for the permissions */
private fun askPermissions() { private fun askPermissions() {
/* phone permission */ /* 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 */ /* modify system settings */
if (!Settings.System.canWrite(this)) { if (!Settings.System.canWrite(this)) {

View File

@ -194,13 +194,11 @@ internal class ContactMenu : BottomSheetDialogFragment() {
binding.phoneNumber.text = contactPhoneNumber binding.phoneNumber.text = contactPhoneNumber
} }
/* detailed info dialog */
@SuppressLint("SetTextI18n")
private fun detailedInfo() { private fun detailedInfo() {
var intent = Intent(Intent.ACTION_VIEW); var intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + packageName)); intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + packageName));
startActivity(intent); startActivity(intent);
} }
/* activity browser dialog */ /* 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.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.Color
import android.net.http.SslError
import android.os.Bundle import android.os.Bundle
import android.provider.AlarmClock import android.provider.AlarmClock
import android.telephony.TelephonyManager
import android.text.format.DateFormat import android.text.format.DateFormat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup 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 android.widget.Toast
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat.RECEIVER_EXPORTED import androidx.core.content.ContextCompat.RECEIVER_EXPORTED
@ -41,6 +50,11 @@ import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import com.google.gson.Gson 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.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.LauncherHomeBinding 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.canAuthenticate
import rasel.lunar.launcher.helpers.UniUtils.Companion.expandNotificationPanel import rasel.lunar.launcher.helpers.UniUtils.Companion.expandNotificationPanel
import rasel.lunar.launcher.helpers.UniUtils.Companion.lockMethod 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.home.weather.WeatherExecutor
import rasel.lunar.launcher.qaccess.QuickAccess import rasel.lunar.launcher.qaccess.QuickAccess
import rasel.lunar.launcher.settings.SettingsActivity import rasel.lunar.launcher.settings.SettingsActivity
import rasel.lunar.launcher.todos.MissedCallsAdapter 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.todos.SmsLogsAdapter
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.MissedCallGetter import rasel.lunar.launcher.utils.MissedCallGetter
import rasel.lunar.launcher.utils.RecentSmsGetter import rasel.lunar.launcher.utils.RecentSmsGetter
import rasel.lunar.launcher.utils.RecentSmsLog import rasel.lunar.launcher.utils.RecentSmsLog
import rasel.lunar.launcher.utils.SimpleFingerGestures import rasel.lunar.launcher.utils.SimpleFingerGestures
import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -78,12 +102,32 @@ internal class LauncherHome : Fragment() {
private lateinit var batteryReceiver: BatteryReceiver private lateinit var batteryReceiver: BatteryReceiver
private var shouldResume = true private var shouldResume = true
companion object { 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 missedCalls = hashMapOf<String, MissedCall>()
var callList = arrayListOf<MissedCall>() var callList = arrayListOf<MissedCall>()
var smsList = arrayListOf<RecentSmsLog>() 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() { class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) { override fun onReceive(context: Context?, intent: Intent) {
@ -94,8 +138,15 @@ internal class LauncherHome : Fragment() {
// txtView.setText(temp) // 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) binding = LauncherHomeBinding.inflate(inflater, container, false)
fragManager = lActivity!!.supportFragmentManager fragManager = lActivity!!.supportFragmentManager
settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0) settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0)
@ -103,13 +154,10 @@ internal class LauncherHome : Fragment() {
mMissedCallsAdapter = MissedCallsAdapter(callList, requireContext()) mMissedCallsAdapter = MissedCallsAdapter(callList, requireContext())
mSmsLogsAdapter = SmsLogsAdapter(smsList, requireContext()) mSmsLogsAdapter = SmsLogsAdapter(smsList, requireContext())
binding.favAppsGroup.visibility = View.GONE 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()) workmanager()?.getWorkInfosByTagLiveData(SMS_WORK_TAG)?.observeForever {
mWorkManager?.getWorkInfosByTagLiveData("RecentSmsGetter")?.observeForever {
binding.recentSms.text = "최근 문자 [${smsList.size}]" binding.recentSms.text = "최근 문자 [${smsList.size}]"
if (binding.recentSms.isChecked) chooseAdpater() if (binding.recentSms.isChecked) chooseAdpater()
else if (missedCalls.size == 0) { else if (missedCalls.size == 0) {
@ -120,17 +168,20 @@ internal class LauncherHome : Fragment() {
it.clear() it.clear()
} }
mWorkManager?.getWorkInfosByTagLiveData("MissedCallGetter")?.observeForever { workmanager()?.getWorkInfosByTagLiveData(CALL_WORK_TAG)?.observeForever {
binding.missedCalls.text = "최근 통화 [${missedCalls.size}]" binding.missedCalls.text = "최근 통화 [${missedCalls.size}]"
if (missedCalls.size > 0) binding.missedCalls.isChecked = true
if (binding.missedCalls.isChecked) chooseAdpater() if (binding.missedCalls.isChecked) chooseAdpater()
it.clear() it.clear()
} }
nReceiver = NotificationReceiver()
val filter = IntentFilter() 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) registerReceiver(requireContext(),nReceiver, filter,RECEIVER_EXPORTED)
BLog.LOGE("onCreateView()") BLog.LOGE("onCreateView()")
refreshSms()
refreshCalls()
return binding.root return binding.root
} }
@ -162,17 +213,74 @@ internal class LauncherHome : Fragment() {
binding.missedCalls.setOnClickListener { binding.missedCalls.setOnClickListener {
binding.missedCalls.isChecked = true binding.missedCalls.isChecked = true
BLog.LOGE("binding.missedCalls >> ${binding.missedCalls.isChecked}")
chooseAdpater() chooseAdpater()
} }
binding.recentSms.setOnClickListener { binding.recentSms.setOnClickListener {
binding.recentSms.isChecked = true binding.recentSms.isChecked = true
chooseAdpater() 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 -> binding.summaryChoose.setOnCheckedChangeListener { group, checkedId ->
chooseAdpater() 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) { if (missedCalls.size > 0 && isAdded && isResumed && isVisible) {
try { try {
callList.clear() callList.clear()
BLog.LOGE("chooseAdpater callList >>> ${callList.size}")
BLog.LOGE("chooseAdpater callList missedCalls >>> ${missedCalls.values.size}")
binding.mainList.adapter = mMissedCallsAdapter binding.mainList.adapter = mMissedCallsAdapter
missedCalls.forEach { t, u -> missedCalls.forEach { t, u ->
callList.add(u) callList.add(u)
}.apply { }.apply {
callList.sortByDescending { it.date }
mMissedCallsAdapter.updateData(callList) mMissedCallsAdapter.updateData(callList)
} }
} catch (e : Exception) { } catch (e : Exception) {
@ -196,7 +303,6 @@ internal class LauncherHome : Fragment() {
} else if(binding.recentSms.isChecked){ } else if(binding.recentSms.isChecked){
if (smsList.size > 0 && isAdded && isResumed && isVisible) { if (smsList.size > 0 && isAdded && isResumed && isVisible) {
try { try {
BLog.LOGE("chooseAdpater smsList >>> ${smsList.size}")
binding.mainList.adapter = mSmsLogsAdapter binding.mainList.adapter = mSmsLogsAdapter
smsList.sortByDescending { it.rcvDate } smsList.sortByDescending { it.rcvDate }
mSmsLogsAdapter.updateData(smsList) 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 */ /* gestures on root view */
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun rootViewGestures() { private fun rootViewGestures() {
@ -555,3 +736,59 @@ class MissedCall {
} }
} }
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.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.ContactsContract
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup 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.home.MissedCall
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.RecentSmsLog import rasel.lunar.launcher.utils.RecentSmsLog
import rasel.lunar.launcher.utils.getContactId
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -58,7 +62,6 @@ internal class MissedCallsAdapter(
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MissedCallsHolder, position: Int) { override fun onBindViewHolder(holder: MissedCallsHolder, position: Int) {
val todo = callList[position] 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}" 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 */ /* multiline texts are enabled for TodoManager */
@ -67,7 +70,17 @@ internal class MissedCallsAdapter(
holder.view.itemText.setOnClickListener { updateDialog(position) } holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */ /* copy texts on long click */
holder.view.itemText.setOnLongClickListener { 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 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.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R 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.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.BLog
import rasel.lunar.launcher.utils.RecentSmsLog import rasel.lunar.launcher.utils.RecentSmsLog
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import kotlin.collections.ArrayList
import kotlin.collections.List
internal class SmsLogsAdapter( internal class SmsLogsAdapter(
@ -56,24 +48,46 @@ internal class SmsLogsAdapter(
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
BLog.LOGE("SmsLogsAdapter smsList.size >>> ${smsList.size}")
return smsList.size return smsList.size
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: SmsLogHolder, position: Int) { override fun onBindViewHolder(holder: SmsLogHolder, position: Int) {
val todo = smsList[position] val todo = smsList[position]
BLog.LOGE("SmsLogsAdapter smsList >>> ${smsList[position]}") if(todo.isMms) {
var body = todo.mmsContents.get("text")?.joinToString("\n")?.replace("\n"," ")
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}" 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 */ /* multiline texts are enabled for TodoManager */
// holder.view.itemText.isSingleLine = false // holder.view.itemText.isSingleLine = false
/* launch edit or update dialog on item click */ /* launch edit or update dialog on item click */
// holder.view.itemText.setOnClickListener { updateDialog(position) } // holder.view.itemText.setOnClickListener { updateDialog(position) }
/* copy texts on long click */ /* copy texts on long click */
holder.view.itemText.setOnLongClickListener { holder.view.itemText.setOnLongClickListener {
var intent = Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:" + Uri.encode(todo.addr)));
lActivity?.startActivity(intent);
true true
} }
@ -82,10 +96,8 @@ internal class SmsLogsAdapter(
inner class SmsLogHolder(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root) inner class SmsLogHolder(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root)
fun updateData(newList: List<RecentSmsLog>) { fun updateData(newList: List<RecentSmsLog>) {
BLog.LOGE("SmsLogsAdapter smsList newList >> ${newList.size}")
val diffUtilResult = DiffUtil.calculateDiff(SmsDiffUtil(smsList, newList)) val diffUtilResult = DiffUtil.calculateDiff(SmsDiffUtil(smsList, newList))
diffUtilResult.dispatchUpdatesTo(this) diffUtilResult.dispatchUpdatesTo(this)
BLog.LOGE("SmsLogsAdapter smsList smsList >> ${smsList.size}")
// smsList.clear() // smsList.clear()
// smsList.addAll(newList) // smsList.addAll(newList)
} }

View File

@ -6,21 +6,23 @@ import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.CallLog import android.provider.CallLog
import android.provider.ContactsContract.PhoneLookup
import android.provider.Telephony import android.provider.Telephony
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.google.gson.Gson import com.google.gson.Gson
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.home.LauncherHome.Companion.missedCalls import rasel.lunar.launcher.home.LauncherHome.Companion.missedCalls
import rasel.lunar.launcher.home.LauncherHome.Companion.smsList import rasel.lunar.launcher.home.LauncherHome.Companion.smsList
import rasel.lunar.launcher.home.MissedCall import rasel.lunar.launcher.home.MissedCall
import java.io.BufferedReader import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import kotlin.properties.Delegates
class MissedCallGetter : Worker { class MissedCallGetter : Worker {
@ -102,7 +104,7 @@ class MissedCallGetter : Worker {
SimpleDateFormat("yyy/MM/dd-HH:mm:ss").format(callDayTime) 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) missedCalls.put(phNumber, missed)
} }
@ -142,6 +144,7 @@ class RecentSmsGetter : Worker {
var dateParam = beforeDay(Date(),3).toString() var dateParam = beforeDay(Date(),3).toString()
val managedCursor = lActivity?.contentResolver?.query( val managedCursor = lActivity?.contentResolver?.query(
Telephony.Sms.CONTENT_URI, arrayOf( Telephony.Sms.CONTENT_URI, arrayOf(
Telephony.Sms.THREAD_ID,
Telephony.Sms.ADDRESS, Telephony.Sms.ADDRESS,
Telephony.Sms.TYPE, Telephony.Sms.TYPE,
Telephony.Sms.DATE, Telephony.Sms.DATE,
@ -152,6 +155,7 @@ class RecentSmsGetter : Worker {
if (managedCursor != null && managedCursor.isClosed == false) { if (managedCursor != null && managedCursor.isClosed == false) {
try { try {
smsList.clear() smsList.clear()
val tid = managedCursor.getColumnIndex(Telephony.Sms.THREAD_ID)
val address = managedCursor.getColumnIndex(Telephony.Sms.ADDRESS) val address = managedCursor.getColumnIndex(Telephony.Sms.ADDRESS)
val type = managedCursor.getColumnIndex(Telephony.Sms.TYPE) val type = managedCursor.getColumnIndex(Telephony.Sms.TYPE)
val date = managedCursor.getColumnIndex(Telephony.Sms.DATE) val date = managedCursor.getColumnIndex(Telephony.Sms.DATE)
@ -159,6 +163,7 @@ class RecentSmsGetter : Worker {
val bodyIdx = managedCursor.getColumnIndex(Telephony.Sms.BODY) val bodyIdx = managedCursor.getColumnIndex(Telephony.Sms.BODY)
val name = managedCursor.getColumnIndex(Telephony.Sms.PERSON) val name = managedCursor.getColumnIndex(Telephony.Sms.PERSON)
while (managedCursor.moveToNext()) { while (managedCursor.moveToNext()) {
val id = managedCursor.getString(tid) // mobile number
val phNumber = managedCursor.getString(address) // mobile number val phNumber = managedCursor.getString(address) // mobile number
val callType = managedCursor.getString(type) // call type val callType = managedCursor.getString(type) // call type
val reciveDate = managedCursor.getString(date) // call date val reciveDate = managedCursor.getString(date) // call date
@ -185,7 +190,10 @@ class RecentSmsGetter : Worker {
smsBody, smsBody,
callerName ?: "" 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) smsList.add(log)
} }
@ -205,12 +213,15 @@ class RecentSmsGetter : Worker {
class RecentSmsLog { class RecentSmsLog {
var id : String = "" var id : String = ""
var isMms : Boolean = false
var addr : String = "" var addr : String = ""
var type : String = "" var type : String = ""
var rcvDate : String = "0" var rcvDate : String = "0"
var pstDate : String = "0" var pstDate : String = "0"
var body : String = "" var body : String = ""
var person : String = "" var person : String = ""
var mmsContents : HashMap<String?,ArrayList<String>> = hashMapOf()
var sender : String = ""
constructor( constructor(
addr: String, addr: String,
@ -226,13 +237,15 @@ class RecentSmsLog {
this.pstDate = pstDate this.pstDate = pstDate
this.body = body this.body = body
this.person = person 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.id = id
this.rcvDate = date this.rcvDate = date
this.body = body this.mmsContents = body
this.addr = sender this.addr = sender
this.isMms = true
} }
fun toJson() : String { fun toJson() : String {
@ -259,14 +272,17 @@ class TestQueryHelper(
val id = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Mms._ID)) val id = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Mms._ID))
val date = cursor.getLong(cursor.getColumnIndexOrThrow(Telephony.Mms.DATE)) * 1000 val date = cursor.getLong(cursor.getColumnIndexOrThrow(Telephony.Mms.DATE)) * 1000
val sender : String = getSender(id) ?: throw NullPointerException("NotFound Sender For Mms") 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( return RecentSmsLog(
id = id.toString(), id = id.toString(),
date = date.toString(), date = date.toString(),
body = body, body = body,
sender = sender sender = sender
) ).apply {
isMms = true
this.sender = getContactName(_contentResolver,addr) ?: ""
}
} }
private fun getSender(id: Int): String? { private fun getSender(id: Int): String? {
@ -286,7 +302,7 @@ class TestQueryHelper(
var sender = senderAddressCursor.getString( var sender = senderAddressCursor.getString(
senderAddressCursor.getColumnIndexOrThrow(Telephony.Mms.Addr.ADDRESS) senderAddressCursor.getColumnIndexOrThrow(Telephony.Mms.Addr.ADDRESS)
) )
BLog.LOGE("sender >> ${sender}") // BLog.LOGE("sender >> ${sender}")
if (isSender) { if (isSender) {
return sender return sender
} }
@ -296,33 +312,103 @@ class TestQueryHelper(
return null 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( _contentResolver.query(
Uri.parse("content://mms/part"), Uri.parse("content://mms/part"),
null, projection,
"${Telephony.Mms.Part.MSG_ID} = ?", "${Telephony.Mms.Part.MSG_ID} = ?",
arrayOf(id.toString()), arrayOf(id.toString()),
null null
)?.use { partsCursor -> )?.use { partsCursor ->
if (partsCursor.moveToFirst()) { if (partsCursor.moveToFirst()) {
do { do {
val partId: String = partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part._ID))
val partContentType = val partContentType =
partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part.CONTENT_TYPE)) partsCursor.getString(partsCursor.getColumnIndexOrThrow(Telephony.Mms.Part.CONTENT_TYPE))
if (partContentType == "text/plain") { // BLog.LOGE("partContentType >> ${partContentType}")
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 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()) } 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?) { fun convertData(cursor: Cursor?) {
@ -343,3 +429,39 @@ class TestQueryHelper(
} }
} }
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.content.IntentFilter
import android.service.notification.NotificationListenerService import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification import android.service.notification.StatusBarNotification
import android.util.Log import com.google.gson.Gson
class NLService : NotificationListenerService() { class NLService : NotificationListenerService() {
@ -17,7 +17,7 @@ class NLService : NotificationListenerService() {
super.onCreate() super.onCreate()
nlservicereciver = NLServiceReceiver() nlservicereciver = NLServiceReceiver()
val filter = IntentFilter() val filter = IntentFilter()
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE") // filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
registerReceiver(nlservicereciver, filter) registerReceiver(nlservicereciver, filter)
} }
@ -27,16 +27,16 @@ class NLService : NotificationListenerService() {
} }
override fun onNotificationPosted(sbn: StatusBarNotification) { override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.i(TAG, "********** onNotificationPosted") BLog.LOGE( "********** onNotificationPosted")
Log.i(TAG, "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName) BLog.LOGE("ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n") i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
sendBroadcast(i) sendBroadcast(i)
} }
override fun onNotificationRemoved(sbn: StatusBarNotification) { override fun onNotificationRemoved(sbn: StatusBarNotification) {
Log.i(TAG, "********** onNOtificationRemoved") BLog.LOGE(TAG, "********** onNOtificationRemoved")
Log.i(TAG, "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName) BLog.LOGE( "ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n") i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
@ -45,22 +45,24 @@ class NLService : NotificationListenerService() {
internal inner class NLServiceReceiver : BroadcastReceiver() { internal inner class NLServiceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) { override fun onReceive(context: Context?, intent: Intent) {
BLog.LOGE("intent >>> ${intent.action}")
if (intent.getStringExtra("command") == "clearall") { if (intent.getStringExtra("command") == "clearall") {
this@NLService.cancelAllNotifications() this@NLService.cancelAllNotifications()
} else if (intent.getStringExtra("command") == "list") { } else if (intent.getStringExtra("command") == "list") {
val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") // val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
i1.putExtra("notification_event", "=====================") // i1.putExtra("notification_event", "=====================")
sendBroadcast(i1) // sendBroadcast(i1)
var i = 1 var i = 1
for (sbn in this@NLService.activeNotifications) { for (sbn in this@NLService.activeNotifications) {
val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") BLog.LOGE("sbn >>> ${sbn.packageName} , ${Gson().toJson(sbn.notification.extras.keySet())}")
i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n") // val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
sendBroadcast(i2) // i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n")
i++ // sendBroadcast(i2)
// i++
} }
val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE") // val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
i3.putExtra("notification_event", "===== Notification List ====") // i3.putExtra("notification_event", "===== Notification List ====")
sendBroadcast(i3) // sendBroadcast(i3)
} }
} }
} }

View File

@ -5,6 +5,26 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="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 <com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/batteryProgress" android:id="@+id/batteryProgress"
@ -76,6 +96,7 @@
android:layout_height="40dp" android:layout_height="40dp"
app:layout_constraintTop_toBottomOf="@+id/batteryProgress" app:layout_constraintTop_toBottomOf="@+id/batteryProgress"
> >
<RadioButton <RadioButton
android:id="@+id/missedCalls" android:id="@+id/missedCalls"
android:button="@null" android:button="@null"
@ -85,7 +106,9 @@
android:layout_weight="1" android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<RadioButton <RadioButton
android:id="@+id/otherCheck"
android:gravity="center" android:gravity="center"
android:button="@null" android:button="@null"
android:text="투두" android:text="투두"
@ -93,6 +116,7 @@
android:layout_weight="1" android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<RadioButton <RadioButton
android:id="@+id/recentSms" android:id="@+id/recentSms"
android:gravity="center" android:gravity="center"