This commit is contained in:
lunaticbum 2025-08-20 17:08:17 +09:00
parent f7f71ca195
commit 2f63f8550a
14 changed files with 686 additions and 393 deletions

View File

@ -120,7 +120,9 @@ dependencies {
// implementation("org.opencv:opencv-android:4.11.0")
// build.gradle에 추가
// implementation ("com.github.aeonSolutions:FloatingActionButtonMenuDrag:1.1")
implementation("io.github.junkfood02.youtubedl-android:library:0.17.4")
implementation("io.github.junkfood02.youtubedl-android:ffmpeg:0.17.4")
implementation("io.github.junkfood02.youtubedl-android:aria2c:0.17.4")
implementation ("androidx.media:media:1.7.0")

View File

@ -57,17 +57,17 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- <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>-->
<!-- <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
android:name=".LunaticLauncher"
android:icon="@drawable/ic_launcher"
@ -79,6 +79,7 @@
android:stateNotNeeded="true"
android:enableOnBackInvokedCallback="true"
android:largeHeap="true"
android:extractNativeLibs="true"
android:networkSecurityConfig="@xml/network_security_config"
android:hardwareAccelerated="true"
android:usesCleartextTraffic="true"
@ -90,7 +91,7 @@
<!-- android:excludeFromRecents="true"-->
<!-- portrait|reversePortrait|userPortrait|sensorPortrait-->
<!-- portrait|reversePortrait|userPortrait|sensorPortrait-->
<activity
android:name=".LauncherActivity"
android:theme="@style/Theme.LunarLauncher.Starting"
@ -117,26 +118,26 @@
</intent-filter>
</activity>
<!-- <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>-->
<!-- <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
android:name=".helpers.BluetoothManager"
android:name=".helpers.ForeGroundService"
android:enabled="true"
android:exported="false" />
<service
@ -150,16 +151,16 @@
android:name="android.service.wallpaper"
android:resource="@xml/wallpaper" />
</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-->
<!-- 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
android:name=".tokiz.Settings"
@ -169,35 +170,35 @@
android:exported="true">
</activity>
<!-- <activity-->
<!-- android:name=".settings.SettingsActivity"-->
<!-- 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-->
<!-- 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>-->
<activity
android:name=".settings.SettingsActivity"
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-->
<!-- 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"-->
<!-- android:enabled="true"-->
<!-- android:exported="true" >-->
<!-- <intent-filter-->
<!-- android:priority="2147483647">-->
<!-- <action android:name="android.intent.action.MEDIA_BUTTON"/>-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <receiver android:name=".helpers.HeadsetActionButtonReceiver"-->
<!-- android:enabled="true"-->
<!-- android:exported="true" >-->
<!-- <intent-filter-->
<!-- android:priority="2147483647">-->
<!-- <action android:name="android.intent.action.MEDIA_BUTTON"/>-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<!-- <service android:name=".MediaButtonService"-->
<!-- android:exported="true">-->
@ -212,52 +213,52 @@
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>-->
<!-- <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>-->
<!-- <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>-->
<!-- <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
android:name="androidx.core.content.FileProvider"
@ -269,55 +270,57 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- <service android:name=".receiver.NLService"-->
<!-- android:label="@string/app_name"-->
<!-- android:enabled="true"-->
<!-- android:exported="true"-->
<!-- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">-->
<!-- <intent-filter>-->
<!-- <action android:name="android.service.notification.NotificationListenerService" />-->
<!-- </intent-filter>-->
<!-- </service>-->
<!-- <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>-->
<service android:name=".receiver.NLService"
android:label="@string/app_name"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<!-- <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>-->
<!-- <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>
</manifest>

View File

@ -253,9 +253,16 @@ document.addEventListener('DOMContentLoaded', function () {
if (port) {
sendMessage({type: "MSG", msg: "connect prot"});
time1 = setTimeout(autoScrollAndSave(false), 3500)
}
})
document.addEventListener('touchstart', function(e) {
console.log('터치 시작');
});
document.addEventListener('touchend', function(e) {
autoScrollAndSave()
});
function scrollToLazyImg(fastMode) {
(function(autoScrollAndSave){
@ -346,12 +353,16 @@ function isNewerThanOneDay(dateStr) {
function autoScrollAndSave(senContents) {
// 도메인에 맞는 handler 실행
const matchedRule = domainRules.find(rule => rule.test(location.href));
if (matchedRule) {
matchedRule.handler();
}
try {
if (matchedRule) {
matchedRule.handler();
}
}catch (e) { }
try {
// 공통 광고 요소 제거는 항상 실행
handleCommon();
window.scrollTo({ top: 2, behavior: 'smooth' });
}catch (e) { }
if (mainContentsEl == null) {
mainContentsEl = document.body.outerHTML
}
@ -545,7 +556,11 @@ function handleCommon() {
gotoNext()
}
window.scrollTo({ top: 2, behavior: 'smooth' });
if (window.scrollY < 5) {
console.log("window.scrollY >>> " + window.scrollY)
window.scrollTo({ top: 5, behavior: 'smooth' });
}
}
function handleToreentZota() {
if (location.href.search("torrentzota") > -1 && document.querySelectorAll('a')) {
@ -759,13 +774,26 @@ function handleDoctorsnews() {
}
function handleDcinside() {
document.querySelectorAll(
'[id^="view_btn_area"], [class^="trend-rank"], [class^="view-btm-con"], [class^="md-tit-box"], [class^="gall-detail-lst"], [class^="outside-search-box"], [class^="footer ftlong"], [class^="adv-group"], li[style^="cursor:default;"], [id^="div_adnmore_area"]'
).forEach(e => e.remove());
document.querySelectorAll('div[class^="imgwrap"]').forEach(function (e) {
try {e.style.backgroundColor = 'red';} catch (e) {}
})
try {
document.querySelectorAll(
'[id^="view_btn_area"], [class^="trend-rank"], [class^="view-btm-con"], [class^="md-tit-box"], [class^="gall-detail-lst"], [class^="outside-search-box"], [class^="footer ftlong"], [class^="adv-group"], li[style^="cursor:default;"], [id^="div_adnmore_area"]'
).forEach(e => e.remove());
}catch (e) {
}
try {
document.querySelectorAll('div[class^="imgwrap"]').forEach(function (e) {
try {e.style.backgroundColor = 'red';} catch (e) {}
})
} catch (e) {
}
try {
document.querySelectorAll('div[class^="imgwrap"]')[0].click()
}catch (e) {
}
mainContentsEl = document.querySelector('div[class="container"]');
}

View File

@ -22,13 +22,11 @@ package bums.lunatic.launcher
import android.annotation.SuppressLint
import android.app.SearchManager
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.Rect
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -49,89 +47,50 @@ import android.view.PointerIcon
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.Button
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.apps.AppDrawer
import bums.lunatic.launcher.tokiz.Novels
import bums.lunatic.launcher.common.CommonActivity
import bums.lunatic.launcher.databinding.LauncherActivityBinding
import bums.lunatic.launcher.feeds.WidgetHost
import bums.lunatic.launcher.helpers.BluetoothManager
import bums.lunatic.launcher.helpers.Constants.Companion.KEY_STATUS_BAR
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
import bums.lunatic.launcher.helpers.Constants.Companion.widgetHostId
import bums.lunatic.launcher.helpers.ForeGroundService
import bums.lunatic.launcher.helpers.HeadsetActionButtonReceiver
import bums.lunatic.launcher.helpers.PrefHelper.putString
import bums.lunatic.launcher.helpers.PrefLong
import bums.lunatic.launcher.home.GeckoWeb
import bums.lunatic.launcher.home.RssHome
import bums.lunatic.launcher.home.RssViewBuilder
import bums.lunatic.launcher.model.RssData
import bums.lunatic.launcher.model.RssDataType
import bums.lunatic.launcher.receiver.NLService
import bums.lunatic.launcher.settings.SettingsActivity
import bums.lunatic.launcher.tokiz.Comics
import bums.lunatic.launcher.tokiz.Magnet
import bums.lunatic.launcher.tokiz.Novels
import bums.lunatic.launcher.tokiz.Perplexity
import bums.lunatic.launcher.tokiz.Twitter
import bums.lunatic.launcher.tokiz.Webtoons
import bums.lunatic.launcher.tokiz.Zota
import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.utils.FeedParseManager
import bums.lunatic.launcher.utils.getJ
import bums.lunatic.launcher.workers.AppInfoGetter
import bums.lunatic.launcher.workers.ArcaGetter
import bums.lunatic.launcher.workers.CalendarGetter
import bums.lunatic.launcher.workers.ClienGetter
import bums.lunatic.launcher.workers.ContactInfoGetter
import bums.lunatic.launcher.workers.DCGetter
import bums.lunatic.launcher.workers.DotaxGetter
import bums.lunatic.launcher.workers.DotaxGetter.Companion.COMIC2_WORK_TAG
import bums.lunatic.launcher.workers.FmKoreaGetter
import bums.lunatic.launcher.workers.FmKoreaGetter.Companion.FM_WORK_TAG
import bums.lunatic.launcher.workers.LocationGetter
import bums.lunatic.launcher.workers.NewsFeedsGetter
import bums.lunatic.launcher.workers.NewsFeedsGetter.Companion.FEDDS_WORK_TAG
import bums.lunatic.launcher.workers.RecentCallGetter
import bums.lunatic.launcher.workers.RecentSmsGetter
import bums.lunatic.launcher.workers.RecentSmsGetter.Companion.SMS_WORK_TAG
import bums.lunatic.launcher.workers.RedditGetter
import bums.lunatic.launcher.workers.RedditGetter.Companion.REDDIT_WORK_TAG
import bums.lunatic.launcher.workers.RuliWebGetter
import bums.lunatic.launcher.workers.TheQooGetter
import bums.lunatic.launcher.workers.WorkersDb
import bums.lunatic.launcher.workers.YoutubeGetter
import bums.lunatic.launcher.workers.YoutubeGetter.Companion.YT_WORK_TAG
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.ext.query
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kr.lunaticbum.utils.ui.DisplayUtil
import org.json.JSONObject
import org.mozilla.geckoview.ExperimentDelegate
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
import java.util.Base64
import java.util.Calendar
import java.util.Date
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.jvm.java
open class LauncherActivity : CommonActivity() {
@ -209,7 +168,8 @@ open class LauncherActivity : CommonActivity() {
Blog.LOGE("onConfigurationChanged newConfig?.screenWidthDp >> ${newConfig?.screenWidthDp}")
Blog.LOGE("onConfigurationChanged newConfig?.screenHeightDp >> ${newConfig?.screenHeightDp}")
isOpendFold = (newConfig.screenWidthDp * 1.1f) > newConfig.screenHeightDp
val nullCursor = PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL)
binding.root.setPointerIcon(nullCursor)
}
// override fun onKeyClick(keyCode: Int): Boolean {
// when (keyCode) {
@ -533,15 +493,24 @@ open class LauncherActivity : CommonActivity() {
@SuppressLint("NewApi", "MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
try {
YoutubeDL.getInstance().init(this)
FFmpeg.getInstance().init(this);
} catch (e: YoutubeDLException) {
Blog.LOGE("failed to initialize youtubedl-android", e)
}
val intent = Intent(this, ForeGroundService::class.java)
this.startForegroundService(intent)
val nlService = Intent(this, NLService::class.java)
this.startService(nlService)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
lActivity = this
DynamicColors.applyToActivityIfAvailable(this)
settingsPrefs = getSharedPreferences(PREFS_SETTINGS, 0)
// AppCompatDelegate.setDefaultNightMode(settingsPrefs.getInt(KEY_APPLICATION_THEME, MODE_NIGHT_FOLLOW_SYSTEM))
super.onCreate(savedInstanceState)
binding = LauncherActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -553,8 +522,8 @@ open class LauncherActivity : CommonActivity() {
updateLocationService()
val intent = Intent(this, BluetoothManager::class.java)
ContextCompat.startForegroundService(this, intent)
showContents(binding.feeds.id)
binding.floatingActionMenu.setOnMenuButtonClickListener { v->
Blog.LOGE("v >> ${v}")
@ -622,6 +591,10 @@ open class LauncherActivity : CommonActivity() {
.replace(R.id.fragment_container, Magnet())
.commit()
}
R.id.setting ->{
startActivity(Intent(this, SettingsActivity::class.java))
}
else -> {}
}
binding.floatingActionMenu.close(false)

View File

@ -2,9 +2,9 @@ package bums.lunatic.launcher.helpers
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@ -17,12 +17,13 @@ import android.os.Build
import android.os.IBinder
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import bums.lunatic.launcher.LauncherActivity
import bums.lunatic.launcher.LauncherActivity.Companion.lActivity
import bums.lunatic.launcher.R
import bums.lunatic.launcher.home.GeckoWeb
import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.workers.ArcaGetter
import bums.lunatic.launcher.workers.ClienGetter
@ -51,8 +52,11 @@ import okhttp3.ResponseBody
import java.util.concurrent.TimeUnit
class BluetoothManager : Service() {
class ForeGroundService : Service() {
companion object {
val ACTION_SENDMSG = "ACTION_SEND_TO_LOVE"
val EXTRA_MSGKEY = "SEND_MSG"
}
enum class BLUETOOTH_STATE(val statestr: String) {
ENABLED("enabledBlutooth"),
DISABLED("disableBlutooth"),
@ -67,44 +71,71 @@ class BluetoothManager : Service() {
super.onCreate()
Blog.LOGE("onCreate")
mWorkManager = WorkManager.getInstance(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(NOTIF_ID, createNotification(this))
}
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)
registerReceiver(bluetoothreceiver, filter)
refreshFeeds()
// GeckoWeb(applicationContext).apply {
// loadUrl("https://arca.live/b/live")
// }
}
override fun onBind(intent: Intent?): IBinder? {
Blog.LOGE("intent >>> ${intent}")
return null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Blog.LOGE("onStartCommand >>> ${intent}")
if (ACTION_SENDMSG.equals(intent?.action)) {
intent?.getStringExtra(EXTRA_MSGKEY)?.let {
sendToI(it)
}
}
startForeGround()
return START_STICKY
}
private val CHANNEL_ID = "ble_service_channel"
private val CHANNEL_NAME = "BLE 서비스"
fun createNotification(context: Context): Notification {
fun startForeGround() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH // 중요도 낮게 (필요시 변경)
"BLE 서비스 채널",
NotificationManager.IMPORTANCE_HIGH
)
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
return NotificationCompat.Builder(context, CHANNEL_ID)
val intent = Intent(this, LauncherActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
startForeground(NOTIF_ID, NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("BLE 서비스")
.setContentText("실행중입니다.")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setSmallIcon(R.drawable.ic_b)
.setContentIntent(pendingIntent)
.addAction(android.R.drawable.ic_btn_speak_now,"퇴근", makeSendMsgAction(0,"돼지 퇴근했다요~!"))
.addAction(android.R.drawable.ic_btn_speak_now,"버스 탐", makeSendMsgAction(1,"돼지 버스 탔다요~!"))
.addAction(android.R.drawable.ic_btn_speak_now,"버스 내림", makeSendMsgAction(2,"돼지 버스 내린다요~!"))
.setOngoing(true) // 사용자가 알림을 스와이프로 지울 수 없게 만듦
.build()
.build())
}
fun makeSendMsgAction(code : Int, msg : String) : PendingIntent {
val actionIntent = Intent(this, ForeGroundService::class.java).apply {
action = ACTION_SENDMSG
putExtra(EXTRA_MSGKEY, msg) // 전달할 데이터
}
return PendingIntent.getService(this, code, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE )
}
override fun onBind(intent: Intent?): IBinder? {
Blog.LOGE("onBind intent >>> ${intent}")
return null
}
private val CHANNEL_ID = "ble_service_channel"
private val CHANNEL_NAME = "BLE 서비스"
//페어링된 디바이스 정보 가져오기
fun getPairedDevices() {
@ -192,6 +223,14 @@ class BluetoothManager : Service() {
PeriodicWorkRequestBuilder<LocationGetter>(PrefLong.locationTimePeriod.get(), TimeUnit.MINUTES)
.addTag(LocationGetter.TAG)
.build())
mWorkManager?.cancelAllWorkByTag(ServiceWatchdogWorker.TAG)
mWorkManager?.enqueueUniquePeriodicWork(
ServiceWatchdogWorker.TAG,
ExistingPeriodicWorkPolicy.REPLACE,
PeriodicWorkRequestBuilder<ServiceWatchdogWorker>(15, TimeUnit.MINUTES)
.addTag(ServiceWatchdogWorker.TAG)
.build())
}
@ -202,6 +241,21 @@ class BluetoothManager : Service() {
return mWorkManager
}
fun sendToI(msg: String) {
if (PrefString.telegramSendTarget.get().length > 5) {
CoroutineScope(Dispatchers.IO).launch {
OkHttpClient.Builder()
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
.build().newCall(Request.Builder().url("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=${PrefString.telegramSendTarget.get()}&text=${msg}")
.addHeader("Content-Type", "application/json").get().build()).execute()?.let { response ->
if (response.isSuccessful()) {
val body: ResponseBody? = response.body()
if (body != null) { }
} else Blog.LOGE("sendToI telegram Error Occurred")
}
}
}
}
fun sendToI(boolean: Boolean) {
if (PrefString.telegramSendTarget.get().length > 5) {
CoroutineScope(Dispatchers.IO).launch {
@ -215,7 +269,7 @@ class BluetoothManager : Service() {
val response: Response = OkHttpClient.Builder()
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
.build().newCall(Request.Builder().url(url)
.addHeader("Content-Type", "application/json").get().build()).execute()
.addHeader("Content-Type", "application/json").get().build()).execute()
if (response.isSuccessful()) {
// 응답 받아서 처리
val body: ResponseBody? = response.body()
@ -251,6 +305,13 @@ class BluetoothManager : Service() {
return BLUETOOTH_STATE.NOT_SUPPORT.statestr
}
override fun stopService(name: Intent?): Boolean {
Blog.LOGE("stopService ${name}")
val intent = Intent(this, ForeGroundService::class.java)
ContextCompat.startForegroundService(this, intent)
return super.stopService(name)
}
//add Receive action
private fun addFilterAction(): IntentFilter {
val stateFilter = IntentFilter()

View File

@ -0,0 +1,36 @@
package bums.lunatic.launcher.helpers
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.work.Worker
import androidx.work.WorkerParameters
class ServiceWatchdogWorker(
private val context: Context,
workerParams: WorkerParameters
) : Worker(context, workerParams) {
companion object{
val TAG = "ServiceWatchdogWorker"
}
override fun doWork(): Result {
val isServiceRunning = isServiceRunning(ForeGroundService::class.java)
if (!isServiceRunning) {
val intent = Intent(context, ForeGroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
return Result.success()
}
fun isServiceRunning(serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Int.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
}

View File

@ -40,6 +40,7 @@ import androidx.core.net.toUri
import androidx.core.view.isVisible
import bums.lunatic.launcher.LauncherActivity.Companion.getRuntime
import bums.lunatic.launcher.R
import bums.lunatic.launcher.model.others.Button
import bums.lunatic.launcher.tokiz.data.model.PortMessage
import bums.lunatic.launcher.tokiz.view.BWebview
import bums.lunatic.launcher.utils.Blog
@ -47,6 +48,9 @@ import bums.lunatic.launcher.utils.CommonUtils
import bums.lunatic.launcher.workers.WorkersDb
import com.google.gson.Gson
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter
import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest
import com.yausername.youtubedl_android.YoutubeDLResponse
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -54,6 +58,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kr.lunaticbum.utils.service.ServiceUtil.getSystemService
import kr.lunaticbum.utils.service.ServiceUtil.layoutInflater
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONException
@ -61,6 +66,7 @@ import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.mozilla.gecko.util.ThreadUtils
import org.mozilla.gecko.util.ThreadUtils.runOnUiThread
import org.mozilla.geckoview.ExperimentDelegate
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoSession
@ -76,6 +82,7 @@ import java.io.FileOutputStream
import java.io.InputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.UUID
class GeckoWeb : BWebview {
constructor(context: Context?) : super(context) {
@ -84,7 +91,7 @@ class GeckoWeb : BWebview {
var decoViews = arrayListOf<View>()
override fun setVisibility(visibility: Int) {
super.setVisibility(visibility)
decoViews.filter { it != null && it.id > -1 }.forEach { it.visibility = visibility }
decoViews.filter { it != null && it.id > -1 && it.id != R.id.dl_video }.forEach { it.visibility = visibility }
}
interface OnSave {
fun saved()
@ -448,6 +455,153 @@ class GeckoWeb : BWebview {
}
}
}
fun checkIfDownloadable(url: String) {
CoroutineScope(Dispatchers.Main).launch {
runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener {}
it.visibility = View.GONE
}}}
Blog.LOGE("checkIfDownloadable ${url}")
CoroutineScope(Dispatchers.IO).launch {
try {
val videoInfo = YoutubeDL.getInstance().getInfo(url)
// videoInfo 가 null 아니고, 필요한 키(예: title, url 등)가 있으면 다운로드 가능
Blog.LOGE("checkIfDownloadable ${url}\n videoInfo : ${videoInfo}")
var canVideoDown = videoInfo != null && !videoInfo.title.isNullOrEmpty()
CoroutineScope(Dispatchers.Main).launch {
runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener {
videoDlownLoad(url)
}
it.visibility = if (canVideoDown){View.VISIBLE} else{View.GONE}
}
}
}
} catch (e: Exception) {
Blog.LOGE("checkIfDownloadable ${url} ${e}")
CoroutineScope(Dispatchers.Main).launch {
runOnUiThread {
decoViews.filter { it.id == R.id.dl_video }.firstOrNull()?.let {
it.setOnClickListener {}
it.visibility = View.GONE
}}}
}
}
}
fun replaceDcUrl(origin: String): String {
var result = origin
for (i in 0..19) {
result = result.replace(String.format("dcimg%d.", i), "dcimg2.")
}
return result
}
fun copyToClipboard(text: String?) {
if (text == null) return
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Media URL", text)
clipboard.setPrimaryClip(clip)
Toast.makeText(context, "주소가 복사되었습니다.", Toast.LENGTH_SHORT).show()
}
suspend fun getFormatList(url: String): List<String> = withContext(Dispatchers.IO) {
val command = YoutubeDLRequest(lastedUrl!!)
command.addOption("--list-formats", url)
val output = YoutubeDL.getInstance().execute(command)
// output.stdout에 포맷 리스트가 문자열로 들어있음
// 줄 단위로 분리 후 리턴
Blog.LOGE("output.out >>> ${output.out}")
return@withContext output.out.split("\n").filter { it.isNotBlank() }
}
fun showFormatSelectionDialog(formats: List<String>, onFormatSelected: (String) -> Unit) {
val builder = AlertDialog.Builder(context)
builder.setTitle("포맷 선택")
builder.setItems(formats.toTypedArray()) { _, which ->
onFormatSelected(formats[which])
}
builder.setNegativeButton("취소", null)
builder.show()
}
lateinit var progressDialog: AlertDialog
fun showProgressDialog() {
val dialogView = layoutInflater.inflate(R.layout.progress_dialog, null)
val progressBar = dialogView.findViewById<ProgressBar>(R.id.progressBar)
val textProgress = dialogView.findViewById<TextView>(R.id.textProgress)
val btn = dialogView.findViewById<android.widget.Button>(R.id.dl_cancel)
progressDialog = AlertDialog.Builder(context)
.setTitle("다운로드 중...")
.setView(dialogView)
.setCancelable(false)
.create()
progressDialog.show()
// UI 업데이트 함수 예 (나중에 실행)
fun updateProgress(progress: Int, est : Long, str : String) {
runOnUiThread {
progressBar.progress = progress
textProgress.text = "$progress%"
}
}
}
fun dismissProgressDialog() {
progressDialog.dismiss()
}
suspend fun downloadVideo(processId : String,url: String, updateProgress: (Float, Long, String) -> Unit) = withContext(Dispatchers.IO) {
val youtubeDLDir = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"youtubedl-android"
)
val command = YoutubeDLRequest(url)
command.addOption("-o", youtubeDLDir.getAbsolutePath() + "/%(title)s.%(ext)s");
var process = YoutubeDL.getInstance().execute(command,processId) { progress, est , str ->
updateProgress(progress, est, str)
}
return@withContext process
}
fun videoDlownLoad(videoUrl : String) {
CoroutineScope(Dispatchers.Main).launch {
try {
showProgressDialog()
var res: YoutubeDLResponse? = null
val processId = UUID.randomUUID().toString()
res = downloadVideo(processId, videoUrl) { progress , time , str->
runOnUiThread {
val pb =
progressDialog.findViewById<ProgressBar>(R.id.progressBar)
val tv =
progressDialog.findViewById<TextView>(R.id.textProgress)
pb?.progress = progress.toInt()
val btn = progressDialog.findViewById<android.widget.Button>(R.id.dl_cancel)
tv?.text = "$progress%\n$str"
btn?.setOnClickListener {
progressDialog?.dismiss()
YoutubeDL.getInstance().destroyProcessById(processId);
}
}
}
dismissProgressDialog()
Toast.makeText(context, "다운로드 완료", Toast.LENGTH_SHORT)
.show()
} catch (e: Exception) {
e.printStackTrace()
progressDialog?.dismiss()
Toast.makeText(context, "오류: ${e.message}", Toast.LENGTH_LONG)
.show()
}
}
}
var dialog : Dialog? = null
fun getFilterF() = String(java.util.Base64.getMimeDecoder().decode("aHR0cHM6Ly9pamF2dG9ycmVudC5jb20=".toByteArray()))
var currentTitle = ""
@ -474,21 +628,7 @@ class GeckoWeb : BWebview {
super.onFirstContentfulPaint(session)
}
fun replaceDcUrl(origin: String): String {
var result = origin
for (i in 0..19) {
result = result.replace(String.format("dcimg%d.", i), "dcimg2.")
}
return result
}
fun copyToClipboard(text: String?) {
if (text == null) return
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Media URL", text)
clipboard.setPrimaryClip(clip)
Toast.makeText(context, "주소가 복사되었습니다.", Toast.LENGTH_SHORT).show()
}
override fun onExternalResponse(session: GeckoSession, response: WebResponse) {
Blog.LOGE("response >>> ${response.uri} ")
@ -504,6 +644,7 @@ class GeckoWeb : BWebview {
val client = OkHttpClient()
val request = Request.Builder()
.url(url)
.addHeader("Referer", lastedUrl)
.addHeader("User-Agent", "Mozilla/5.0")
// 필요시 Referer, 쿠키 등 헤더 추가
.build()
@ -531,6 +672,7 @@ class GeckoWeb : BWebview {
super.onExternalResponse(session, response)
}
override fun onContextMenu(
session: GeckoSession,
screenX: Int,
@ -539,18 +681,11 @@ class GeckoWeb : BWebview {
) {
if (element.baseUri?.contains("youtube") == true) {
copyToClipboard(lastedUrl)
loadUrl("https://ko.savefrom.net/227lt/#url=${lastedUrl}")
// copyToClipboard(lastedUrl)
// Dialog(context)?.let { dialog ->
// val popupWebView = GeckoWeb(context).apply {
// loadUrl(lastedUrl!!.replace("https://","https://ss"))
// this.dialog = dialog
// }
// dialog.setCanceledOnTouchOutside(true)
// dialog.setContentView(popupWebView)
// dialog.show()
// }
lastedUrl?.let { videoUrl ->
lastedUrl?.let {
videoDlownLoad(it)
}
}
} else {
Blog.LOGE("onContextMenu:: x = ${x}, y = ${y} , element = ${Gson().toJson(element)}")
if (element.type == GeckoSession.ContentDelegate.ContextElement.TYPE_IMAGE) {
@ -656,8 +791,8 @@ class GeckoWeb : BWebview {
)
} == true ||
((it.host?.contains("x.com") ?: false) == true) ||
((it.host?.contains("www.instagram.com") ?: false) == true)
) {
((it.host?.contains("www.instagram.com") ?: false) == true)
) {
loadUrl(uri)
} else if(uri.contains("googlevideo.com")) {
CommonUtils.downloadFileWithOkHttp(context, Uri.parse(lastedUrl),uri)
@ -723,6 +858,7 @@ class GeckoWeb : BWebview {
} else {
lastedUrl = url
}
checkIfDownloadable(url)
}
@ -735,6 +871,8 @@ class GeckoWeb : BWebview {
it.tag = currentTitle
it.text = url
}
}else if (it.id == R.id.reload) {
it.setOnClickListener { session.reload() }
}
}
}

View File

@ -625,6 +625,8 @@ internal class RssHome : Fragment() {
(activity as? LauncherActivity)?.let { activity ->
binding.geckoWeb.decoViews.add(activity.findViewById<TextView>(R.id.current_address))
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.back))
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.reload))
binding.geckoWeb.decoViews.add(activity.findViewById<ImageButton>(R.id.dl_video))
}

View File

@ -1,5 +1,6 @@
package bums.lunatic.launcher.receiver
import android.app.Notification
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
@ -13,9 +14,11 @@ import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import bums.lunatic.launcher.helpers.ForeGroundService
import bums.lunatic.launcher.model.CurrentPlayItem
import bums.lunatic.launcher.model.NotificationItem
import bums.lunatic.launcher.utils.BitmapConverter
import bums.lunatic.launcher.utils.Blog
import bums.lunatic.launcher.workers.WorkersDb
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
@ -29,7 +32,6 @@ class NLService : NotificationListenerService() {
super.onCreate()
nlservicereciver = NLServiceReceiver()
val filter = IntentFilter()
// filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE")
registerReceiver(nlservicereciver, filter)
}
@ -38,130 +40,54 @@ class NLService : NotificationListenerService() {
unregisterReceiver(nlservicereciver)
}
val skips = arrayListOf("com.wssyncmldm")
@RequiresApi(Build.VERSION_CODES.S)
override fun onNotificationPosted(sbn: StatusBarNotification) {
// BLog.LOGE("NLService********** onNotificationPosted")
// BLog.LOGE("NLServiceID :" + sbn.id + "\t${sbn.notification.tickerText}\t" + sbn.packageName)
// sbn.notification.extras.keySet().forEach {
// BLog.LOGE("NLService********** keySet >> ${it} ${sbn.notification.extras.get(it)}")
// }
try {
if (sbn.id != 0 && (sbn.packageName.contains(".") || sbn.packageName.contains("android")) && sbn.packageName.length > 0) {
NotificationItem().apply {
notiId = sbn.id
pkgName = sbn.packageName
title = sbn.notification?.extras?.getString("android.title") ?: ""
subtext = sbn.notification?.extras?.getString("android.subText") ?: ""
selfDisplayName = sbn.notification?.extras?.getString("android.selfDisplayName") ?: ""
tikerMsg = sbn.notification?.tickerText?.toString() ?: ""
postTime = sbn.postTime
var uniq = title ?: subtext ?: selfDisplayName ?: tikerMsg ?: ""
uniq_id = "${sbn.id}_${sbn.packageName}_${if (uniq.length > 3) uniq.substring(0,3) else uniq}"
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${true == "bumssavor".equals(title)}")
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${(true == "org.telegram.messenger".equals(pkgName))}")
// BLog.LOGE("NLService********** enqueue TelegramBotGetter ${sbn.notification?.extras?.getString("android.text")?.startsWith("/") == true}")
}.apply {
if (skips.contains(pkgName)) {
Blog.LOGE("onNotificationPosted ${sbn}")
val notification = sbn.notification
val extras = notification.extras
when (sbn.packageName){
"com.kakao.talk" -> {
} else {
// WorkersDb.insertNoti(this)
// BLog.LOGE("NLService********** onNotificationPosted ${Gson().toJson(this)}")
}
}
}
} catch (e : Exception) {
e.printStackTrace()
}
try {
if (sbn.packageName.contains("youtube")) {
val m = getSystemService<MediaSessionManager>()!!
val component = ComponentName(this, NLService::class.java)
val sessions = m.getActiveSessions(component)
sessions.forEach { session ->
WorkersDb.getRealm().writeBlocking {
// Blog.LOGE("session.playbackState >>> ${session.playbackState}")
if (session.playbackState != null) {
if (session.playbackState?.isActive == true && session.playbackState?.state?.equals(
STATE_PLAYING
) == true
) {
session.playbackState?.state
val result = query<CurrentPlayItem>().find()
var current: CurrentPlayItem? = null
if (result.size > 0) {
current = result.first()
} else {
current = CurrentPlayItem()
copyToRealm(current, UpdatePolicy.ALL)
}
if (session?.metadata?.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART) == true) {
current.albumArt = BitmapConverter.BitmapToString(
session.metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
)
} else {
current.albumArt = ""
}
current.title =
session?.metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
current.artists =
session?.metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
} else {
delete(query<CurrentPlayItem>().find())
}
}
}
}
}}catch (e : Exception) {
e.printStackTrace()
}
// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i.putExtra("notification_event", "onNotificationPosted :" + sbn.packageName + "\n")
// sendBroadcast(i)
val title = extras.getString(Notification.EXTRA_TITLE) ?: ""
val text = extras.getCharSequence(Notification.EXTRA_TEXT)?.toString() ?: ""
val bigText = extras.getCharSequence(Notification.EXTRA_BIG_TEXT)?.toString() ?: ""
val extraInfo = extras.getCharSequence(Notification.EXTRA_INFO_TEXT)?.toString() ?: ""
val subText = extras.getCharSequence(Notification.EXTRA_SUB_TEXT)?.toString() ?: ""
val conversationTitle = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE)?.toString() ?: ""
val summaryText = extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT)?.toString() ?: ""
val verificationText = extras.getCharSequence(Notification.EXTRA_VERIFICATION_TEXT)?.toString() ?: ""
Blog.LOGE("title >> ${title} text >> ${text} bigText >> ${bigText} extraInfo >> ${extraInfo} subText >> ${subText} conversationTitle >> ${conversationTitle} summaryText >> ${summaryText} verificationText >> ${verificationText}")
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
//// BLog.LOGE("NLService********** onNOtificationRemoved")
//// BLog.LOGE("NLService ID :" + sbn.id + "\t" + sbn.notification.tickerText + "\t" + sbn.packageName)
// var uniq_id = "${sbn.id}_${sbn.packageName}"
// try {
// WorkersDb.getRealm()?.apply {
// this.writeBlocking {
//// delete(query<NotificationItem>().query("pkgName == $0", sbn.packageName).find())
// }
// }
// }catch (e : Exception){e.printStackTrace()}
//// val i = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
//// i.putExtra("notification_event", "onNotificationRemoved :" + sbn.packageName + "\n")
//// sendBroadcast(i)
Blog.LOGE("onNotificationPosted ${sbn}")
if (sbn.packageName == "bums.lunatic.launcher" && sbn.id == 830721) {
// 포그라운드 알림이 사라짐 감지
Blog.LOGE("NotificationListener", "포그라운드 알림 제거 감지")
// 서비스 재시작 시도
val intent = Intent(this, ForeGroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
}
internal inner class NLServiceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
// BLog.LOGE("NLService intent >>> ${intent.action}")
if (intent.getStringExtra("command") == "clearall") {
this@NLService.cancelAllNotifications()
} else if (intent.getStringExtra("command") == "list") {
// val i1 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i1.putExtra("notification_event", "=====================")
// sendBroadcast(i1)
var i = 1
for (sbn in this@NLService.activeNotifications) {
// BLog.LOGE("NLService sbn >>> ${sbn.packageName} , ${Gson().toJson(sbn.notification.extras.keySet())}")
// val i2 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i2.putExtra("notification_event", i.toString() + " " + sbn.packageName + "\n")
// sendBroadcast(i2)
// i++
}
// val i3 = Intent("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE")
// i3.putExtra("notification_event", "===== Notification List ====")
// sendBroadcast(i3)
}
}
}
}

View File

@ -0,0 +1,57 @@
package bums.lunatic.launcher.view
import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import androidx.appcompat.widget.AppCompatImageView
class ZoomImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs),
ScaleGestureDetector.OnScaleGestureListener, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
private var scaleFactor = 1.0f
private val scaleGestureDetector = ScaleGestureDetector(context, this)
private val gestureDetector = GestureDetector(context, this)
override fun onTouchEvent(event: MotionEvent): Boolean {
scaleGestureDetector.onTouchEvent(event)
gestureDetector.onTouchEvent(event)
return true
}
// ScaleGestureDetector callbacks
override fun onScale(detector: ScaleGestureDetector): Boolean {
scaleFactor *= detector.scaleFactor
scaleFactor = scaleFactor.coerceIn(1.0f, 4.0f)
scaleX = scaleFactor
scaleY = scaleFactor
return true
}
override fun onScaleBegin(detector: ScaleGestureDetector) = true
override fun onScaleEnd(detector: ScaleGestureDetector) {}
// GestureDetector callbacks (클릭, 터치 등)
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
performClick() // 클릭 이벤트 발생
return true
}
override fun performClick(): Boolean {
super.performClick()
// 추가로 클릭 시 동작할 코드 넣기
if (hasOnClickListeners()) {
callOnClick()
}
return true
}
override fun onDown(e: MotionEvent) = true
override fun onShowPress(e: MotionEvent) {}
override fun onSingleTapUp(e: MotionEvent) = true
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float) = false
override fun onLongPress(e: MotionEvent) {}
override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float) = false
override fun onDoubleTap(e: MotionEvent) = true
override fun onDoubleTapEvent(e: MotionEvent) = true
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

View File

@ -36,12 +36,27 @@
android:layout_width="40dp"
tools:ignore="ContentDescription"
android:layout_height="40dp" />
<ImageButton
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fragment_container"
app:layout_constraintLeft_toRightOf="@id/back"
android:id="@+id/reload"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:visibility="visible"
android:background="@null"
android:src="@drawable/ic_refresh"
android:tint="@color/white"
android:foregroundTint="@color/white"
android:layout_width="40dp"
tools:ignore="ContentDescription"
android:layout_height="40dp" />
<TextView
android:text="asdasdsadasd"
android:id="@+id/current_address"
app:layout_constraintTop_toTopOf="@id/back"
app:layout_constraintRight_toLeftOf="@id/share"
app:layout_constraintLeft_toRightOf="@id/back"
app:layout_constraintRight_toLeftOf="@id/dl_video"
app:layout_constraintLeft_toRightOf="@id/reload"
android:textColor="@color/white"
android:gravity="center"
android:textSize="@dimen/_12sp"
@ -49,6 +64,21 @@
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="40dp"/>
<ImageButton
app:layout_constraintTop_toTopOf="@id/back"
app:layout_constraintRight_toLeftOf="@id/share"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/dl_video"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:visibility="gone"
android:background="@null"
android:tint="@color/white"
android:foregroundTint="@color/white"
android:src="@drawable/dl_vid"
android:layout_width="40dp"
tools:ignore="ContentDescription"
android:layout_height="40dp" />
<ImageButton
app:layout_constraintTop_toTopOf="@id/back"
app:layout_constraintRight_toRightOf="parent"
@ -140,5 +170,13 @@
android:onClick="floatClick"
android:layout_width="wrap_content"
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.FloatingActionMenu>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -49,7 +49,7 @@
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
<bums.lunatic.launcher.view.ZoomImageView
app:layout_constraintTop_toBottomOf="@id/date"
android:alpha="0.05"
android:adjustViewBounds="true"
@ -78,7 +78,7 @@
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
<bums.lunatic.launcher.view.ZoomImageView
app:layout_constraintTop_toBottomOf="@id/desc"
android:id="@+id/screen"
android:alpha="0.05"

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="24dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<TextView
android:id="@+id/textProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="0%" />
<Button
android:text="다운로드 취소"
android:gravity="center"
android:id="@+id/dl_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>