...
This commit is contained in:
parent
e61fa99c98
commit
16640559b3
@ -98,6 +98,11 @@ android {
|
|||||||
packagingOptions.resources.excludes.add("META-INF/*")
|
packagingOptions.resources.excludes.add("META-INF/*")
|
||||||
packagingOptions.resources.excludes.add("mozilla/*")
|
packagingOptions.resources.excludes.add("mozilla/*")
|
||||||
packagingOptions.resources.excludes.add("META-INF/*/*")
|
packagingOptions.resources.excludes.add("META-INF/*/*")
|
||||||
|
packagingOptions {
|
||||||
|
jniLibs {
|
||||||
|
useLegacyPackaging = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
|
|||||||
@ -23,7 +23,6 @@
|
|||||||
<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.RECEIVE_MMS" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
|
|
||||||
@ -46,6 +45,7 @@
|
|||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.READ_SMS"
|
android:name="android.permission.READ_SMS"
|
||||||
tools:ignore="QueryAllPackagesPermission" />
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
@ -58,18 +58,11 @@
|
|||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_CALL_LOG" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
|
|
||||||
<!-- <queries>-->
|
|
||||||
<!-- <intent>-->
|
|
||||||
<!-- <action android:name="android.intent.action.MAIN" />-->
|
|
||||||
<!-- </intent>-->
|
|
||||||
<!-- </queries>-->
|
|
||||||
<!-- <queries>-->
|
|
||||||
<!-- <intent>-->
|
|
||||||
<!-- <action android:name="android.intent.action.SEARCH" />-->
|
|
||||||
<!-- <category android:name="android.intent.category.DEFAULT" />-->
|
|
||||||
<!-- </intent>-->
|
|
||||||
<!-- </queries>-->
|
|
||||||
<application
|
<application
|
||||||
android:name=".LunaticLauncher"
|
android:name=".LunaticLauncher"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
@ -82,7 +75,6 @@
|
|||||||
android:enableOnBackInvokedCallback="true"
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:largeHeap="true"
|
android:largeHeap="true"
|
||||||
android:debuggable="false"
|
android:debuggable="false"
|
||||||
android:extractNativeLibs="true"
|
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
@ -139,29 +131,25 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
<receiver android:name=".receiver.CallReceiver" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.PHONE_STATE" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".receiver.SmsReceiver"
|
||||||
|
android:exported="true"> <intent-filter android:priority="2147483647">
|
||||||
|
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||||
|
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
|
||||||
|
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<!-- <activity-->
|
|
||||||
<!-- android:name=".SearchAbleActivity"-->
|
|
||||||
<!-- android:theme="@style/Theme.LunarLauncher.Starting"-->
|
|
||||||
<!-- android:launchMode="singleTop"-->
|
|
||||||
<!-- android:screenOrientation="userPortrait"-->
|
|
||||||
<!-- android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection|navigation"-->
|
|
||||||
<!-- android:windowSoftInputMode="adjustResize"-->
|
|
||||||
<!-- android:enabled="true"-->
|
|
||||||
<!-- android:exported="true">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.WEB_SEARCH"/>-->
|
|
||||||
<!-- <category android:name="android.intent.category.DEFAULT" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- <meta-data-->
|
|
||||||
<!-- android:name="android.app.searchable"-->
|
|
||||||
<!-- android:resource="@xml/searchable" />-->
|
|
||||||
<!-- </activity>-->
|
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".helpers.ForeGroundService"
|
android:name=".helpers.ForeGroundService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".wall.MyWallpaperService"
|
android:name=".wall.MyWallpaperService"
|
||||||
android:label="Bums Live Wallpaper"
|
android:label="Bums Live Wallpaper"
|
||||||
@ -173,16 +161,7 @@
|
|||||||
android:name="android.service.wallpaper"
|
android:name="android.service.wallpaper"
|
||||||
android:resource="@xml/wallpaper" />
|
android:resource="@xml/wallpaper" />
|
||||||
</service>
|
</service>
|
||||||
<!-- <activity-->
|
|
||||||
<!-- android:name=".apps.AppDrawer"-->
|
|
||||||
<!-- android:label="@string/lunar_settings"-->
|
|
||||||
<!-- android:launchMode="singleTask"-->
|
|
||||||
<!-- android:excludeFromRecents="true"-->
|
|
||||||
<!-- android:exported="true">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </activity>-->
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".home.tokiz.Settings"
|
android:name=".home.tokiz.Settings"
|
||||||
@ -202,85 +181,11 @@
|
|||||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- <activity-->
|
|
||||||
<!-- android:name=".behavior.Behavior"-->
|
|
||||||
<!-- android:label="@string/lunar_settings"-->
|
|
||||||
<!-- android:launchMode="singleTask"-->
|
|
||||||
<!-- android:excludeFromRecents="true"-->
|
|
||||||
<!-- android:exported="true">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </activity>-->
|
|
||||||
|
|
||||||
<!-- <receiver android:name=".helpers.HeadsetActionButtonReceiver"-->
|
<!-- <service-->
|
||||||
<!-- android:enabled="true"-->
|
<!-- android:name=".feeds.rss.RssService"-->
|
||||||
<!-- android:exported="true" >-->
|
<!-- android:permission="android.permission.BIND_JOB_SERVICE"-->
|
||||||
<!-- <intent-filter-->
|
<!-- android:exported="false"/>-->
|
||||||
<!-- android:priority="2147483647">-->
|
|
||||||
<!-- <action android:name="android.intent.action.MEDIA_BUTTON"/>-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </receiver>-->
|
|
||||||
|
|
||||||
<!-- <service android:name=".MediaButtonService"-->
|
|
||||||
<!-- android:exported="true">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.MEDIA_BUTTON" />-->
|
|
||||||
<!-- <action android:name="android.media.browse.MediaBrowserService" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </service>-->
|
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".feeds.rss.RssService"
|
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
|
||||||
android:exported="false"/>
|
|
||||||
|
|
||||||
<!-- <service-->
|
|
||||||
<!-- android:name=".helpers.LockService"-->
|
|
||||||
<!-- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"-->
|
|
||||||
<!-- android:exported="false">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.accessibilityservice.AccessibilityService" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- <meta-data-->
|
|
||||||
<!-- android:name="android.accessibilityservice"-->
|
|
||||||
<!-- android:resource="@xml/lock_service" />-->
|
|
||||||
<!-- </service>-->
|
|
||||||
|
|
||||||
<!-- <receiver-->
|
|
||||||
<!-- android:name=".helpers.AdminReceiver"-->
|
|
||||||
<!-- android:label="@string/app_name"-->
|
|
||||||
<!-- android:description="@string/device_admin_description"-->
|
|
||||||
<!-- android:permission="android.permission.BIND_DEVICE_ADMIN"-->
|
|
||||||
<!-- android:exported="false">-->
|
|
||||||
<!-- <meta-data-->
|
|
||||||
<!-- android:name="android.app.device_admin"-->
|
|
||||||
<!-- android:resource="@xml/device_admin" />-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </receiver>-->
|
|
||||||
|
|
||||||
<!-- <activity-->
|
|
||||||
<!-- android:name=".home.RssViewerActivity"-->
|
|
||||||
<!-- android:configChanges="keyboardHidden|orientation|screenSize"-->
|
|
||||||
<!-- android:hardwareAccelerated="true"-->
|
|
||||||
<!-- android:launchMode="singleTask"-->
|
|
||||||
<!-- android:exported="true"-->
|
|
||||||
<!-- android:excludeFromRecents="true"-->
|
|
||||||
<!-- android:theme="@style/FinestWebViewTheme.Fullscreen" >-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.VIEW" />-->
|
|
||||||
<!-- <category android:name="android.intent.category.DEFAULT" />-->
|
|
||||||
<!-- <data android:scheme="file"/>-->
|
|
||||||
<!-- <data android:scheme="content"/>-->
|
|
||||||
<!-- <data android:mimeType="text/html"/>-->
|
|
||||||
<!-- <data android:mimeType="text/plain"/>-->
|
|
||||||
<!-- <data android:mimeType="text/xml"/>-->
|
|
||||||
<!-- <data android:mimeType="application/xhtml+xml"/>-->
|
|
||||||
<!-- <data android:mimeType="application/vnd.wap.xhtml+xml"/>-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </activity>-->
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
@ -305,44 +210,5 @@
|
|||||||
|
|
||||||
<service android:name="bums.lunatic.launcher.workers.LocationUpdateService" />
|
<service android:name="bums.lunatic.launcher.workers.LocationUpdateService" />
|
||||||
|
|
||||||
<!-- <receiver android:name=".LauncherActivity$EndCallReceiver"-->
|
|
||||||
<!-- android:enabled="true"-->
|
|
||||||
<!-- android:exported="true">-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PHONE_STATE" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </receiver>-->
|
|
||||||
<!-- <receiver android:name=".LauncherActivity$SMSReceiver"-->
|
|
||||||
<!-- android:exported="true"-->
|
|
||||||
<!-- android:enabled="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>-->
|
|
||||||
|
|
||||||
<!-- <receiver-->
|
|
||||||
<!-- android:exported="true"-->
|
|
||||||
<!-- android:enabled="true"-->
|
|
||||||
<!-- android:name=".receiver.PackageEventReceiver"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <intent-filter>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_REPLACED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_INSTALL"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_ADDED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_CHANGED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_FIRST_LAUNCH"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_INSTALL"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_REMOVED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_REPLACED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"/>-->
|
|
||||||
<!-- <action android:name="android.intent.action.PACKAGE_VERIFIED"/>-->
|
|
||||||
<!-- <data android:scheme="package" />-->
|
|
||||||
<!-- </intent-filter>-->
|
|
||||||
<!-- </receiver>-->
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -10,6 +10,7 @@ import android.appwidget.AppWidgetManager
|
|||||||
import android.appwidget.AppWidgetProviderInfo
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -35,6 +36,7 @@ import android.view.View
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
@ -54,13 +56,11 @@ import bums.lunatic.launcher.home.NeoRssActivity
|
|||||||
import bums.lunatic.launcher.home.RssHome
|
import bums.lunatic.launcher.home.RssHome
|
||||||
import bums.lunatic.launcher.model.WidgetData
|
import bums.lunatic.launcher.model.WidgetData
|
||||||
import bums.lunatic.launcher.receiver.NLService
|
import bums.lunatic.launcher.receiver.NLService
|
||||||
|
import bums.lunatic.launcher.receiver.SmsReceiver
|
||||||
|
import bums.lunatic.launcher.settings.SettingsActivity
|
||||||
import bums.lunatic.launcher.utils.Blog
|
import bums.lunatic.launcher.utils.Blog
|
||||||
import bums.lunatic.launcher.workers.WorkersDb
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import bums.lunatic.launcher.workers.WorkersDb.syncSystemUsageStats
|
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import com.yausername.ffmpeg.FFmpeg
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDLException
|
|
||||||
import io.realm.kotlin.UpdatePolicy
|
import io.realm.kotlin.UpdatePolicy
|
||||||
import io.realm.kotlin.ext.query
|
import io.realm.kotlin.ext.query
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -135,10 +135,37 @@ open class LauncherActivity : CommonActivity() {
|
|||||||
|
|
||||||
// 4. 롱프레스 감지 (빈 공간)
|
// 4. 롱프레스 감지 (빈 공간)
|
||||||
override fun onLongPress(e: MotionEvent) {
|
override fun onLongPress(e: MotionEvent) {
|
||||||
// 위젯 추가 메뉴 등을 띄우려면 여기서 처리
|
// 1. 기기 화면의 전체 높이 가져오기 (Resources 사용)
|
||||||
// 주의: 위젯 위에서 롱프레스하면 위젯 드래그가 먼저 작동하도록 설계해야 함
|
val screenHeight = resources.displayMetrics.heightPixels
|
||||||
// showToast("바탕화면 롱프레스: 위젯 추가")
|
|
||||||
selectWidget() // 기존에 만든 위젯 추가 함수 호출
|
// 2. 롱프레스가 발생한 절대 Y 좌표
|
||||||
|
val touchY = e.rawY
|
||||||
|
|
||||||
|
// 3. 높이에 따른 분기 처리
|
||||||
|
when {
|
||||||
|
touchY < screenHeight / 3 -> {
|
||||||
|
// 상단 롱프레스 (0 ~ 33%)
|
||||||
|
handleTopLongPress()
|
||||||
|
}
|
||||||
|
touchY < (screenHeight / 3) * 2 -> {
|
||||||
|
// 중단 롱프레스 (33% ~ 66%)
|
||||||
|
selectWidget() // 기존 함수
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// 하단 롱프레스 (66% ~ 100%)
|
||||||
|
handleBottomLongPress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 각 구간별로 실행할 함수들 (예시)
|
||||||
|
private fun handleTopLongPress() {
|
||||||
|
// 상단 전용 기능
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleBottomLongPress() {
|
||||||
|
// 하단 전용 기능
|
||||||
|
startActivity(Intent(this@LauncherActivity, SettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
// onDown은 true를 반환해야 다른 제스처들이 시작됨
|
// onDown은 true를 반환해야 다른 제스처들이 시작됨
|
||||||
@ -406,10 +433,10 @@ open class LauncherActivity : CommonActivity() {
|
|||||||
restoreWidgets()
|
restoreWidgets()
|
||||||
|
|
||||||
// 3. 바탕화면 롱클릭 시 위젯 추가 메뉴 띄우기 (예시)
|
// 3. 바탕화면 롱클릭 시 위젯 추가 메뉴 띄우기 (예시)
|
||||||
binding.widgetContainer.setOnLongClickListener {
|
// binding.widgetContainer.setOnLongClickListener {
|
||||||
selectWidget()
|
// selectWidget()
|
||||||
true
|
// true
|
||||||
}
|
// }
|
||||||
scaleDetector = android.view.ScaleGestureDetector(this, object : android.view.ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
scaleDetector = android.view.ScaleGestureDetector(this, object : android.view.ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||||
override fun onScale(detector: android.view.ScaleGestureDetector): Boolean {
|
override fun onScale(detector: android.view.ScaleGestureDetector): Boolean {
|
||||||
currentDragView?.let { view ->
|
currentDragView?.let { view ->
|
||||||
@ -433,6 +460,41 @@ open class LauncherActivity : CommonActivity() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
requestSmsPermissionLauncher.launch(arrayOf(
|
||||||
|
android.Manifest.permission.RECEIVE_SMS,
|
||||||
|
android.Manifest.permission.READ_SMS
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
private var smsReceiver: SmsReceiver? = null
|
||||||
|
|
||||||
|
// 권한 요청 결과 처리기
|
||||||
|
private val requestSmsPermissionLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.RequestMultiplePermissions()
|
||||||
|
) { permissions ->
|
||||||
|
val granted = permissions[android.Manifest.permission.RECEIVE_SMS] ?: false
|
||||||
|
if (granted) {
|
||||||
|
Blog.LOGE("SMS 권한 승인됨 -> 리시버 동적 등록 실행")
|
||||||
|
registerSmsDynamicReceiver()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerSmsDynamicReceiver() {
|
||||||
|
if (smsReceiver == null) {
|
||||||
|
smsReceiver = SmsReceiver()
|
||||||
|
val filter = IntentFilter("android.provider.Telephony.SMS_RECEIVED").apply {
|
||||||
|
priority = 2147483647 // 시스템 최우선 순위
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android 14 이상(안드 16 포함) 필수 플래그: RECEIVER_EXPORTED
|
||||||
|
// 외부 앱(시스템 타워)으로부터 브로드캐스트를 받으려면 필수입니다.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
registerReceiver(smsReceiver, filter, Context.RECEIVER_EXPORTED)
|
||||||
|
} else {
|
||||||
|
registerReceiver(smsReceiver, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWidgetOptions(appWidgetId: Int, hostView: AppWidgetHostView) {
|
private fun updateWidgetOptions(appWidgetId: Int, hostView: AppWidgetHostView) {
|
||||||
@ -732,10 +794,14 @@ open class LauncherActivity : CommonActivity() {
|
|||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
appWidgetHost?.stopListening() // [필수] 여기서 리스닝 중지 (onDestroy 대신 여기 추천)
|
appWidgetHost?.stopListening() // [필수] 여기서 리스닝 중지 (onDestroy 대신 여기 추천)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
smsReceiver?.let {
|
||||||
|
unregisterReceiver(it)
|
||||||
|
smsReceiver = null
|
||||||
|
}
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -283,7 +283,7 @@ class AppDrawerBottomSheet : BottomSheetDialogFragment() {
|
|||||||
val pm = requireContext().packageManager
|
val pm = requireContext().packageManager
|
||||||
|
|
||||||
// 1. [추천 로직] 에러가 나도 앱 목록 로딩은 진행되도록 try-catch 분리
|
// 1. [추천 로직] 에러가 나도 앱 목록 로딩은 진행되도록 try-catch 분리
|
||||||
val scoredItems = WorkersDb.getContextualRecommendations(limit = 8)
|
val scoredItems = WorkersDb.getContextualRecommendations(limit = 18)
|
||||||
|
|
||||||
val unifiedList = mutableListOf<RecommendationItem>()
|
val unifiedList = mutableListOf<RecommendationItem>()
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
package bums.lunatic.launcher.apps;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64; // Java 기본 Base64 사용
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
@ -505,9 +505,7 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
.replace(R.id.fragment_container, BookmarkPagerFragment())
|
.replace(R.id.fragment_container, BookmarkPagerFragment())
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
R.id.setting ->{
|
|
||||||
startActivity(Intent(this, SettingsActivity::class.java))
|
|
||||||
}
|
|
||||||
R.id.close ->{
|
R.id.close ->{
|
||||||
supportFragmentManager.findFragmentById(R.id.fragment_container)?.let {
|
supportFragmentManager.findFragmentById(R.id.fragment_container)?.let {
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
|
|||||||
@ -27,4 +27,16 @@ class SimpleContact : RealmObject {
|
|||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return """
|
||||||
|
id : $id
|
||||||
|
name : $name
|
||||||
|
chosung : $chosung
|
||||||
|
phoneNumber : $phoneNumber
|
||||||
|
touchCount : $touchCount
|
||||||
|
lastedTouchDateTime : $lastedTouchDateTime
|
||||||
|
visibilityMode : $visibilityMode
|
||||||
|
blockRecommend : $blockRecommend
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
package bums.lunatic.launcher.receiver
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.telephony.SmsMessage
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import bums.lunatic.launcher.utils.Blog
|
||||||
|
import bums.lunatic.launcher.workers.UsageUpdateType
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
|
|
||||||
|
// 1. 전화 감지 리시버
|
||||||
|
class CallReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action == TelephonyManager.ACTION_PHONE_STATE_CHANGED) {
|
||||||
|
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
|
||||||
|
val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
|
||||||
|
|
||||||
|
// 전화 벨이 울릴 때 (수신)
|
||||||
|
if (state == TelephonyManager.EXTRA_STATE_RINGING && number != null) {
|
||||||
|
WorkersDb.logContactInteraction(number, UsageUpdateType.CALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 문자 감지 리시버
|
||||||
|
class SmsReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
// 1. 액션 수신 확인 로그
|
||||||
|
Blog.LOGE("SMS_RECEIVED 브로드캐스트 수신됨: ${intent.action}")
|
||||||
|
Toast.makeText(context, "문자 수신 신호 감지!", Toast.LENGTH_SHORT).show()
|
||||||
|
Blog.LOGE("Action: ${intent.action}")
|
||||||
|
|
||||||
|
if (intent.action == "android.provider.Telephony.SMS_RECEIVED") {
|
||||||
|
val bundle = intent.extras
|
||||||
|
val pdus = bundle?.get("pdus") as? Array<*>
|
||||||
|
// format이 null일 경우를 대비해 기본값 "3gpp"(GSM) 또는 "3gpp2"(CDMA) 처리
|
||||||
|
val format = bundle?.getString("format") ?: "3gpp"
|
||||||
|
|
||||||
|
if (pdus != null) {
|
||||||
|
for (pdu in pdus) {
|
||||||
|
try {
|
||||||
|
val sms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
SmsMessage.createFromPdu(pdu as ByteArray, format)
|
||||||
|
} else {
|
||||||
|
SmsMessage.createFromPdu(pdu as ByteArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
val senderNumber = sms.originatingAddress
|
||||||
|
Blog.LOGE("수신된 번호: $senderNumber")
|
||||||
|
|
||||||
|
if (senderNumber != null) {
|
||||||
|
WorkersDb.logContactInteraction(senderNumber, UsageUpdateType.SMS)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Blog.LOGE("SMS 파싱 오류: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Blog.LOGE("SMS 데이터(pdus)가 null입니다.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import android.content.IntentFilter
|
|||||||
import android.location.Geocoder
|
import android.location.Geocoder
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.provider.ContactsContract
|
||||||
import android.service.notification.NotificationListenerService
|
import android.service.notification.NotificationListenerService
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
@ -21,6 +22,8 @@ import bums.lunatic.launcher.helpers.ForeGroundService.Companion.EXTRA_MSGKEY
|
|||||||
import bums.lunatic.launcher.helpers.PrefBoolean
|
import bums.lunatic.launcher.helpers.PrefBoolean
|
||||||
import bums.lunatic.launcher.utils.Blog
|
import bums.lunatic.launcher.utils.Blog
|
||||||
import bums.lunatic.launcher.utils.KakaoPublicTransfer
|
import bums.lunatic.launcher.utils.KakaoPublicTransfer
|
||||||
|
import bums.lunatic.launcher.workers.UsageUpdateType
|
||||||
|
import bums.lunatic.launcher.workers.WorkersDb
|
||||||
import com.google.android.gms.location.LocationServices
|
import com.google.android.gms.location.LocationServices
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -69,10 +72,33 @@ class NLService : NotificationListenerService() {
|
|||||||
stringBuffer.append(conversationTitle).append("\n")
|
stringBuffer.append(conversationTitle).append("\n")
|
||||||
stringBuffer.append(summaryText).append("\n")
|
stringBuffer.append(summaryText).append("\n")
|
||||||
stringBuffer.append(verificationText).append("\n")
|
stringBuffer.append(verificationText).append("\n")
|
||||||
// Blog.LOGE("title >> ${title} text >> ${text} bigText >> ${bigText} extraInfo >> ${extraInfo} subText >> ${subText} conversationTitle >> ${conversationTitle} summaryText >> ${summaryText} verificationText >> ${verificationText}")
|
|
||||||
mHourlyLogWriter?.writeLog("${sbn.packageName}\n${stringBuffer.toString()}")
|
if (sbn.packageName == "com.samsung.android.messaging" || sbn.packageName == "com.google.android.apps.messaging") {
|
||||||
|
val extras = sbn.notification.extras
|
||||||
|
val title = extras.getString(Notification.EXTRA_TITLE) ?: return
|
||||||
|
val cleanTitle = sanitizeIdentifier(title)
|
||||||
|
if (cleanTitle.isEmpty()) return
|
||||||
|
// 1. 제목이 숫자인지 확인 (정규식: 숫자, +, - 만 포함된 경우)
|
||||||
|
val isNumber = cleanTitle.matches(Regex("^[0-9+\\- ]+$"))
|
||||||
|
|
||||||
|
if (isNumber) {
|
||||||
|
// 번호가 바로 왔을 때
|
||||||
|
WorkersDb.logContactInteraction(cleanTitle, UsageUpdateType.SMS)
|
||||||
|
} else {
|
||||||
|
// 이름이 왔을 때 -> 주소록에서 번호 조회
|
||||||
|
val foundNumber = getPhoneNumberByName(applicationContext, cleanTitle)
|
||||||
|
if (foundNumber != null) {
|
||||||
|
Blog.LOGE("이름($title)으로 번호($foundNumber) 조회 성공")
|
||||||
|
WorkersDb.logContactInteraction(foundNumber, UsageUpdateType.SMS)
|
||||||
|
} else {
|
||||||
|
// 주소록에도 없는 이름일 경우 (이름 자체로 로그를 남기려면 WorkersDb 수정 필요)
|
||||||
|
Blog.LOGE("주소록에서 찾을 수 없는 이름: $title")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
when (sbn.packageName) {
|
when (sbn.packageName) {
|
||||||
"com.kakao.taxi" -> {
|
"com.kakao.taxi" -> {
|
||||||
|
Blog.LOGE("packageName ${sbn.packageName} :::: title >> ${title} text >> ${text} bigText >> ${bigText} extraInfo >> ${extraInfo} subText >> ${subText} conversationTitle >> ${conversationTitle} summaryText >> ${summaryText} verificationText >> ${verificationText}")
|
||||||
var defaultMsg: StringBuffer? = StringBuffer("돼지 택시 ")
|
var defaultMsg: StringBuffer? = StringBuffer("돼지 택시 ")
|
||||||
if (stringBuffer.contains("택시") && stringBuffer.contains("탑승") && stringBuffer.contains(
|
if (stringBuffer.contains("택시") && stringBuffer.contains("탑승") && stringBuffer.contains(
|
||||||
"완료"
|
"완료"
|
||||||
@ -128,6 +154,35 @@ class NLService : NotificationListenerService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sanitizeIdentifier(input: String): String {
|
||||||
|
// 1. 한글(가-힣), 초성(ㄱ-ㅎ), 숫자(0-9), 영문(a-zA-Z)만 남기고 모두 제거
|
||||||
|
val regex = Regex("[^가-힣ㄱ-ㅎ0-9a-zA-Z]")
|
||||||
|
val cleaned = input.replace(regex, "").trim()
|
||||||
|
|
||||||
|
Blog.LOGE("정제 전: [$input] -> 정제 후: [$cleaned]")
|
||||||
|
return cleaned
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPhoneNumberByName(context: Context, name: String): String? {
|
||||||
|
val contentResolver = context.contentResolver
|
||||||
|
|
||||||
|
// 이름의 일부라도 포함되어 있는지 검색 (%name%)
|
||||||
|
val cursor = contentResolver.query(
|
||||||
|
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
|
||||||
|
arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER),
|
||||||
|
"${ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME} LIKE ?",
|
||||||
|
arrayOf("%$name%"),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
cursor?.use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
return it.getString(0).replace(Regex("[^0-9]"), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
|
@RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
|
||||||
fun makeMsgByTransferInfomation(stringBuffer : StringBuffer) {
|
fun makeMsgByTransferInfomation(stringBuffer : StringBuffer) {
|
||||||
val actionIntent = Intent(this, ForeGroundService::class.java).apply {
|
val actionIntent = Intent(this, ForeGroundService::class.java).apply {
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class CustMigration : AutomaticSchemaMigration {
|
|||||||
|
|
||||||
data class ScoredItem(val key: String, val type: String, val score: Double)
|
data class ScoredItem(val key: String, val type: String, val score: Double)
|
||||||
enum class UsageLogType { APP, CONTACT };
|
enum class UsageLogType { APP, CONTACT };
|
||||||
enum class UsageUpdateType { JC, COUNT, DATETIME };
|
enum class UsageUpdateType { JC, COUNT, DATETIME,CALL, SMS };
|
||||||
object WorkersDb {
|
object WorkersDb {
|
||||||
|
|
||||||
//RecentCall::class, RecentSms::class,
|
//RecentCall::class, RecentSms::class,
|
||||||
@ -141,8 +141,51 @@ object WorkersDb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun logContactInteraction(phoneNumber: String, updateType: UsageUpdateType) {
|
||||||
|
val realm = getRealm()
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
|
||||||
|
// 전화번호에서 하이픈 제거 등 포맷 정리 (DB 저장 형식에 맞춤)
|
||||||
|
val normalizedNumber = phoneNumber.replace("-", "").replace(" ", "")
|
||||||
|
|
||||||
|
realm.writeBlocking {
|
||||||
|
// 1. 전화번호로 해당 연락처 찾기 (SimpleContact에 phone 필드가 있다고 가정)
|
||||||
|
val contact = query<SimpleContact>("phoneNumber == $0", normalizedNumber).first().find()
|
||||||
|
|
||||||
|
if (contact != null) {
|
||||||
|
val key = contact.id // 추천 시스템에서 사용하는 키값
|
||||||
|
Blog.LOGE("contact >>> ${contact}")
|
||||||
|
when (updateType) {
|
||||||
|
UsageUpdateType.CALL -> {
|
||||||
|
contact.touchCount += 20 // 통화는 가중치를 더 높게 설정
|
||||||
|
contact.lastedTouchDateTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
UsageUpdateType.SMS -> {
|
||||||
|
contact.touchCount += 10 // 문자는 중간 정도
|
||||||
|
contact.lastedTouchDateTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
contact.touchCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key?.let { key ->
|
||||||
|
// 2. 추천 시스템이 사용하는 AppUsageLog에도 기록 추가
|
||||||
|
copyToRealm(AppUsageLog().apply {
|
||||||
|
itemKey = key
|
||||||
|
itemType = UsageLogType.CONTACT.name
|
||||||
|
timestamp = System.currentTimeMillis()
|
||||||
|
month = calendar.get(Calendar.MONTH)
|
||||||
|
dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH)
|
||||||
|
dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)
|
||||||
|
hour = calendar.get(Calendar.HOUR_OF_DAY)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// [핵심] 현재 시간 상황에 맞는 추천 리스트 가져오기
|
// [핵심] 현재 시간 상황에 맞는 추천 리스트 가져오기
|
||||||
fun getContextualRecommendations(limit: Int = 10): List<ScoredItem> {
|
fun getContextualRecommendations(limit: Int = 18): List<ScoredItem> {
|
||||||
val realm = getRealm()
|
val realm = getRealm()
|
||||||
val calendar = Calendar.getInstance()
|
val calendar = Calendar.getInstance()
|
||||||
|
|
||||||
|
|||||||
@ -152,14 +152,6 @@
|
|||||||
android:layout_height="20dp"/>
|
android:layout_height="20dp"/>
|
||||||
|
|
||||||
|
|
||||||
<bums.lunatic.launcher.view.FloatingActionButton
|
|
||||||
app:fab_label="setting"
|
|
||||||
android:id="@+id/setting"
|
|
||||||
app:fab_showShadow="true"
|
|
||||||
app:fab_size="mini"
|
|
||||||
android:onClick="floatClick"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="20dp"/>
|
|
||||||
|
|
||||||
<bums.lunatic.launcher.view.FloatingActionButton
|
<bums.lunatic.launcher.view.FloatingActionButton
|
||||||
app:fab_label="close"
|
app:fab_label="close"
|
||||||
|
|||||||
@ -13,8 +13,8 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
val kotlinVersion: String by extra
|
val kotlinVersion: String by extra
|
||||||
id ("com.android.application") version "8.6.0" apply false
|
id ("com.android.application") version "8.10.1" apply false
|
||||||
id ("com.android.library") version "8.6.0" apply false
|
id ("com.android.library") version "8.10.1" apply false
|
||||||
id ("io.realm.kotlin") version "2.0.0" apply false
|
id ("io.realm.kotlin") version "2.0.0" apply false
|
||||||
id("org.jetbrains.kotlin.android") version kotlinVersion apply false
|
id("org.jetbrains.kotlin.android") version kotlinVersion apply false
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user