diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2ed45e4..14fc5264 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: - release env: - LATEST_VERSION: "1.5" + LATEST_VERSION: "2.0.0" jobs: build-and-deploy: diff --git a/README.md b/README.md index 9ed4e382..b4c279d8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ SKIP 是一款免费开源的安卓应用,旨在利用 Android 无障碍服务 ## 主界面预览 -https://guoxicheng.top/assets/image/skip-docs/main-interface.jpg +https://guoxicheng.top/assets/image/skip-docs/main-interface-light.png ## 使用说明 @@ -18,7 +18,7 @@ SKIP 是一款免费开源的安卓应用,旨在利用 Android 无障碍服务 ## 如何贡献 - 应用市场APP种类繁多,情况各异,无法保证完全适配 -- 如有问题可以提交issue,或者参考 👉 [贡献指南](https://guoxicheng.top/projects/SKIP-Docs/003-contribute.html) +- 如有问题可以提交issue,或者参考 👉 [贡献指南](https://guoxicheng.top/projects/SKIP-Docs/contribute.html) ## 许可证 diff --git a/apk/SKIP-v2.0.0.apk b/apk/SKIP-v2.0.0.apk new file mode 100644 index 00000000..4507ea6b Binary files /dev/null and b/apk/SKIP-v2.0.0.apk differ diff --git a/app/build.gradle b/app/build.gradle index 4faecac7..f3cffb53 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { minSdk 24 targetSdk 32 versionCode 1 - versionName "1.5" + versionName "2.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/android/skip/AboutActivity.kt b/app/src/main/java/com/android/skip/AboutActivity.kt index 6fef33f9..9d1ccd94 100644 --- a/app/src/main/java/com/android/skip/AboutActivity.kt +++ b/app/src/main/java/com/android/skip/AboutActivity.kt @@ -1,15 +1,11 @@ package com.android.skip -import android.content.Intent -import android.net.Uri import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import com.android.skip.compose.ConfirmDialog import com.android.skip.compose.FlatButton +import com.android.skip.compose.OpenBrowserDialog import com.android.skip.compose.RowContent import com.android.skip.compose.ScaffoldPage import com.android.skip.manager.RectManager @@ -54,31 +50,14 @@ fun AboutActivityInterface(onBackClick: () -> Unit) { } FlatButton(content = { - RowContent("当前版本:${BuildConfig.VERSION_NAME}") + RowContent(stringResource(id = R.string.about_current_version) + BuildConfig.VERSION_NAME) }) FlatButton(content = { - RowContent("当前分辨率:${RectManager.getMaxRect()}") + RowContent(stringResource(id = R.string.about_current_resolution) + RectManager.getMaxRect()) }) }) - OpenApplicationDialog(openName = openName.value, openUrl = openUrl.value, showDialog) -} - -@Composable -fun OpenApplicationDialog(openName: String, openUrl: String, showDialog: MutableState) { - val context = LocalContext.current - - if (showDialog.value) { - ConfirmDialog( - title = "启动应用", - content = "是否通过浏览器访问 $openName?", - onDismiss = { showDialog.value = false }, - onAllow = { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(openUrl)) - context.startActivity(intent) - showDialog.value = false - }) - } + OpenBrowserDialog(openName = openName.value, openUrl = openUrl.value, showDialog) } diff --git a/app/src/main/java/com/android/skip/BaseActivity.kt b/app/src/main/java/com/android/skip/BaseActivity.kt index 4cfae732..3d8bec49 100644 --- a/app/src/main/java/com/android/skip/BaseActivity.kt +++ b/app/src/main/java/com/android/skip/BaseActivity.kt @@ -39,7 +39,16 @@ abstract class BaseActivity : AppCompatActivity() { ProvideContent() } } + RectManager.setMaxRect(this) + + // 清理临时文件 + val directory = this.getExternalFilesDir(null) + directory?.let { + it.listFiles()?.forEach { file -> + file.delete() + } + } } @Composable diff --git a/app/src/main/java/com/android/skip/KeepAliveActivity.kt b/app/src/main/java/com/android/skip/KeepAliveActivity.kt index ed32dde7..7dd11144 100644 --- a/app/src/main/java/com/android/skip/KeepAliveActivity.kt +++ b/app/src/main/java/com/android/skip/KeepAliveActivity.kt @@ -3,6 +3,7 @@ package com.android.skip import android.content.ComponentName import android.content.Intent import android.net.Uri +import android.os.Build import android.provider.Settings import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf @@ -10,10 +11,12 @@ import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.android.skip.compose.FlatButton +import com.android.skip.compose.OpenBrowserDialog import com.android.skip.compose.PictureDialog import com.android.skip.compose.ResourceIcon import com.android.skip.compose.RowContent import com.android.skip.compose.ScaffoldPage +import java.net.URLEncoder class KeepAliveActivity : BaseActivity() { @@ -28,14 +31,15 @@ class KeepAliveActivity : BaseActivity() { @Composable fun KeepAliveInterface(onBackClick: () -> Unit) { val context = LocalContext.current - val showDialog = remember { mutableStateOf(false) } + val showPicDialog = remember { mutableStateOf(false) } + val showBrowserDialog = remember { mutableStateOf(false) } ScaffoldPage(stringResource(id = R.string.alive), onBackClick = onBackClick, content = { - PictureDialog(showDialog) + PictureDialog(showPicDialog) FlatButton(content = { RowContent( stringResource(id = R.string.alive_power_saving_title), stringResource(id = R.string.alive_power_saving_subtitle), - { ResourceIcon(iconResource = R.drawable.counter_1)} + { ResourceIcon(iconResource = R.drawable.counter_1) } ) }) { val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) @@ -46,7 +50,7 @@ fun KeepAliveInterface(onBackClick: () -> Unit) { RowContent( stringResource(id = R.string.alive_self_start_title), stringResource(id = R.string.alive_self_start_subtitle), - { ResourceIcon(iconResource = R.drawable.counter_2)} + { ResourceIcon(iconResource = R.drawable.counter_2) } ) }) { val intent = Intent() @@ -60,17 +64,30 @@ fun KeepAliveInterface(onBackClick: () -> Unit) { RowContent( stringResource(id = R.string.alive_backstage_title), stringResource(id = R.string.alive_backstage_subtitle), - { ResourceIcon(iconResource = R.drawable.counter_3)} + { ResourceIcon(iconResource = R.drawable.counter_3) } ) }) { - showDialog.value = true + showPicDialog.value = true } FlatButton(content = { RowContent( stringResource(id = R.string.alive_warn_title), stringResource(id = R.string.alive_warn_subtitle), - { ResourceIcon(iconResource = R.drawable.warning)} + { ResourceIcon(iconResource = R.drawable.warning) } ) - }) + }) { + showBrowserDialog.value = true + } }) + + val searchContent = Build.MANUFACTURER + stringResource(id = R.string.alive_warn_search_content) + OpenBrowserDialog( + openName = searchContent, + openUrl = createBaiduSearchUrl(searchContent), + showDialog = showBrowserDialog + ) +} + +fun createBaiduSearchUrl(query: String): String { + return "https://www.baidu.com/s?wd=${URLEncoder.encode(query, "UTF-8")}" } \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/MainActivity.kt b/app/src/main/java/com/android/skip/MainActivity.kt index 546830ad..ee7baab7 100644 --- a/app/src/main/java/com/android/skip/MainActivity.kt +++ b/app/src/main/java/com/android/skip/MainActivity.kt @@ -1,638 +1,638 @@ package com.android.skip - -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.text.ClickableText -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.withStyle -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.core.content.FileProvider -import com.android.skip.dataclass.PackageInfo -import com.android.skip.manager.HttpManager -import com.android.skip.manager.RectManager -import com.android.skip.manager.SkipConfigManager -import com.android.skip.manager.ToastManager -import com.android.skip.ui.theme.AppTheme -import com.android.skip.ui.theme.green -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.launch -import org.yaml.snakeyaml.Yaml -import java.io.File -import java.util.Locale -import kotlin.concurrent.thread -import kotlin.math.roundToInt - - -var accessibilityState by mutableStateOf(false) - -var alertDialogPositiveButtonClickState by mutableStateOf(false) - -// 无障碍服务启用停用按钮 -var isAccessibilityBtnClicked by mutableStateOf(false) - -// 后台任务管理 -var isBackendTaskBtnClicked by mutableStateOf(false) - -// 自启动管理 -var isAutoStartBtnClicked by mutableStateOf(false) - -// 省电策略按钮 -var isPowerSavingBtnClicked by mutableStateOf(false) - -// 检查更新按钮 -var isCheckUpdateBtnClicked by mutableStateOf(false) - -// 是否需要更新 -var isNeedUpdateAPK by mutableStateOf(false) - -// 最新版本号 -var latestVersionText by mutableStateOf("") - -// 立即更新 -var isUpdateAPKClicked by mutableStateOf(false) - -// 更新进度对话框 -var isProcessDialogVisible by mutableStateOf(false) - -var downloadProgress by mutableStateOf(0f) - - -class MainActivity : ComponentActivity() { - - private fun openAppInfo() { - val packageName = packageName - val intent = Intent( - Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:$packageName") - ) - startActivity(intent) - } - - private fun openAutoStartSettings(context: Context) { - try { - val intent = Intent() - - val manufacturer = Build.MANUFACTURER.lowercase(Locale.ENGLISH) - when { - manufacturer.contains("xiaomi") -> { - intent.component = ComponentName( - "com.miui.securitycenter", - "com.miui.permcenter.autostart.AutoStartManagementActivity" - ) - } - manufacturer.contains("oppo") -> { - intent.component = ComponentName( - "com.coloros.safecenter", - "com.coloros.safecenter.permission.startup.StartupAppListActivity" - ) - } - manufacturer.contains("vivo") -> { - intent.component = ComponentName( - "com.vivo.permissionmanager", - "com.vivo.permissionmanager.activity.BgStartUpManagerActivity" - ) - } - manufacturer.contains("oneplus") -> { - intent.component = ComponentName( - "com.oneplus.security", - "com.oneplus.security.chainlaunch.view.ChainLaunchAppListAct‌​ivity" - ) - } - manufacturer.contains("huawei") -> { - intent.component = ComponentName( - "com.huawei.systemmanager", - "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity" - ) - } - else -> { - openAppInfo() - } - } - - context.startActivity(intent) - } catch (e: Exception) { - openAppInfo() - } - } - - private fun openBatteryOptimizationSettings(context: Context) { - try { - val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) - intent.data = Uri.parse("package:${context.packageName}") - context.startActivity(intent) - } catch (e: Exception) { - openAppInfo() - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - - super.onCreate(savedInstanceState) - - setContent { - - val displayMetrics = LocalContext.current.resources.displayMetrics - val widthPixels = displayMetrics.widthPixels - val fontScale = LocalDensity.current.fontScale - - CompositionLocalProvider( - LocalDensity provides Density( - density = widthPixels / 360.0f, - fontScale = fontScale - ) - ) { - MainSurface() - ProcessDialog() - } - - - if (isAccessibilityBtnClicked) { - if (!accessibilityState) { - AlertDialog( - context = this, - title = "启用无障碍服务", - message = "已下载的应用 > SKIP > 打开「使用SKIP」", - negativeText = "再想想", - positiveText = "去开启" - ) { - alertDialogPositiveButtonClickState = true - } - } else { - AlertDialog( - context = this, - title = "停用无障碍服务", - message = "已下载的应用 > SKIP > 关闭「使用SKIP」", - negativeText = "再想想", - positiveText = "去停用" - ) { - alertDialogPositiveButtonClickState = true - } - } - isAccessibilityBtnClicked = false - } - - if (isNeedUpdateAPK) { - AlertDialog( - context = this, - title = "发现新版本", - message = "${BuildConfig.VERSION_NAME} -> $latestVersionText", - negativeText = "暂不更新", - positiveText = "立即更新" - ) { - isUpdateAPKClicked = true - } - isNeedUpdateAPK = false - } - - when { - alertDialogPositiveButtonClickState -> { - val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) - this.startActivity(intent) - alertDialogPositiveButtonClickState = false - } - isAutoStartBtnClicked -> { - openAutoStartSettings(this) - isAutoStartBtnClicked = false - } - isPowerSavingBtnClicked -> { - openBatteryOptimizationSettings(this) - isPowerSavingBtnClicked = false - } - isBackendTaskBtnClicked -> { - ImageDialog() - } - isCheckUpdateBtnClicked -> { - thread { - ToastManager.showToast(this, "开始检查更新") - val updateSkipConfigResult = - if (HttpManager.updateSkipConfig()) "配置更新成功" else "配置更新失败" - ToastManager.showToast(this, updateSkipConfigResult) - - val latestVersion = HttpManager.getLatestVersion() - if (latestVersion != BuildConfig.VERSION_NAME.trim()) { - isNeedUpdateAPK = true - latestVersionText = latestVersion - } else { - ToastManager.showToast(this, "当前版本已是最新版") - } - - isCheckUpdateBtnClicked = false - } - } - isUpdateAPKClicked -> { - thread { - isProcessDialogVisible = true - HttpManager.downloadNewAPK(latestVersionText, this) { it -> - downloadProgress = it * 0.01f - if (it == 100) isProcessDialogVisible = false - } - val latestVersionAPK = "SKIP-v$latestVersionText.apk" - val apkFile = File(this.getExternalFilesDir(null), latestVersionAPK) - - val apkUri = FileProvider.getUriForFile( - this, - this.applicationContext.packageName + ".provider", - apkFile - ) - - val intent = Intent(Intent.ACTION_VIEW) - intent.setDataAndType(apkUri, "application/vnd.android.package-archive") - intent.flags = - Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION - this.startActivity(intent) - - isUpdateAPKClicked = false - } - } - } - - } - - RectManager.setMaxRect(this) - - val yaml = Yaml().load>(assets.open("skip_config.yaml")) - SkipConfigManager.setConfig(yaml) - - // 清理临时文件 - val directory = this.getExternalFilesDir(null) - directory?.let { - it.listFiles()?.forEach { file -> - file.delete() - } - } - } - - override fun onResume() { - super.onResume() - accessibilityState = MyUtils.isAccessibilitySettingsOn(this) - } -} - - -@Composable -@Preview(showBackground = true) -fun MainSurface() { - AppTheme { - - val res = LocalContext.current.resources - - PageHeader(res.getString(R.string.app_name), "是一款免费开源的自动跳过开屏广告的工具") - - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Box(modifier = Modifier.offset(y = (-50).dp)) { - AccessibilityControlBtn() - } - } - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Box(modifier = Modifier.offset(y = (90).dp)) { - AccessibilityTextBox() - } - } - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.BottomCenter - ) { - TipBox() - PageFooter() - } - - } -} - -@Composable -fun PageHeader(title: String, subtitle: String) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(top = 60.dp, start = 20.dp) - ) { - Text( - text = title, - color = Color.White, - fontSize = 36.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(bottom = 8.dp) - ) - Text( - text = subtitle, - color = Color.White, - fontSize = 16.sp, - ) - } -} - -@Composable -fun AccessibilityTextBox() { - Row { - if (accessibilityState) { - Text(text = "无障碍服务功能: 启用中", color = Color.White) - } else { - Text(text = "无障碍服务功能: 未启用", color = Color.White) - } - - } -} - -@Composable -fun TipBox() { - - Column( - modifier = Modifier - .background(color = Color.White) - .height(240.dp) - .fillMaxWidth() - .padding(start = 15.dp, top = 10.dp) - ) { - Text( - "操作方式", - fontWeight = FontWeight.Bold, - fontSize = 18.sp, - modifier = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) - ) - - Row { - TipText("第一步:进入「") - ClickableText("后台任务管理", onClick = { clicked -> isBackendTaskBtnClicked = clicked }) - TipText("」,长按「SKIP」,锁定") - } - - Row { - TipText("第二步:进入「") - ClickableText("省电策略", onClick = { clicked -> isPowerSavingBtnClicked = clicked }) - TipText("」,无限制") - } - - Row { - TipText("第三步:进入「") - ClickableText("自启动管理", onClick = { clicked -> isAutoStartBtnClicked = clicked }) - TipText("」,找到「SKIP」,允许") - } - - Text( - "注意事项", - fontWeight = FontWeight.Bold, - fontSize = 18.sp, - modifier = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) - ) - - TipText("由于无障碍服务会在应用进程结束后自动关闭,因此需要完成上述操作开启应用后台运行权限") - - - } -} - -@Composable -fun TipText(text: String) { - Text( - text, - fontSize = 14.sp, - color = Color.Gray, - modifier = Modifier.padding(0.dp, 2.5.dp, 0.dp, 2.5.dp) - ) -} - - -@Composable -fun ClickableText(text: String, onClick: (Boolean) -> Unit) { - val annotatedString = buildAnnotatedString { - append(text) - addStyle( - style = SpanStyle(textDecoration = androidx.compose.ui.text.style.TextDecoration.Underline), - start = 0, - end = length - ) - addStringAnnotation( - tag = "Clickable", - annotation = "Details", - start = 0, - end = length - ) - } - - ClickableText( - text = annotatedString, - modifier = Modifier.padding(0.dp, 2.5.dp, 0.dp, 2.5.dp), - onClick = { offset -> - annotatedString.getStringAnnotations("Clickable", offset, offset) - .firstOrNull()?.let { _ -> - onClick(true) - } - } - ) -} - - -@Composable -fun AccessibilityControlBtn() { - Button( - onClick = { - isAccessibilityBtnClicked = true - }, - contentPadding = PaddingValues(0.dp), - colors = ButtonDefaults.textButtonColors() - ) { - if (accessibilityState) { - Image( - modifier = Modifier.size(140.dp, 140.dp), - painter = painterResource(id = R.drawable.disabled), - contentDescription = "disabled", - ) - } else { - Image( - modifier = Modifier.size(140.dp, 140.dp), - painter = painterResource(id = R.drawable.enabled), - contentDescription = "enabled", - ) - } - } -} - -@Composable -fun PageFooter() { - val context = LocalContext.current - val coroutineScope = rememberCoroutineScope() - - Row( - modifier = Modifier - .fillMaxWidth() - .height(45.dp) - .background(color = Color.White), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - val annotatedString = buildAnnotatedString { - withStyle(style = SpanStyle(color = Color.Black, fontSize = 12.sp)) { - append("Github") - addStringAnnotation( - tag = "URL", - annotation = "https://github.com/GuoXiCheng/SKIP", - start = 0, - end = 6 - ) - append(" | ") - append(RectManager.getMaxRect()) - append(" | version " + BuildConfig.VERSION_NAME) - append(" | ") - append("检查更新") - addStringAnnotation( - tag = "CHECK_UPDATE", - annotation = "", - start = length - 4, - end = length - ) - } - } - ClickableText( - text = annotatedString, - onClick = { offset -> - annotatedString.getStringAnnotations(start = offset, end = offset).firstOrNull() - ?.let { annotation -> - when (annotation.tag) { - "URL" -> { - val url = annotation.item - coroutineScope.launch { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - context.startActivity(intent) - } - } - "CHECK_UPDATE" -> { - isCheckUpdateBtnClicked = true - } - } - } - } - ) - } -} - - -@Composable -fun AlertDialog( - context: Context, title: CharSequence, - message: CharSequence?, negativeText: CharSequence, - positiveText: CharSequence, onPositiveButtonClick: () -> Unit -) { - MaterialAlertDialogBuilder(context) - .setTitle(title) - .setMessage(message) - .setNegativeButton(negativeText, null) - .setPositiveButton(positiveText) { _, _ -> - onPositiveButtonClick() - } - .show() -} - -@Composable -fun ImageDialog() { - AlertDialog( - onDismissRequest = { isBackendTaskBtnClicked = false }, - containerColor = Color.White, - text = { - Box(modifier = Modifier.fillMaxWidth()) { - Image( - painter = painterResource(R.drawable.backend_lock), // 设置要显示的图片 - contentDescription = "Image", - modifier = Modifier.fillMaxWidth() - ) - } - }, - confirmButton = { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - TextButton( - onClick = { isBackendTaskBtnClicked = false }, - colors = ButtonDefaults.textButtonColors(contentColor = green) - ) { - Text(text = "我知道了") - } - } - - } - ) -} - -@Composable -fun ProcessDialog() { - if (isProcessDialogVisible) { - AlertDialog( - onDismissRequest = { - isProcessDialogVisible = false - }, - title = { - Text(text = "正在下载") - }, - text = { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier.padding(16.dp) - ) { - LinearProgressIndicator(progress = downloadProgress) - Spacer(modifier = Modifier.height(16.dp)) - Text(text = "下载进度:${(downloadProgress * 100).roundToInt()}%") - } - }, - confirmButton = { - }, - dismissButton = { - } - ) - } -} - - +// +//import android.content.ComponentName +//import android.content.Context +//import android.content.Intent +//import android.net.Uri +//import android.os.Build +//import android.os.Bundle +//import android.provider.Settings +//import androidx.activity.ComponentActivity +//import androidx.activity.compose.setContent +//import androidx.compose.foundation.Image +//import androidx.compose.foundation.background +//import androidx.compose.foundation.layout.Arrangement +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Column +//import androidx.compose.foundation.layout.PaddingValues +//import androidx.compose.foundation.layout.Row +//import androidx.compose.foundation.layout.Spacer +//import androidx.compose.foundation.layout.fillMaxSize +//import androidx.compose.foundation.layout.fillMaxWidth +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.layout.offset +//import androidx.compose.foundation.layout.padding +//import androidx.compose.foundation.layout.size +//import androidx.compose.foundation.text.ClickableText +//import androidx.compose.material3.AlertDialog +//import androidx.compose.material3.Button +//import androidx.compose.material3.ButtonDefaults +//import androidx.compose.material3.LinearProgressIndicator +//import androidx.compose.material3.Text +//import androidx.compose.material3.TextButton +//import androidx.compose.runtime.Composable +//import androidx.compose.runtime.CompositionLocalProvider +//import androidx.compose.runtime.getValue +//import androidx.compose.runtime.mutableStateOf +//import androidx.compose.runtime.rememberCoroutineScope +//import androidx.compose.runtime.setValue +//import androidx.compose.ui.Alignment +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.graphics.Color +//import androidx.compose.ui.platform.LocalContext +//import androidx.compose.ui.platform.LocalDensity +//import androidx.compose.ui.res.painterResource +//import androidx.compose.ui.text.SpanStyle +//import androidx.compose.ui.text.buildAnnotatedString +//import androidx.compose.ui.text.font.FontWeight +//import androidx.compose.ui.text.withStyle +//import androidx.compose.ui.tooling.preview.Preview +//import androidx.compose.ui.unit.Density +//import androidx.compose.ui.unit.dp +//import androidx.compose.ui.unit.sp +//import androidx.core.content.FileProvider +//import com.android.skip.dataclass.PackageInfo +//import com.android.skip.manager.HttpManager +//import com.android.skip.manager.RectManager +//import com.android.skip.manager.SkipConfigManager +//import com.android.skip.manager.ToastManager +//import com.android.skip.ui.theme.AppTheme +//import com.android.skip.ui.theme.green +//import com.google.android.material.dialog.MaterialAlertDialogBuilder +//import kotlinx.coroutines.launch +//import org.yaml.snakeyaml.Yaml +//import java.io.File +//import java.util.Locale +//import kotlin.concurrent.thread +//import kotlin.math.roundToInt +// +// +//var accessibilityState by mutableStateOf(false) +// +//var alertDialogPositiveButtonClickState by mutableStateOf(false) +// +//// 无障碍服务启用停用按钮 +//var isAccessibilityBtnClicked by mutableStateOf(false) +// +//// 后台任务管理 +//var isBackendTaskBtnClicked by mutableStateOf(false) +// +//// 自启动管理 +//var isAutoStartBtnClicked by mutableStateOf(false) +// +//// 省电策略按钮 +//var isPowerSavingBtnClicked by mutableStateOf(false) +// +//// 检查更新按钮 +//var isCheckUpdateBtnClicked by mutableStateOf(false) +// +//// 是否需要更新 +//var isNeedUpdateAPK by mutableStateOf(false) +// +//// 最新版本号 +//var latestVersionText by mutableStateOf("") +// +//// 立即更新 +//var isUpdateAPKClicked by mutableStateOf(false) +// +//// 更新进度对话框 +//var isProcessDialogVisible by mutableStateOf(false) +// +//var downloadProgress by mutableStateOf(0f) +// +// +//class MainActivity : ComponentActivity() { +// +// private fun openAppInfo() { +// val packageName = packageName +// val intent = Intent( +// Settings.ACTION_APPLICATION_DETAILS_SETTINGS, +// Uri.parse("package:$packageName") +// ) +// startActivity(intent) +// } +// +// private fun openAutoStartSettings(context: Context) { +// try { +// val intent = Intent() +// +// val manufacturer = Build.MANUFACTURER.lowercase(Locale.ENGLISH) +// when { +// manufacturer.contains("xiaomi") -> { +// intent.component = ComponentName( +// "com.miui.securitycenter", +// "com.miui.permcenter.autostart.AutoStartManagementActivity" +// ) +// } +// manufacturer.contains("oppo") -> { +// intent.component = ComponentName( +// "com.coloros.safecenter", +// "com.coloros.safecenter.permission.startup.StartupAppListActivity" +// ) +// } +// manufacturer.contains("vivo") -> { +// intent.component = ComponentName( +// "com.vivo.permissionmanager", +// "com.vivo.permissionmanager.activity.BgStartUpManagerActivity" +// ) +// } +// manufacturer.contains("oneplus") -> { +// intent.component = ComponentName( +// "com.oneplus.security", +// "com.oneplus.security.chainlaunch.view.ChainLaunchAppListAct‌​ivity" +// ) +// } +// manufacturer.contains("huawei") -> { +// intent.component = ComponentName( +// "com.huawei.systemmanager", +// "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity" +// ) +// } +// else -> { +// openAppInfo() +// } +// } +// +// context.startActivity(intent) +// } catch (e: Exception) { +// openAppInfo() +// } +// } +// +// private fun openBatteryOptimizationSettings(context: Context) { +// try { +// val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) +// intent.data = Uri.parse("package:${context.packageName}") +// context.startActivity(intent) +// } catch (e: Exception) { +// openAppInfo() +// } +// } +// +// override fun onCreate(savedInstanceState: Bundle?) { +// +// super.onCreate(savedInstanceState) +// +// setContent { +// +// val displayMetrics = LocalContext.current.resources.displayMetrics +// val widthPixels = displayMetrics.widthPixels +// val fontScale = LocalDensity.current.fontScale +// +// CompositionLocalProvider( +// LocalDensity provides Density( +// density = widthPixels / 360.0f, +// fontScale = fontScale +// ) +// ) { +// MainSurface() +// ProcessDialog() +// } +// +// +// if (isAccessibilityBtnClicked) { +// if (!accessibilityState) { +// AlertDialog( +// context = this, +// title = "启用无障碍服务", +// message = "已下载的应用 > SKIP > 打开「使用SKIP」", +// negativeText = "再想想", +// positiveText = "去开启" +// ) { +// alertDialogPositiveButtonClickState = true +// } +// } else { +// AlertDialog( +// context = this, +// title = "停用无障碍服务", +// message = "已下载的应用 > SKIP > 关闭「使用SKIP」", +// negativeText = "再想想", +// positiveText = "去停用" +// ) { +// alertDialogPositiveButtonClickState = true +// } +// } +// isAccessibilityBtnClicked = false +// } +// +// if (isNeedUpdateAPK) { +// AlertDialog( +// context = this, +// title = "发现新版本", +// message = "${BuildConfig.VERSION_NAME} -> $latestVersionText", +// negativeText = "暂不更新", +// positiveText = "立即更新" +// ) { +// isUpdateAPKClicked = true +// } +// isNeedUpdateAPK = false +// } +// +// when { +// alertDialogPositiveButtonClickState -> { +// val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) +// this.startActivity(intent) +// alertDialogPositiveButtonClickState = false +// } +// isAutoStartBtnClicked -> { +// openAutoStartSettings(this) +// isAutoStartBtnClicked = false +// } +// isPowerSavingBtnClicked -> { +// openBatteryOptimizationSettings(this) +// isPowerSavingBtnClicked = false +// } +// isBackendTaskBtnClicked -> { +// ImageDialog() +// } +// isCheckUpdateBtnClicked -> { +// thread { +// ToastManager.showToast(this, "开始检查更新") +// val updateSkipConfigResult = +// if (HttpManager.updateSkipConfig()) "配置更新成功" else "配置更新失败" +// ToastManager.showToast(this, updateSkipConfigResult) +// +// val latestVersion = HttpManager.getLatestVersion() +// if (latestVersion != BuildConfig.VERSION_NAME.trim()) { +// isNeedUpdateAPK = true +// latestVersionText = latestVersion +// } else { +// ToastManager.showToast(this, "当前版本已是最新版") +// } +// +// isCheckUpdateBtnClicked = false +// } +// } +// isUpdateAPKClicked -> { +// thread { +// isProcessDialogVisible = true +// HttpManager.downloadNewAPK(latestVersionText, this) { it -> +// downloadProgress = it * 0.01f +// if (it == 100) isProcessDialogVisible = false +// } +// val latestVersionAPK = "SKIP-v$latestVersionText.apk" +// val apkFile = File(this.getExternalFilesDir(null), latestVersionAPK) +// +// val apkUri = FileProvider.getUriForFile( +// this, +// this.applicationContext.packageName + ".provider", +// apkFile +// ) +// +// val intent = Intent(Intent.ACTION_VIEW) +// intent.setDataAndType(apkUri, "application/vnd.android.package-archive") +// intent.flags = +// Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION +// this.startActivity(intent) +// +// isUpdateAPKClicked = false +// } +// } +// } +// +// } +// +// RectManager.setMaxRect(this) +// +// val yaml = Yaml().load>(assets.open("skip_config.yaml")) +// SkipConfigManager.setConfig(yaml) +// +// // 清理临时文件 +// val directory = this.getExternalFilesDir(null) +// directory?.let { +// it.listFiles()?.forEach { file -> +// file.delete() +// } +// } +// } +// +// override fun onResume() { +// super.onResume() +// accessibilityState = MyUtils.isAccessibilitySettingsOn(this) +// } +//} +// +// +//@Composable +//@Preview(showBackground = true) +//fun MainSurface() { +// AppTheme { +// +// val res = LocalContext.current.resources +// +// PageHeader(res.getString(R.string.app_name), "是一款免费开源的自动跳过开屏广告的工具") +// +// +// Box( +// modifier = Modifier.fillMaxSize(), +// contentAlignment = Alignment.Center +// ) { +// Box(modifier = Modifier.offset(y = (-50).dp)) { +// AccessibilityControlBtn() +// } +// } +// +// Box( +// modifier = Modifier.fillMaxSize(), +// contentAlignment = Alignment.Center +// ) { +// Box(modifier = Modifier.offset(y = (90).dp)) { +// AccessibilityTextBox() +// } +// } +// +// Box( +// modifier = Modifier.fillMaxSize(), +// contentAlignment = Alignment.BottomCenter +// ) { +// TipBox() +// PageFooter() +// } +// +// } +//} +// +//@Composable +//fun PageHeader(title: String, subtitle: String) { +// Column( +// modifier = Modifier +// .fillMaxWidth() +// .padding(top = 60.dp, start = 20.dp) +// ) { +// Text( +// text = title, +// color = Color.White, +// fontSize = 36.sp, +// fontWeight = FontWeight.Bold, +// modifier = Modifier.padding(bottom = 8.dp) +// ) +// Text( +// text = subtitle, +// color = Color.White, +// fontSize = 16.sp, +// ) +// } +//} +// +//@Composable +//fun AccessibilityTextBox() { +// Row { +// if (accessibilityState) { +// Text(text = "无障碍服务功能: 启用中", color = Color.White) +// } else { +// Text(text = "无障碍服务功能: 未启用", color = Color.White) +// } +// +// } +//} +// +//@Composable +//fun TipBox() { +// +// Column( +// modifier = Modifier +// .background(color = Color.White) +// .height(240.dp) +// .fillMaxWidth() +// .padding(start = 15.dp, top = 10.dp) +// ) { +// Text( +// "操作方式", +// fontWeight = FontWeight.Bold, +// fontSize = 18.sp, +// modifier = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) +// ) +// +// Row { +// TipText("第一步:进入「") +// ClickableText("后台任务管理", onClick = { clicked -> isBackendTaskBtnClicked = clicked }) +// TipText("」,长按「SKIP」,锁定") +// } +// +// Row { +// TipText("第二步:进入「") +// ClickableText("省电策略", onClick = { clicked -> isPowerSavingBtnClicked = clicked }) +// TipText("」,无限制") +// } +// +// Row { +// TipText("第三步:进入「") +// ClickableText("自启动管理", onClick = { clicked -> isAutoStartBtnClicked = clicked }) +// TipText("」,找到「SKIP」,允许") +// } +// +// Text( +// "注意事项", +// fontWeight = FontWeight.Bold, +// fontSize = 18.sp, +// modifier = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) +// ) +// +// TipText("由于无障碍服务会在应用进程结束后自动关闭,因此需要完成上述操作开启应用后台运行权限") +// +// +// } +//} +// +//@Composable +//fun TipText(text: String) { +// Text( +// text, +// fontSize = 14.sp, +// color = Color.Gray, +// modifier = Modifier.padding(0.dp, 2.5.dp, 0.dp, 2.5.dp) +// ) +//} +// +// +//@Composable +//fun ClickableText(text: String, onClick: (Boolean) -> Unit) { +// val annotatedString = buildAnnotatedString { +// append(text) +// addStyle( +// style = SpanStyle(textDecoration = androidx.compose.ui.text.style.TextDecoration.Underline), +// start = 0, +// end = length +// ) +// addStringAnnotation( +// tag = "Clickable", +// annotation = "Details", +// start = 0, +// end = length +// ) +// } +// +// ClickableText( +// text = annotatedString, +// modifier = Modifier.padding(0.dp, 2.5.dp, 0.dp, 2.5.dp), +// onClick = { offset -> +// annotatedString.getStringAnnotations("Clickable", offset, offset) +// .firstOrNull()?.let { _ -> +// onClick(true) +// } +// } +// ) +//} +// +// +//@Composable +//fun AccessibilityControlBtn() { +// Button( +// onClick = { +// isAccessibilityBtnClicked = true +// }, +// contentPadding = PaddingValues(0.dp), +// colors = ButtonDefaults.textButtonColors() +// ) { +// if (accessibilityState) { +// Image( +// modifier = Modifier.size(140.dp, 140.dp), +// painter = painterResource(id = R.drawable.disabled), +// contentDescription = "disabled", +// ) +// } else { +// Image( +// modifier = Modifier.size(140.dp, 140.dp), +// painter = painterResource(id = R.drawable.enabled), +// contentDescription = "enabled", +// ) +// } +// } +//} +// +//@Composable +//fun PageFooter() { +// val context = LocalContext.current +// val coroutineScope = rememberCoroutineScope() +// +// Row( +// modifier = Modifier +// .fillMaxWidth() +// .height(45.dp) +// .background(color = Color.White), +// verticalAlignment = Alignment.CenterVertically, +// horizontalArrangement = Arrangement.Center +// ) { +// val annotatedString = buildAnnotatedString { +// withStyle(style = SpanStyle(color = Color.Black, fontSize = 12.sp)) { +// append("Github") +// addStringAnnotation( +// tag = "URL", +// annotation = "https://github.com/GuoXiCheng/SKIP", +// start = 0, +// end = 6 +// ) +// append(" | ") +// append(RectManager.getMaxRect()) +// append(" | version " + BuildConfig.VERSION_NAME) +// append(" | ") +// append("检查更新") +// addStringAnnotation( +// tag = "CHECK_UPDATE", +// annotation = "", +// start = length - 4, +// end = length +// ) +// } +// } +// ClickableText( +// text = annotatedString, +// onClick = { offset -> +// annotatedString.getStringAnnotations(start = offset, end = offset).firstOrNull() +// ?.let { annotation -> +// when (annotation.tag) { +// "URL" -> { +// val url = annotation.item +// coroutineScope.launch { +// val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) +// context.startActivity(intent) +// } +// } +// "CHECK_UPDATE" -> { +// isCheckUpdateBtnClicked = true +// } +// } +// } +// } +// ) +// } +//} +// +// +//@Composable +//fun AlertDialog( +// context: Context, title: CharSequence, +// message: CharSequence?, negativeText: CharSequence, +// positiveText: CharSequence, onPositiveButtonClick: () -> Unit +//) { +// MaterialAlertDialogBuilder(context) +// .setTitle(title) +// .setMessage(message) +// .setNegativeButton(negativeText, null) +// .setPositiveButton(positiveText) { _, _ -> +// onPositiveButtonClick() +// } +// .show() +//} +// +//@Composable +//fun ImageDialog() { +// AlertDialog( +// onDismissRequest = { isBackendTaskBtnClicked = false }, +// containerColor = Color.White, +// text = { +// Box(modifier = Modifier.fillMaxWidth()) { +// Image( +// painter = painterResource(R.drawable.backend_lock), // 设置要显示的图片 +// contentDescription = "Image", +// modifier = Modifier.fillMaxWidth() +// ) +// } +// }, +// confirmButton = { +// Row( +// modifier = Modifier.fillMaxWidth(), +// horizontalArrangement = Arrangement.Center +// ) { +// TextButton( +// onClick = { isBackendTaskBtnClicked = false }, +// colors = ButtonDefaults.textButtonColors(contentColor = green) +// ) { +// Text(text = "我知道了") +// } +// } +// +// } +// ) +//} +// +//@Composable +//fun ProcessDialog() { +// if (isProcessDialogVisible) { +// AlertDialog( +// onDismissRequest = { +// isProcessDialogVisible = false +// }, +// title = { +// Text(text = "正在下载") +// }, +// text = { +// Column( +// horizontalAlignment = Alignment.CenterHorizontally, +// verticalArrangement = Arrangement.Center, +// modifier = Modifier.padding(16.dp) +// ) { +// LinearProgressIndicator(progress = downloadProgress) +// Spacer(modifier = Modifier.height(16.dp)) +// Text(text = "下载进度:${(downloadProgress * 100).roundToInt()}%") +// } +// }, +// confirmButton = { +// }, +// dismissButton = { +// } +// ) +// } +//} +// +// diff --git a/app/src/main/java/com/android/skip/MyUtils.kt b/app/src/main/java/com/android/skip/MyUtils.kt deleted file mode 100644 index 20013cdb..00000000 --- a/app/src/main/java/com/android/skip/MyUtils.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.android.skip -import android.content.Context -import android.provider.Settings -import android.text.TextUtils -import com.android.skip.service.MyAccessibilityService - -object MyUtils { - /** - * 判断无障碍服务是否已经启用 - */ - fun isAccessibilitySettingsOn(mContext: Context): Boolean { - var accessibilityEnabled = 0 - val service = mContext.packageName + "/" + MyAccessibilityService::class.java.canonicalName - try { - accessibilityEnabled = Settings.Secure.getInt( - mContext.applicationContext.contentResolver, - android.provider.Settings.Secure.ACCESSIBILITY_ENABLED - ) - } catch (e: Settings.SettingNotFoundException) { - } - val mStringColonSplitter = TextUtils.SimpleStringSplitter(':') - if (accessibilityEnabled == 1) { - val settingValue = Settings.Secure.getString( - mContext.applicationContext.contentResolver, - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES - ) - if (settingValue != null) { - mStringColonSplitter.setString(settingValue) - while (mStringColonSplitter.hasNext()) { - val accessibilityService = mStringColonSplitter.next() - if (accessibilityService.equals(service, ignoreCase = true)) { - return true - } - } - } - } - return false - } -} \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/NewMainActivity.kt b/app/src/main/java/com/android/skip/NewMainActivity.kt index 77261c1b..a802ef3a 100644 --- a/app/src/main/java/com/android/skip/NewMainActivity.kt +++ b/app/src/main/java/com/android/skip/NewMainActivity.kt @@ -1,6 +1,10 @@ package com.android.skip +import android.content.Context +import android.content.Intent import android.os.Bundle +import android.provider.Settings +import android.text.TextUtils import androidx.activity.viewModels import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -11,22 +15,44 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.content.FileProvider import androidx.lifecycle.lifecycleScope import com.android.skip.compose.AboutButton +import com.android.skip.compose.ConfirmDialog +import com.android.skip.compose.DownloadProcessDialog import com.android.skip.compose.KeepAliveButton import com.android.skip.compose.SettingsButton import com.android.skip.compose.StartButton import com.android.skip.compose.WhitelistButton import com.android.skip.dataclass.PackageInfoV2 +import com.android.skip.manager.HttpManager import com.android.skip.manager.SkipConfigManagerV2 import com.android.skip.manager.WhitelistManager +import com.android.skip.service.MyAccessibilityService +import com.android.skip.utils.DataStoreUtils import com.android.skip.viewmodel.StartButtonViewModel import org.yaml.snakeyaml.Yaml +import java.io.File +import kotlin.concurrent.thread +var showUpdateDialog by mutableStateOf(false) + +var showDownloadDialog by mutableStateOf(false) + +var showApkInstallDialog by mutableStateOf(false) + +var apkDownloadProgress by mutableStateOf(0f) + +var apkLatestVersionText by mutableStateOf(BuildConfig.VERSION_NAME.trim()) class NewMainActivity : BaseActivity() { private val startButtonViewModel: StartButtonViewModel by viewModels() @@ -44,6 +70,7 @@ class NewMainActivity : BaseActivity() { @Composable override fun ProvideContent() { + val context = LocalContext.current Column( modifier = Modifier .fillMaxSize() @@ -53,7 +80,7 @@ class NewMainActivity : BaseActivity() { ) { Row { Text( - text = "SKIP", + text = stringResource(id = R.string.app_name), fontSize = 24.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground @@ -64,12 +91,110 @@ class NewMainActivity : BaseActivity() { KeepAliveButton() SettingsButton() AboutButton() + + if (showUpdateDialog) { + ConfirmDialog( + title = "发现新版本", + content = "是否立即下载更新?", + onDismiss = { showUpdateDialog = false }, + onAllow = { + showUpdateDialog = false + showDownloadDialog = true + }) + } + + if (showDownloadDialog) { + DownloadProcessDialog() + + thread { + HttpManager.downloadNewAPK(apkLatestVersionText, context) { it -> + apkDownloadProgress = it * 0.01f + if (it == 100) { + showDownloadDialog = false + showApkInstallDialog = true + } + } + } + } + + if (showApkInstallDialog) { + ConfirmDialog( + title = "下载完成", + content = "是否立即安装新版本?", + onDismiss = { showApkInstallDialog = false }, + onAllow = { + showApkInstallDialog = false + + val filename = "SKIP-v$apkLatestVersionText.apk" + val apkFile = File(context.getExternalFilesDir(null), filename) + val apkUri = FileProvider.getUriForFile( + context, + context.applicationContext.packageName + ".provider", + apkFile + ) + + val intent = Intent(Intent.ACTION_VIEW) + intent.setDataAndType(apkUri, "application/vnd.android.package-archive") + intent.flags = + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + context.startActivity(intent) + }) + } } } override fun onResume() { super.onResume() - startButtonViewModel.changeButtonState(MyUtils.isAccessibilitySettingsOn(this)) + startButtonViewModel.changeButtonState(isAccessibilitySettingsOn(this)) WhitelistManager.setWhitelist(lifecycleScope, applicationContext) + + if (DataStoreUtils.getSyncData(SKIP_AUTO_SYNC_CONFIG, false)) { + thread { + HttpManager.updateSkipConfigV2() + } + } + + if (DataStoreUtils.getSyncData(SKIP_AUTO_CHECK_UPDATE, false)) { + thread { + val latestVersion = HttpManager.getLatestVersion() + if (latestVersion != BuildConfig.VERSION_NAME.trim()) { + apkLatestVersionText = latestVersion + showUpdateDialog = true + } + } + } + } +} + +/** + * 判断无障碍服务是否已经启用 + */ +fun isAccessibilitySettingsOn(mContext: Context): Boolean { + var accessibilityEnabled = 0 + val service = mContext.packageName + "/" + MyAccessibilityService::class.java.canonicalName + try { + accessibilityEnabled = Settings.Secure.getInt( + mContext.applicationContext.contentResolver, + android.provider.Settings.Secure.ACCESSIBILITY_ENABLED + ) + } catch (e: Settings.SettingNotFoundException) { + e.printStackTrace() + } + val mStringColonSplitter = TextUtils.SimpleStringSplitter(':') + if (accessibilityEnabled == 1) { + val settingValue = Settings.Secure.getString( + mContext.applicationContext.contentResolver, + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + ) + if (settingValue != null) { + mStringColonSplitter.setString(settingValue) + while (mStringColonSplitter.hasNext()) { + val accessibilityService = mStringColonSplitter.next() + if (accessibilityService.equals(service, ignoreCase = true)) { + return true + } + } + } } + return false } \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/SettingsActivity.kt b/app/src/main/java/com/android/skip/SettingsActivity.kt index dcfe9b39..22b11404 100644 --- a/app/src/main/java/com/android/skip/SettingsActivity.kt +++ b/app/src/main/java/com/android/skip/SettingsActivity.kt @@ -57,14 +57,14 @@ fun SettingsActivityInterface(onBackClick: () -> Unit) { val checkUpdateVersion = remember { mutableStateOf( DataStoreUtils.getSyncData( - SKIP_AUTO_CHECK_UPDATE, true + SKIP_AUTO_CHECK_UPDATE, false ) ) } val checkUpdateConfig = remember { mutableStateOf( DataStoreUtils.getSyncData( - SKIP_AUTO_SYNC_CONFIG, true + SKIP_AUTO_SYNC_CONFIG, false ) ) } diff --git a/app/src/main/java/com/android/skip/compose/CheckNewVersionButton.kt b/app/src/main/java/com/android/skip/compose/CheckNewVersionButton.kt deleted file mode 100644 index f4b6eccd..00000000 --- a/app/src/main/java/com/android/skip/compose/CheckNewVersionButton.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.android.skip.compose - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.res.stringResource -import com.android.skip.R - -@Composable -fun CheckNewVersionButton() { - val showDialog = remember { mutableStateOf(false) } - - FlatButton( - content = { - RowContent(stringResource(id = R.string.main_check_new_version), null, { - ResourceIcon( - iconResource = R.drawable.sync - ) - }) - } - ) { - showDialog.value = true - } - - if (showDialog.value) { - ConfirmDialog( - title = "发现新版本", - content = "是否立即下载更新?", - onDismiss = { showDialog.value = false }, - onAllow = { - showDialog.value = false - }) - } -} diff --git a/app/src/main/java/com/android/skip/compose/ConfigUpdateButton.kt b/app/src/main/java/com/android/skip/compose/ConfigUpdateButton.kt deleted file mode 100644 index b7a2b7ae..00000000 --- a/app/src/main/java/com/android/skip/compose/ConfigUpdateButton.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.android.skip.compose - -import androidx.compose.runtime.Composable -import com.android.skip.R - -@Composable -fun ConfigUpdateButton() { - FlatButton( - content = { - RowContent("点此同步配置", null, { ResourceIcon(iconResource = R.drawable.lists) }) - }) { - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/compose/ConfirmDialog.kt b/app/src/main/java/com/android/skip/compose/ConfirmDialog.kt index b754f5a9..0206038f 100644 --- a/app/src/main/java/com/android/skip/compose/ConfirmDialog.kt +++ b/app/src/main/java/com/android/skip/compose/ConfirmDialog.kt @@ -1,5 +1,7 @@ package com.android.skip.compose +import android.content.res.Configuration +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,6 +12,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -20,9 +23,13 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog +import com.android.skip.R +import com.android.skip.themeTypeState @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -32,6 +39,7 @@ fun ConfirmDialog( onDismiss: () -> Unit, onAllow: () -> Unit ) { + val darkTheme = isSystemInDarkTheme() Dialog(onDismissRequest = { /* 点击外部不关闭对话框 */ }) { Card( modifier = Modifier.height(200.dp), @@ -65,10 +73,12 @@ fun ConfirmDialog( Button( onClick = onDismiss, modifier = Modifier.weight(1f), - colors = ButtonDefaults.buttonColors(Color(0xFFE0E0E0)) + colors = if (darkTheme || themeTypeState.value == Configuration.UI_MODE_NIGHT_YES) ButtonDefaults.buttonColors( + Color(0xFF454545) + ) else ButtonDefaults.buttonColors(Color(0xFFF0F0F0)) ) { Text( - text = "拒绝", + text = stringResource(id = R.string.dialog_confirm_dismiss), color = Color(0xFFc3c3c3), fontSize = 16.sp ) @@ -82,7 +92,7 @@ fun ConfirmDialog( ) ) { Text( - text = "允许", + text = stringResource(id = R.string.dialog_confirm_allow), color = Color.White, fontSize = 16.sp ) diff --git a/app/src/main/java/com/android/skip/compose/DownloadProcessDialog.kt b/app/src/main/java/com/android/skip/compose/DownloadProcessDialog.kt new file mode 100644 index 00000000..7312404c --- /dev/null +++ b/app/src/main/java/com/android/skip/compose/DownloadProcessDialog.kt @@ -0,0 +1,48 @@ +package com.android.skip.compose + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.android.skip.apkDownloadProgress +import kotlin.math.roundToInt + +@Composable +fun DownloadProcessDialog() { + AlertDialog( + onDismissRequest = {}, + title = { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + Text(text = "正在下载") + } + }, + text = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.padding(16.dp) + ) { + LinearProgressIndicator(progress = apkDownloadProgress) + Spacer(modifier = Modifier.height(16.dp)) + Text(text = "下载进度:${(apkDownloadProgress * 100).roundToInt()}%") + } + }, + confirmButton = {}, + dismissButton = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/compose/OpenBrowserDialog.kt b/app/src/main/java/com/android/skip/compose/OpenBrowserDialog.kt new file mode 100644 index 00000000..43225477 --- /dev/null +++ b/app/src/main/java/com/android/skip/compose/OpenBrowserDialog.kt @@ -0,0 +1,26 @@ +package com.android.skip.compose + +import android.content.Intent +import android.net.Uri +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.skip.R + +@Composable +fun OpenBrowserDialog(openName: String, openUrl: String, showDialog: MutableState) { + val context = LocalContext.current + + if (showDialog.value) { + ConfirmDialog( + title = stringResource(id = R.string.dialog_open_browser_title), + content = stringResource(id = R.string.dialog_open_browser_content) + openName, + onDismiss = { showDialog.value = false }, + onAllow = { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(openUrl)) + context.startActivity(intent) + showDialog.value = false + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/manager/HttpManager.kt b/app/src/main/java/com/android/skip/manager/HttpManager.kt index e219fcef..6c21c6fa 100644 --- a/app/src/main/java/com/android/skip/manager/HttpManager.kt +++ b/app/src/main/java/com/android/skip/manager/HttpManager.kt @@ -26,6 +26,19 @@ object HttpManager { } } + fun updateSkipConfigV2() { + try { + val request = Request.Builder().url("$BASE_URL/skip_config_v2.yaml").build() + client.newCall(request).execute().use {response -> + val bodyContent = response.body()?.string() + val yaml = Yaml().load(bodyContent) + SkipConfigManagerV2.setConfig(yaml) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + fun getLatestVersion(): String { return try { val request = Request.Builder().url("$BASE_URL/latest_version.txt").build() @@ -62,7 +75,7 @@ object HttpManager { } } } catch (e: Exception) { - LogManager.i(e.toString()) + e.printStackTrace() } } } \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/manager/LogManager.kt b/app/src/main/java/com/android/skip/manager/LogManager.kt deleted file mode 100644 index d2bc96dc..00000000 --- a/app/src/main/java/com/android/skip/manager/LogManager.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.android.skip.manager - -import android.util.Log - -object LogManager { - private const val TAG = "SKIPS" - - private const val DEBUG = false - - fun i(message: String) { - if (DEBUG) { - Log.i(TAG, message) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/android/skip/ui/theme/Theme.kt b/app/src/main/java/com/android/skip/ui/theme/Theme.kt index 2e761302..c418c3c7 100644 --- a/app/src/main/java/com/android/skip/ui/theme/Theme.kt +++ b/app/src/main/java/com/android/skip/ui/theme/Theme.kt @@ -10,15 +10,12 @@ import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.core.view.ViewCompat -import com.android.skip.SKIP_APP_THEME -import com.android.skip.utils.DataStoreUtils +import com.android.skip.themeTypeState private val darkColorScheme = darkColorScheme( primary = Purple80, @@ -37,7 +34,6 @@ private val lightColorScheme = lightColorScheme( ) - @Composable fun AppTheme( darkTheme: Boolean = isSystemInDarkTheme(), @@ -50,6 +46,7 @@ fun AppTheme( val context = LocalContext.current if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } + darkTheme -> darkColorScheme else -> lightColorScheme } @@ -58,6 +55,9 @@ fun AppTheme( SideEffect { (view.context as Activity).window.statusBarColor = colorScheme.background.toArgb() ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme + // 根据主题设置状态栏图标和文字颜色 + ViewCompat.getWindowInsetsController((view.context as Activity).window.decorView)?.isAppearanceLightStatusBars = + !darkTheme || themeTypeState.value != Configuration.UI_MODE_NIGHT_YES } } diff --git a/app/src/main/res/drawable-v24/backend_lock.jpg b/app/src/main/res/drawable-v24/backend_lock.jpg index 23392b6c..0aa9f653 100644 Binary files a/app/src/main/res/drawable-v24/backend_lock.jpg and b/app/src/main/res/drawable-v24/backend_lock.jpg differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4b854c5b..39655cb8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,10 +5,12 @@ 检查更新 关于 - SKIP 源代码地址 + 源代码 https://github.com/GuoXiCheng/SKIP - SKIP Docs文档地址 + 文档 https://guoxicheng.top/projects/SKIP-Docs + 当前版本号: + 当前分辨率: 设置 浅色模式 @@ -32,7 +34,13 @@ 后台任务管理 进入最近打开程序页面,长按「SKIP」卡片,锁定 请注意 - 以上操作方法可能仅适用于MIUI手机,其他品牌手机请自行查询相应的应用保活方法 + 以上操作方法可能仅适用于MIUI或HyperOS,其他系统手机请自行查询相应的应用保活方法 + 如何实现应用后台保活 应用白名单 + + 允许 + 拒绝 + 启动浏览器 + 是否要通过浏览器访问 \ No newline at end of file