commit 888deb17e8437108871881a4874d2bb01acdab1a Author: litingting Date: Tue Jul 2 15:16:49 2024 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6a69ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +/.safedk/dex/android-support-multidex.dex +/app/release/baselineProfiles/0/app-release.dm +/app/release/baselineProfiles/1/app-release.dm +/app/release/AppLock Defender1.0(1).aab +/.safedk/list.enc +/app/release/output-metadata.json +/.safedk/proguard-safedk.pro +/.safedk/dex/SafeDKAndroid-6.2.5.dex +/.safedk/api/SafeDKAndroid-6.2.5.jar +gradle.properties +gradlew +gradlew.bat +.idea/.gitignore +.idea/.name +.idea/appInsightsSettings.xml +.idea/compiler.xml +.idea/dbnavigator.xml +.idea/deploymentTargetDropDown.xml +.idea/deploymentTargetSelector.xml +.idea/gradle.xml +.idea/kotlinc.xml +.idea/migrations.xml +.idea/misc.xml +.idea/vcs.xml +.safedk/app_sdks.lst +.safedk/hashes.safedk +.safedk/plugin.properties +.safedk/api/SafeDKAndroid-6.2.6.jar +.safedk/api/SafeDKAndroid-6.3.1.jar +.safedk/dex/SafeDKAndroid-6.3.1.dex +app/release/AppLock Defender1.1(2).aab +app/release/app-release.apk diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..c15f53e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,74 @@ +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.jetbrainsKotlinAndroid) + id("kotlin-kapt") + id("com.google.gms.google-services") + id("com.google.firebase.crashlytics") + id("applovin-quality-service") +} + +applovin { + apiKey "gaubl3w6OhMaWqmJb15zVNMO8W91OOSTe2fnoftZMmDkQFTnwMdQVdOdPOMwLRbglPnJsKHfqoPl079qleMk96" +} + +android { + namespace 'com.kitobochi.softapp.timberlock' + compileSdk 34 + + defaultConfig { + applicationId "com.applock.privacy.defender" + minSdk 22 + targetSdk 34 + versionCode 2 + versionName "1.1" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + + debug { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation libs.androidx.core.ktx + implementation libs.androidx.appcompat + implementation libs.material + implementation libs.androidx.activity + implementation libs.androidx.constraintlayout + testImplementation libs.junit + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.espresso.core + + kapt 'androidx.room:room-compiler:2.6.1' + implementation 'androidx.room:room-runtime:2.6.1' + implementation("androidx.room:room-ktx:2.6.1") + + implementation(platform("com.google.firebase:firebase-bom:32.3.1")) + implementation("com.google.firebase:firebase-analytics-ktx") + implementation("com.google.firebase:firebase-crashlytics-ktx") + + implementation("com.applovin:applovin-sdk:+") + implementation("com.applovin.mediation:vungle-adapter:+") + implementation("com.applovin.mediation:bytedance-adapter:+") + implementation("com.applovin.mediation:mintegral-adapter:+") + +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..f4a8f8a --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "36819996956", + "project_id": "applock-defender---security", + "storage_bucket": "applock-defender---security.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:36819996956:android:63137f1a9ab4d34a37ead9", + "android_client_info": { + "package_name": "com.applock.privacy.defender" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBGf4ZJn19sNlDd8U1Qt9L9vOUfyNTlF8I" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/info/info.txt b/app/info/info.txt new file mode 100644 index 0000000..6f6d83e --- /dev/null +++ b/app/info/info.txt @@ -0,0 +1,6 @@ +包名:com.applock.privacy.defender +应用名:AppLock Defender + +别名:key_applock_defender +key:key_applock_defender +password:key123456 \ No newline at end of file diff --git a/app/info/key_applock_defender.jks b/app/info/key_applock_defender.jks new file mode 100644 index 0000000..25e278c Binary files /dev/null and b/app/info/key_applock_defender.jks differ diff --git a/app/info/key_applock_defender_test.jks b/app/info/key_applock_defender_test.jks new file mode 100644 index 0000000..1a587fe Binary files /dev/null and b/app/info/key_applock_defender_test.jks differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..60e9391 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,35 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# room base +-keepclassmembers class * { + @androidx.room.Query ; +} + +-keepclassmembers class com.kitobochi.softapp.timberlock.db.AppDatabaseManager{ + public static final java.lang.String DB_NAME; + public static final int DB_VERSION; +} + +-keep class com.kitobochi.softapp.timberlock.db.AppDatabase { *; } +-keep class com.kitobochi.softapp.timberlock.db.AppDao { *; } +-keep class com.kitobochi.softapp.timberlock.db.AppEntity { *; } diff --git a/app/src/androidTest/java/com/kitobochi/softapp/timberlock/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/kitobochi/softapp/timberlock/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..fa93f02 --- /dev/null +++ b/app/src/androidTest/java/com/kitobochi/softapp/timberlock/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.kitobochi.softapp.timberlock + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.kitobochi.softapp.timberlock", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..45b2051 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/App.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/App.kt new file mode 100644 index 0000000..59e1339 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/App.kt @@ -0,0 +1,88 @@ +package com.kitobochi.softapp.timberlock + +import android.app.Application +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.applovin.sdk.AppLovinMediationProvider +import com.applovin.sdk.AppLovinSdk +import com.applovin.sdk.AppLovinSdkInitializationConfiguration +import com.kitobochi.softapp.timberlock.db.AppDatabase +import com.kitobochi.softapp.timberlock.db.AppEntity +import com.kitobochi.softapp.timberlock.tools.AppListManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + + +class App : Application() { + private val spName = "share_name" + private val PWD_KEY = "locker_pwd" + val reqCodeUsage = 1 + val reqCodeOverlays = 2 + + companion object { + lateinit var appContext: Context + lateinit var sp: SharedPreferences + lateinit var SpEditor: SharedPreferences.Editor + + const val ADSDK = "2qIXFPBROAqtuAoW4uQ78MTqJTfXWGurGLpQvE0iae3vmVXLa8SMxnxgdtq9O1GU3qQVRR1EcHhpS74qiyL8CK" + const val AD_INIT = "on_success_action" + var initOK = false + var count = 0 + } + + override fun onCreate() { + super.onCreate() + appContext = this + + initSp() + + CoroutineScope(Dispatchers.IO).launch { + for (appEntity: AppEntity in AppDatabase.database.getAppDao().findApp()!!) { + val isNeedDelete = AppListManager().delUnInstallApp(appContext, appEntity.packageName) + if (isNeedDelete) { + AppDatabase.database.getAppDao().deleteData(appEntity) + } + } + } + + val pwd = getPwd() + if (pwd.isEmpty()) { + AppListManager().getAppList(appContext, false) + } else { + AppListManager().getAppList(appContext, true) + } + + initSDK() + } + + private fun initSDK() { + + val initConfig = AppLovinSdkInitializationConfiguration.builder(ADSDK, this) + .setMediationProvider(AppLovinMediationProvider.MAX) + .build() + + AppLovinSdk.getInstance(this).initialize(initConfig){ + initOK = true + LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(AD_INIT)) + } + AppLovinSdk.getInstance(this).settings.setVerboseLogging(true) + + } + + public fun updatePwd(pwd: String) { + SpEditor.putString(PWD_KEY, pwd) + SpEditor.apply() + } + + public fun getPwd(): String { + return sp.getString(PWD_KEY, "")!! + } + + private fun initSp() { + sp = App.appContext.getSharedPreferences(spName, Context.MODE_PRIVATE) + SpEditor = sp.edit() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdListener.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdListener.kt new file mode 100644 index 0000000..627f804 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdListener.kt @@ -0,0 +1,9 @@ +package com.kitobochi.softapp.timberlock.ad + +import com.applovin.mediation.MaxAd + +interface AdListener { + fun onFail(ad: MaxAd) + fun onSuccess() + fun onHidden() +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdManager.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdManager.kt new file mode 100644 index 0000000..3634548 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdManager.kt @@ -0,0 +1,78 @@ +package com.kitobochi.softapp.timberlock.ad + +import android.app.Activity +import com.applovin.mediation.MaxAd +import com.applovin.mediation.MaxAdListener +import com.applovin.mediation.MaxError +import com.applovin.mediation.ads.MaxInterstitialAd +import com.kitobochi.softapp.timberlock.App + +object AdManager { + + private val one_AD = "02d8ee636a579373" + private val two_Ad = "02d8ee636a579373" + private val three_ad = "0b004d33e636f7f8" + + private val list: MutableList = mutableListOf() + + fun onCache(list: List): MaxInterstitialAd? { + list.shuffled() + for (ad in list) { + if (ad.isReady) { + return ad + } + } + return null + } + + fun adLoad(): List { + if (list.isEmpty()) { + val ad_two = MaxInterstitialAd(two_Ad, App.appContext) + val ad_one = MaxInterstitialAd(one_AD, App.appContext) + val ad_three = MaxInterstitialAd(three_ad, App.appContext) + ad_two.loadAd() + ad_one.loadAd() + ad_three.loadAd() + + list.add(ad_one) + list.add(ad_two) + list.add(ad_three) + } + for (ad: MaxInterstitialAd in list) { + if (!ad.isReady) { + ad.loadAd() + } + } + + return list + } + + fun setAdListener(ad: MaxInterstitialAd, listener: AdListener) { + ad.setListener(object : MaxAdListener { + override fun onAdLoaded(p0: MaxAd) { + + } + + override fun onAdDisplayed(p0: MaxAd) { + listener.onSuccess() + } + + override fun onAdHidden(p0: MaxAd) { + listener.onHidden() + } + + override fun onAdClicked(p0: MaxAd) { + + } + + override fun onAdLoadFailed(p0: String, p1: MaxError) { + + } + + override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) { + listener.onFail(p0) + } + }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdMsgListener.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdMsgListener.kt new file mode 100644 index 0000000..a69bc08 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ad/AdMsgListener.kt @@ -0,0 +1,5 @@ +package com.kitobochi.softapp.timberlock.ad + +interface AdMsgListener { + fun msg(msg: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDao.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDao.kt new file mode 100644 index 0000000..88acb83 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDao.kt @@ -0,0 +1,29 @@ +package com.kitobochi.softapp.timberlock.db + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update + +@Dao +interface AppDao { + @Delete + fun deleteData(dataApp: AppEntity) + + @Query("select * from t_data_app where packageName=:packName") + fun findByPackName(packName: String): AppEntity? + + @Query("select * from t_data_app where isSyStem=:system AND isRecommend = :recommend") + fun findByType(system: Boolean, recommend: Boolean): List? + + @Update + fun updateData(dataApp: AppEntity) + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insertData(dataApp: AppEntity) + + @Query("select * from t_data_app") + fun findApp(): List? +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabase.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabase.kt new file mode 100644 index 0000000..da42732 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabase.kt @@ -0,0 +1,27 @@ +package com.kitobochi.softapp.timberlock.db + +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.kitobochi.softapp.timberlock.App + +@Database( + entities = [AppEntity::class], + version = AppDatabaseManager.DB_VERSION, + exportSchema = false +) +abstract class AppDatabase : RoomDatabase() { + companion object { + val database: AppDatabase by lazy { + getInstance() + } + + private fun getInstance(): AppDatabase { + return Room.databaseBuilder( + App.appContext, AppDatabase::class.java, AppDatabaseManager.DB_NAME + ).build() + } + } + + abstract fun getAppDao(): AppDao +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabaseManager.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabaseManager.kt new file mode 100644 index 0000000..68dcede --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppDatabaseManager.kt @@ -0,0 +1,7 @@ +package com.kitobochi.softapp.timberlock.db + +object AppDatabaseManager { + const val TABLE_NAME = "t_data_app" + const val DB_VERSION = 1 + const val DB_NAME = "app_db" +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppEntity.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppEntity.kt new file mode 100644 index 0000000..cbcd1a3 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/db/AppEntity.kt @@ -0,0 +1,15 @@ +package com.kitobochi.softapp.timberlock.db + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = AppDatabaseManager.TABLE_NAME, indices = [Index(value = ["packageName"], unique = true)]) +data class AppEntity( + @PrimaryKey(autoGenerate = true) var id: Int = 0, + var packageName: String = "", + var appName: String = "", + var isLock: Boolean = false, + var isSyStem: Boolean = true, + var isRecommend: Boolean = false +) \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/service/AppLockService.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/service/AppLockService.kt new file mode 100644 index 0000000..7962361 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/service/AppLockService.kt @@ -0,0 +1,75 @@ +package com.kitobochi.softapp.timberlock.service + +import android.app.IntentService +import android.content.Intent +import android.os.Handler +import android.os.Looper +import android.util.Log +import com.kitobochi.softapp.timberlock.db.AppDatabase +import com.kitobochi.softapp.timberlock.tools.LockManager +import com.kitobochi.softapp.timberlock.tools.LockServiceManager +import java.util.Objects + + +class AppLockService(name: String? = "") : IntentService(name) { + + + private lateinit var instance: LockManager + + private var lastLockPackName = "" + + override fun onHandleIntent(intent: Intent?) { + instance = LockManager(this) + val isCheckTop: Boolean = true + while (isCheckTop) { + + val packageName = LockServiceManager().checkUsageStats(this) + + if (Objects.equals(packageName, "")) { +// Log.d("-------", "continue1") +// Log.d("-------", packageName) + continue + } + + val appEntity = AppDatabase.database.getAppDao().findByPackName(packageName) + if (appEntity == null) { + val mainHandler = Handler(Looper.getMainLooper()) + mainHandler.post(Runnable { + instance.unLock() + }) + lastLockPackName = packageName +// Log.d("-------", "continue2") + continue + } + + if (Objects.equals(packageName, lastLockPackName)) { +// Log.d("-------", "continue3") + continue + } + if (appEntity.isLock) { + if (!Objects.equals(packageName, lastLockPackName)) { + + val mainHandler = Handler(Looper.getMainLooper()) + mainHandler.post(Runnable { + instance.showLockView() + }) + +// Log.d("-------", "continue4") + } else { + + } + } else { + + + val mainHandler = Handler(Looper.getMainLooper()) + mainHandler.post(Runnable { + instance.unLock() + }) +// Log.d("-------", "continue5") + } + lastLockPackName = packageName + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/tools/AppListManager.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/AppListManager.kt new file mode 100644 index 0000000..3567077 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/AppListManager.kt @@ -0,0 +1,113 @@ +package com.kitobochi.softapp.timberlock.tools + +import android.content.Context +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import com.kitobochi.softapp.timberlock.db.AppDatabase +import com.kitobochi.softapp.timberlock.db.AppEntity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.util.Objects + +class AppListManager { + private fun addDb(list: List, isSystem: Boolean, isUpdate: Boolean) { + for (i in 0 until list.size) { + + val appEntity = list[i] + appEntity.isSyStem = isSystem + if (isUpdate) { + val appEntity1 = AppDatabase.database.getAppDao().findByPackName(appEntity.packageName) + if (appEntity1 == null) { + AppDatabase.database.getAppDao().insertData(appEntity) + } + } else { + appEntity.isRecommend = false + AppDatabase.database.getAppDao().insertData(appEntity) + } + + } + } + + private fun checkSystemApp(context: Context, packageName: String): Boolean { + try { + val info = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES) + if (info.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) { + return true + } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + return false + } + + + private fun removeDuplApp(list: List): List { + val hashMap: HashMap = hashMapOf() + for (appEntity: AppEntity in list) { + if (!hashMap.containsKey(appEntity.packageName)) { + hashMap.put(appEntity.packageName, appEntity) + } + } + val appEntityList: MutableList = mutableListOf() + for (entry in hashMap.entries) { + appEntityList.add(entry.value) + } + return appEntityList + } + + public fun getAppList(context: Context, isUpdate: Boolean): List { + val packageManager = context.packageManager + val intent = Intent(Intent.ACTION_MAIN, null) + intent.addCategory(Intent.CATEGORY_LAUNCHER) + val resolveInfos = packageManager.queryIntentActivities(intent, 0) + val systemAppList: MutableList = mutableListOf() + val threeAppList: MutableList = mutableListOf() + for (i in 0 until resolveInfos.size) { + val resolveInfo = resolveInfos[i] + val packageName = resolveInfo.activityInfo.packageName + if (Objects.equals(packageName, context.packageName)) { + continue + } + val appInfo: ApplicationInfo + try { + val applicationInfo = + packageManager.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES) + val appName = packageManager.getApplicationLabel(applicationInfo).toString() + val appEntity = AppEntity() + appEntity.packageName = packageName + appEntity.appName = appName + val isSystemApp = checkSystemApp(context, packageName) + if (isSystemApp) { + appEntity.isSyStem = true + systemAppList.add(appEntity) + } else { + appEntity.isSyStem = false + threeAppList.add(appEntity) + } + } catch (nameNotFoundException: PackageManager.NameNotFoundException) { + + } + } + + val uniqueSystemList: List = removeDuplApp(systemAppList) + val uniqueThreeList: List = removeDuplApp(threeAppList) + + CoroutineScope(Dispatchers.IO).launch { + addDb(uniqueSystemList, true, isUpdate) + addDb(uniqueThreeList, false, isUpdate) + } + return uniqueThreeList + } + + public fun delUnInstallApp(context: Context, packName: String): Boolean { + val packageManager = context.packageManager + return try { + packageManager.getApplicationInfo(packName, PackageManager.GET_UNINSTALLED_PACKAGES) + false + } catch (nameNotFoundException: PackageManager.NameNotFoundException) { + true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/tools/CustomViewTools.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/CustomViewTools.kt new file mode 100644 index 0000000..8135274 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/CustomViewTools.kt @@ -0,0 +1,16 @@ +package com.kitobochi.softapp.timberlock.tools + +import android.content.Context +import androidx.annotation.ColorRes +import androidx.annotation.DimenRes +import androidx.core.content.ContextCompat + +class CustomViewTools { + fun getPx(context: Context, @DimenRes id: Int): Float { + return context.resources.getDimension(id) + } + + fun getColor(context: Context?, @ColorRes id: Int): Int { + return ContextCompat.getColor(context!!, id) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockManager.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockManager.kt new file mode 100644 index 0000000..6e3fa62 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockManager.kt @@ -0,0 +1,94 @@ +package com.kitobochi.softapp.timberlock.tools + +import android.content.Context +import android.graphics.PixelFormat +import android.graphics.Point +import android.os.Build +import android.util.DisplayMetrics +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.ui.customview.InputStateView +import com.kitobochi.softapp.timberlock.ui.customview.KeyboardView +import com.kitobochi.softapp.timberlock.ui.customview.ListenerLock +import java.util.Objects + +class LockManager(context: Context) { + + private lateinit var mContext: Context + private lateinit var mView: View + private lateinit var lockView: KeyboardView + private lateinit var windowManager: WindowManager + private lateinit var layoutParams: WindowManager.LayoutParams + lateinit var lockManager: LockManager + + init { + mContext = context + mView = LayoutInflater.from(context).inflate(R.layout.view_lock, null, false) + + windowManager = mContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager + + initView() + + val myState = mView.findViewById(R.id.indicator_dots) + + lockView = mView.findViewById(R.id.pin_lock_view) + lockView.attachIndicatorDots(myState) + lockView.setPinLockListener(object : ListenerLock { + override fun onInPutComplete(pin: String) { + + val pwd = App().getPwd() + if (Objects.equals(pin, pin)) { + unLock() + } else { + lockView.resetPinLockView() + } + + } + }) + + } + + fun unLock() { + try { + windowManager.removeView(mView) + } catch (exception: Exception) { + } + } + + fun showLockView() { + lockView.resetPinLockView() + windowManager.addView(mView, layoutParams) + } + + private fun initView() { + var type = 0 + type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + } else { + WindowManager.LayoutParams.TYPE_PHONE + } + val displayMetrics = DisplayMetrics() + windowManager.getDefaultDisplay().getMetrics(displayMetrics) + layoutParams = WindowManager.LayoutParams() + layoutParams.type = type + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT + layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT + + layoutParams.format = PixelFormat.RGBA_8888 + layoutParams.flags = + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_FULLSCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + + layoutParams.gravity = Gravity.START or Gravity.TOP + + val screenSize = Point() + windowManager.getDefaultDisplay().getRealSize(screenSize) + layoutParams.width = screenSize.x + layoutParams.height = screenSize.y + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockServiceManager.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockServiceManager.kt new file mode 100644 index 0000000..311a0b1 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/tools/LockServiceManager.kt @@ -0,0 +1,70 @@ +package com.kitobochi.softapp.timberlock.tools + +import android.app.Activity +import android.app.AppOpsManager +import android.app.usage.UsageEvents +import android.app.usage.UsageStatsManager +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Process +import android.provider.Settings +import android.text.TextUtils +import androidx.annotation.RequiresApi + +class LockServiceManager { + fun checkUsageStats(context: Context): String { + val sUsageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager + val endTime = System.currentTimeMillis() + val beginTime = endTime - 10000 + var result = "" + val event = UsageEvents.Event() + val usageEvents = sUsageStatsManager.queryEvents(beginTime, endTime) + while (usageEvents.hasNextEvent()) { + usageEvents.getNextEvent(event) + if (event.eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) { + result = event.packageName + } + } + return if (!TextUtils.isEmpty(result)) { + result + } else { + "" + } + } + + fun checkPermission(context: Context): Boolean { + val appOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager + var mode = 0 + mode = appOps.checkOpNoThrow("android:get_usage_stats", Process.myUid(), context.packageName) + return mode == AppOpsManager.MODE_ALLOWED + } + + + @RequiresApi(Build.VERSION_CODES.M) + fun getCanDrawOverlays(context: Context?): Boolean { + return Settings.canDrawOverlays(context) + } + + fun toSetUsagePermission(context: Activity, requestCode: Int) { + val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS) + // Uri uri = Uri.fromParts("package", context.getPackageName(), null); +// intent.setData(uri); + context.startActivityForResult(intent, requestCode) + } + + fun goDrawOverlays(activity: Activity, requestCode: Int) { + val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + //8.0 + } else { + // 6.0、7.0、9.0 + val uri = Uri.fromParts("package", activity.packageName, null) + intent.setData(uri) + // intent.setData(Uri.parse("package:" + activity.getPackageName())); + } + activity.startActivityForResult(intent, requestCode) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/BaseActivity.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/BaseActivity.kt new file mode 100644 index 0000000..1a385cf --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/BaseActivity.kt @@ -0,0 +1,35 @@ +package com.kitobochi.softapp.timberlock.ui.activity + +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity + +abstract class BaseActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(getActivityView()) + initView() + } + + open fun initView() { + initStatusBar() + } + + abstract fun getActivityView(): View + + private fun initStatusBar() { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// window.decorView.systemUiVisibility = +// (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR +// window.statusBarColor = Color.TRANSPARENT +// } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.decorView.systemUiVisibility = + (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) + window.statusBarColor = Color.TRANSPARENT + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/MainActivity.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/MainActivity.kt new file mode 100644 index 0000000..e5fc7cc --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/MainActivity.kt @@ -0,0 +1,195 @@ +package com.kitobochi.softapp.timberlock.ui.activity + +import android.content.Intent +import android.os.Build +import android.util.Log +import android.view.View +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentStatePagerAdapter +import androidx.viewpager.widget.ViewPager +import com.google.android.material.tabs.TabLayout +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.databinding.ActivityMainBinding +import com.kitobochi.softapp.timberlock.databinding.ViewTabBinding +import com.kitobochi.softapp.timberlock.service.AppLockService +import com.kitobochi.softapp.timberlock.tools.LockServiceManager +import com.kitobochi.softapp.timberlock.ui.customview.DialogPer +import com.kitobochi.softapp.timberlock.ui.customview.onPermssionListener +import com.kitobochi.softapp.timberlock.ui.fragment.AppListFragment +import com.kitobochi.softapp.timberlock.ui.fragment.SettingFragment + +class MainActivity : BaseActivity(), onPermssionListener { + + private lateinit var binding: ActivityMainBinding + private lateinit var dialogPer: DialogPer + private var fragmentList: ArrayList = arrayListOf() + + override fun getActivityView(): View { + binding = ActivityMainBinding.inflate(layoutInflater); + return binding.root + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun initView() { + super.initView() + initTabLayout() + initViewPager() + startPermission() + startService(Intent(this, AppLockService::class.java)) + } + + @RequiresApi(Build.VERSION_CODES.M) + private fun checkPermission(): Boolean { + val b: Boolean = LockServiceManager().checkPermission(this) + val canDrawOverlays: Boolean = LockServiceManager().getCanDrawOverlays(this) + return b && canDrawOverlays + } + + @RequiresApi(Build.VERSION_CODES.M) + private fun startPermission() { + if (!checkPermission()) { + dialogPer = DialogPer.newInstance() + dialogPer.setListener(this) + dialogPer.show(supportFragmentManager, "") + } + } + + private fun initViewPager() { + + val titles = arrayOf( + getString(R.string.text_system), + getString(R.string.text_third), + getString(R.string.text_setting) + ) + + binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + + } + + override fun onPageSelected(position: Int) { + binding.mainTab.getTabAt(position)?.select() + } + + override fun onPageScrollStateChanged(state: Int) { + + } + + }) + + binding.mainViewPager.adapter = object : FragmentStatePagerAdapter(supportFragmentManager) { + override fun getCount(): Int { + return fragmentList.size + } + + override fun getItem(position: Int): Fragment { + return fragmentList[position] + } + + override fun getPageTitle(position: Int): CharSequence { + return titles[position] + } + + } + + } + + private fun initTabLayout() { + fragmentList.add(AppListFragment(true)) + fragmentList.add(AppListFragment(false)) + fragmentList.add(SettingFragment()) + + val titles = arrayOf( + getString(R.string.text_system), + getString(R.string.text_third), + getString(R.string.text_setting) + ) + + for (i in 0 until fragmentList.size) { + val newTab = binding.mainTab.newTab() + val viewTabBinding = ViewTabBinding.inflate(layoutInflater) + viewTabBinding.tvTabtext.text = titles[i] + newTab.customView = viewTabBinding.root + binding.mainTab.addTab(newTab) + } + + val tabAt = binding.mainTab.getTabAt(1) + val tabAt2 = binding.mainTab.getTabAt(2) + if (tabAt != null && tabAt2 != null) { + updateTab(tabAt, false) + updateTab(tabAt2, false) + } + + binding.mainTab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(p0: TabLayout.Tab?) { + if (p0 != null) { + updateTab(p0, true) + binding.mainViewPager.setCurrentItem(p0.position) + } + } + + override fun onTabUnselected(p0: TabLayout.Tab?) { + p0?.let { updateTab(it, false) } + } + + override fun onTabReselected(p0: TabLayout.Tab?) { + + } + }) + } + + private fun updateTab(tabAt: TabLayout.Tab, b: Boolean) { + val customView = tabAt.customView ?: return + val textView = customView.findViewById(R.id.tv_tabtext) + textView.isSelected = b + if (b) { + textView.background = ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_yellow_r30) + } else { + textView.background = null + } + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun onToSetting() { + val b: Boolean = LockServiceManager().checkPermission(this) + val canDrawOverlays: Boolean = LockServiceManager().getCanDrawOverlays(this) + if (!b) { + LockServiceManager().toSetUsagePermission(this@MainActivity, App().reqCodeUsage) + } else { + if (!canDrawOverlays) { + LockServiceManager().goDrawOverlays(this, App().reqCodeOverlays) + } + } + } + + @Deprecated("Deprecated in Java") + @RequiresApi(Build.VERSION_CODES.M) + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == App().reqCodeUsage) { + if (checkPermission()) { + dialogPer.dismiss() + return + } + val canDrawOverlays = LockServiceManager().getCanDrawOverlays(this) + if (!canDrawOverlays) { + LockServiceManager().goDrawOverlays(this, App().reqCodeOverlays) + } + } + + if (requestCode == App().reqCodeOverlays) { + if (checkPermission()) { + + Log.d("---------","-------dismiss---") + dialogPer.dismiss() + } else { + Toast.makeText(this, getString(R.string.no_permission), Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/SetPwdActivity.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/SetPwdActivity.kt new file mode 100644 index 0000000..c1d4206 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/SetPwdActivity.kt @@ -0,0 +1,157 @@ +package com.kitobochi.softapp.timberlock.ui.activity + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.View +import android.widget.EditText +import android.widget.Toast +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.applovin.mediation.MaxAd +import com.applovin.mediation.ads.MaxInterstitialAd +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.ad.AdListener +import com.kitobochi.softapp.timberlock.ad.AdManager +import com.kitobochi.softapp.timberlock.databinding.ActivitySetpwdBinding + +class SetPwdActivity : BaseActivity(), View.OnClickListener { + + private lateinit var binding: ActivitySetpwdBinding + private var isShowAd: Boolean = false + private val IS_SHOW_AD = "IS_SHOW_AD" + + private val countTime: Long = 12000 + private lateinit var adList: List + private lateinit var timer: CountDownTimer + + override fun getActivityView(): View { + binding = ActivitySetpwdBinding.inflate(layoutInflater) + return binding.root + } + + override fun initView() { + super.initView() + initAd() + initButton() + initInput() + } + + private fun initAd() { + isShowAd = intent.getBooleanExtra(IS_SHOW_AD, false) + + timer = object : CountDownTimer(countTime, 200) { + override fun onTick(millisUntilFinished: Long) { + if (isShowAd) { + startShowAd() + } + } + override fun onFinish() { + if (isShowAd) { + startShowAd() + } + } + } + startAd() + } + + private fun startAd() { + if (!App.initOK) { + LocalBroadcastManager.getInstance(this).registerReceiver(object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + loadMyAdAndStart() + Log.d("------------", "------------1sucess") + } + }, IntentFilter(App.AD_INIT)) + } else { + loadMyAdAndStart() + Log.d("------------", "------------2sucess") + } + } + + private fun loadMyAdAndStart() { + adList = AdManager.adLoad() + timer.start() + } + + private fun startShowAd() { + val checkCacheAd = AdManager.onCache(adList) + if (checkCacheAd == null) { + return + } else { + AdManager.setAdListener(checkCacheAd, object : AdListener { + override fun onFail(ad: MaxAd) { + + } + + override fun onSuccess() { + + } + + override fun onHidden() { + checkCacheAd.loadAd() + } + + }) + checkCacheAd.showAd() + } + } + + private fun initInput() { + for (i in 0 until binding.layoutPwd.childCount) { + val editText = binding.layoutPwd.getChildAt(i) as EditText + var editNext: EditText? = null + if ((i + 1) < binding.layoutPwd.childCount) { + editNext = binding.layoutPwd.getChildAt(i + 1) as EditText + } + val finalEditText = editNext + editText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + + } + + override fun afterTextChanged(s: Editable?) { + finalEditText?.requestFocus() + } + }) + } + } + + private fun initButton() { + binding.pwdBack.setOnClickListener(this) + binding.pwdOk.setOnClickListener(this) + } + + override fun onClick(v: View?) { + when (v) { + binding.pwdOk -> { + val stringBuilder = StringBuilder() + stringBuilder.append(binding.et1.text.toString()) + stringBuilder.append(binding.et2.text.toString()) + stringBuilder.append(binding.et3.text.toString()) + stringBuilder.append(binding.et4.text.toString()) + if (stringBuilder.length == 4) { + App().updatePwd(stringBuilder.toString()) + Toast.makeText(this@SetPwdActivity, getString(R.string.pwd_success), Toast.LENGTH_SHORT).show() + val intent = Intent(this@SetPwdActivity, MainActivity::class.java) + startActivity(intent) + } else { + Toast.makeText(this@SetPwdActivity, getString(R.string.pwd_err), Toast.LENGTH_SHORT).show() + } + } + + binding.pwdBack -> { + finish() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/StartPageActivity.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/StartPageActivity.kt new file mode 100644 index 0000000..7776907 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/activity/StartPageActivity.kt @@ -0,0 +1,127 @@ +package com.kitobochi.softapp.timberlock.ui.activity + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.CountDownTimer +import android.util.Log +import android.view.View +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.applovin.mediation.MaxAd +import com.applovin.mediation.ads.MaxInterstitialAd +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.ad.AdListener +import com.kitobochi.softapp.timberlock.ad.AdManager +import com.kitobochi.softapp.timberlock.databinding.ActivityStartBinding +import com.vungle.ads.Ad +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class StartPageActivity : BaseActivity() { + + private lateinit var binding: ActivityStartBinding + + // private val coroutineScope = CoroutineScope(Dispatchers.Main) + private val countTime: Long = 12000 + + private val IS_SHOW_AD = "IS_SHOW_AD" + + + private lateinit var adList: List + private lateinit var timer: CountDownTimer + private var needShow = true + + override fun getActivityView(): View { + binding = ActivityStartBinding.inflate(layoutInflater) + return binding.root + } + + override fun initView() { + super.initView() + Log.d("start-ad", "onCreate") + + timer = object : CountDownTimer(countTime, 200) { + override fun onTick(millisUntilFinished: Long) { + if (needShow) { + startShowAd {} + } + } + + override fun onFinish() { + if (needShow) { + startShowAd { + startMainActivity() + } + } + } + } + startAd() +// startMainActivity() + } + + private fun startAd() { + if (!App.initOK) { + LocalBroadcastManager.getInstance(this).registerReceiver(object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + loadMyAdAndStart() + Log.d("------------", "------------1sucess") + } + }, IntentFilter(App.AD_INIT)) + } else { + loadMyAdAndStart() + Log.d("------------", "------------2sucess") + } + } + + private fun loadMyAdAndStart() { + adList = AdManager.adLoad() + timer.start() + } + + private fun startShowAd(action: () -> Unit) { + val checkCacheAd = AdManager.onCache(adList) + if (checkCacheAd == null) { + action.invoke() + } else { + needShow = false + AdManager.setAdListener(checkCacheAd, object : AdListener { + override fun onFail(ad: MaxAd) { + startMainActivity() + } + + override fun onSuccess() { + + } + + override fun onHidden() { + startMainActivity() + checkCacheAd.loadAd() + } + + }) + checkCacheAd.showAd() + } + } + + private fun startMainActivity() { + + if (App().getPwd().isEmpty()) { + val intent = Intent(this, SetPwdActivity::class.java) + intent.putExtra(IS_SHOW_AD, false) + startActivity(intent) + } else { + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + } + + finish() + } + + override fun onDestroy() { + super.onDestroy() + timer.cancel() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/AppListAdapter.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/AppListAdapter.kt new file mode 100644 index 0000000..f55f9cb --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/AppListAdapter.kt @@ -0,0 +1,131 @@ +package com.kitobochi.softapp.timberlock.ui.adapter + +import android.content.Context +import android.content.pm.PackageManager +import android.graphics.drawable.Drawable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.CompoundButton +import android.widget.ImageView +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.widget.SwitchCompat +import androidx.recyclerview.widget.RecyclerView +import com.applovin.mediation.MaxAd +import com.applovin.mediation.ads.MaxInterstitialAd +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.ad.AdListener +import com.kitobochi.softapp.timberlock.ad.AdManager +import com.kitobochi.softapp.timberlock.ad.AdMsgListener +import com.kitobochi.softapp.timberlock.db.AppDatabase +import com.kitobochi.softapp.timberlock.db.AppEntity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class AppListAdapter( + context: Context, + private val msgListener: AdMsgListener +) : RecyclerView.Adapter() { + + private val mContext: Context = context + + private val packageManager = context.packageManager + + private var list: List = mutableListOf() + + public fun updateSystemApp(infoList: List) { + list = infoList + notifyDataSetChanged() + } + + inner class AppListVH(view: View) : RecyclerView.ViewHolder(view) { + val imageView = itemView.findViewById(R.id.item_logo) + val textView = itemView.findViewById(R.id.item_name) + val switchCompat = itemView.findViewById(R.id.app_switch) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppListVH { + return AppListVH(LayoutInflater.from(parent.context).inflate(R.layout.item_app, parent, false)) + } + + override fun getItemCount(): Int { + return list.size + } + + private fun getAppLog(packageName: String): Drawable { + val applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES) + return packageManager.getApplicationIcon(applicationInfo) + } + + override fun onBindViewHolder(holder: AppListVH, position: Int) { + holder.switchCompat.setOnCheckedChangeListener(null) + val appEntity = list[position] + val appName = appEntity.appName + val lock = appEntity.isLock + holder.switchCompat.isChecked = lock + holder.switchCompat.setOnCheckedChangeListener( + CompoundButton.OnCheckedChangeListener + { _: CompoundButton, isChecked: Boolean -> + CoroutineScope(Dispatchers.IO).launch { + appEntity.isLock = isChecked + AppDatabase.database.getAppDao().updateData(dataApp = appEntity) + } + var format: String + if (isChecked) { + format = String.format(mContext.getString(R.string.text_locked), appName) + } else { + format = String.format(mContext.getString(R.string.text_unlocked), appName) + } + Toast.makeText(mContext, format, Toast.LENGTH_SHORT).show() + + + if (App.count % 5 == 0) { + showAd({ showPopup(format) }, format) + } + App.count++ + + }) + + try { + val appLog = getAppLog(appEntity.packageName) + holder.imageView.setImageDrawable(appLog) + } catch (e: PackageManager.NameNotFoundException) { + + } + holder.textView.text = appName + } + + private fun showAd(action: () -> Unit, msg: String) { + val adList = AdManager.adLoad() + val checkCacheAd = AdManager.onCache(adList) + if (checkCacheAd == null) { + action.invoke() + } else { + AdManager.setAdListener(checkCacheAd, object : AdListener { + override fun onFail(ad: MaxAd) { + showPopup(msg) + } + + override fun onSuccess() { + + } + + override fun onHidden() { + showPopup(msg) + checkCacheAd.loadAd() + } + + }) + checkCacheAd.showAd() + } + + } + + private fun showPopup(msg: String) { + msgListener.msg(msg) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/KeyboardAdapter.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/KeyboardAdapter.kt new file mode 100644 index 0000000..b92e176 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/adapter/KeyboardAdapter.kt @@ -0,0 +1,154 @@ +package com.kitobochi.softapp.timberlock.ui.adapter + +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.ui.customview.CustomBundle + + +class KeyboardAdapter : RecyclerView.Adapter() { + private var mOnNumberListener: OnNumberClickListener? = null + private var mOnDeleteListener: OnDeleteClickListener? = null + private var mCustomBundle: CustomBundle? = null + private var mCurLength = 0 + private val mKeyValues: IntArray + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val viewHolder: RecyclerView.ViewHolder + val inflater = LayoutInflater.from(parent.context) + if (viewType == TYPE_NUMBER) { + val view: View = inflater.inflate(R.layout.item_number, parent, false) + viewHolder = NumberViewHolder(view) + } else { + val view: View = inflater.inflate(R.layout.item_delete, parent, false) + viewHolder = DeleteViewHolder(view) + } + return viewHolder + } + + init { + mKeyValues = getKeyValues(intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder.itemViewType == TYPE_NUMBER) { + val vh1 = holder as NumberViewHolder + setNumberBtn(vh1, position) + } + } + + private fun setNumberBtn(holder: NumberViewHolder?, position: Int) { + if (holder != null) { + if (position == 9) { + holder.mNumberButton.visibility = View.GONE + } else { + holder.mNumberButton.text = mKeyValues[position].toString() + holder.mNumberButton.visibility = View.VISIBLE + holder.mNumberButton.tag = mKeyValues[position] + } + if (mCustomBundle != null) { + holder.mNumberButton.setTextColor(mCustomBundle!!.textColor) + if (mCustomBundle!!.backgroundDrawable != null) { + holder.mNumberButton.background = mCustomBundle!!.backgroundDrawable + } + holder.mNumberButton.setTextSize( + TypedValue.COMPLEX_UNIT_PX, + mCustomBundle!!.textSize.toFloat() + ) + val params: LinearLayout.LayoutParams = LinearLayout.LayoutParams( + mCustomBundle!!.buttonSize, + mCustomBundle!!.buttonSize + ) + holder.mNumberButton.setLayoutParams(params) + } + } + } + + override fun getItemCount(): Int { + return 12 + } + + override fun getItemViewType(position: Int): Int { + return if (position == itemCount - 1) { + VIEW_TYPE_DELETE + } else TYPE_NUMBER + } + + fun setPinLength(pinLength: Int) { + mCurLength = pinLength + } + + private fun getKeyValues(keyValues: IntArray): IntArray { + val adjustedKeyValues = IntArray(keyValues.size + 1) + for (i in keyValues.indices) { + if (i < 9) { + adjustedKeyValues[i] = keyValues[i] + } else { + adjustedKeyValues[i] = -1 + adjustedKeyValues[i + 1] = keyValues[i] + } + } + return adjustedKeyValues + } + + fun setOnItemClickListener(onNumberClickListener: OnNumberClickListener?) { + mOnNumberListener = onNumberClickListener + } + + fun setOnDeleteClickListener(onDeleteClickListener: OnDeleteClickListener?) { + mOnDeleteListener = onDeleteClickListener + } + + fun setCustomizationOptions(customBundle: CustomBundle?) { + mCustomBundle = customBundle + } + + inner class NumberViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + var mNumberButton: Button + + init { + mNumberButton = itemView.findViewById(R.id.deleteLayout) as Button + mNumberButton.setOnClickListener { v -> + if (mOnNumberListener != null) { + mOnNumberListener!!.onNumberClicked(v.tag as Int) + } + } + } + } + + interface OnNumberClickListener { + fun onNumberClicked(keyValue: Int) + } + + interface OnDeleteClickListener { + fun onDeleteClicked() + } + + inner class DeleteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + private var mDeleteLayout: LinearLayout + private var mDeleteImage: ImageView + + init { + mDeleteLayout = itemView.findViewById(R.id.deleteLayout) as LinearLayout + mDeleteImage = itemView.findViewById(R.id.deleteImage) as ImageView + if (mCustomBundle?.isShowDeleteButton!! && mCurLength > 0) { + mDeleteLayout.setOnClickListener { + if (mOnDeleteListener != null) { + mOnDeleteListener!!.onDeleteClicked() + } + } + } + } + } + + companion object { + private const val TYPE_NUMBER = 0 + private const val VIEW_TYPE_DELETE = 1 + } +} + diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/CustomBundle.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/CustomBundle.kt new file mode 100644 index 0000000..df23972 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/CustomBundle.kt @@ -0,0 +1,18 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +import android.graphics.drawable.Drawable + +class CustomBundle { + @JvmField + var textColor = 0 + + @JvmField + var textSize = 0 + var isShowDeleteButton: Boolean = false + + @JvmField + var buttonSize = 0 + + @JvmField + var backgroundDrawable: Drawable? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/DialogPer.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/DialogPer.kt new file mode 100644 index 0000000..845c8cd --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/DialogPer.kt @@ -0,0 +1,44 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.fragment.app.DialogFragment +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.databinding.ViewDialogBinding + +class DialogPer : DialogFragment() { + private lateinit var binding: ViewDialogBinding + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = ViewDialogBinding.inflate(getLayoutInflater()) + dialog!!.setCanceledOnTouchOutside(false) + dialog!!.setCancelable(false) + val window = dialog!!.window + window!!.setBackgroundDrawableResource(R.color.null_color) + window.decorView.setPadding(0, 0, 0, 0) + val wlp = window.attributes + wlp.gravity = Gravity.CENTER + wlp.width = WindowManager.LayoutParams.MATCH_PARENT + wlp.height = WindowManager.LayoutParams.WRAP_CONTENT + window.setAttributes(wlp) + binding.tvGo.setOnClickListener(View.OnClickListener { listener?.onToSetting() }) + return binding.getRoot() + } + + private var listener: onPermssionListener? = null + + public fun setListener(listener: onPermssionListener?) { + this.listener = listener + } + + companion object{ + fun newInstance(): DialogPer { + return DialogPer() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/InputStateView.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/InputStateView.kt new file mode 100644 index 0000000..ed360d4 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/InputStateView.kt @@ -0,0 +1,90 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import androidx.core.view.ViewCompat +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.tools.CustomViewTools + +class InputStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + LinearLayout(context, attrs, defStyleAttr) { + private var mPinLength = 0 + private var mPreviousLength = 0 + private var mDotDiameter = 0 + private var mDotSpacing = 0 + private var mFillDrawable = 0 + private var mEmptyDrawable = 0 + private fun initView(context: Context) { + ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR) + for (i in 0 until mPinLength) { + val dot = View(context) + emptyDot(dot) + val params = LayoutParams( + mDotDiameter, + mDotDiameter + ) + params.setMargins(mDotSpacing, 0, mDotSpacing, 0) + dot.setLayoutParams(params) + addView(dot) + } + } + + init { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyLock) + try { + mDotDiameter = typedArray.getDimension( + R.styleable.MyLock_dotDiameter, + CustomViewTools().getPx(getContext(), R.dimen.default_dot_diameter) + ).toInt() + mDotSpacing = typedArray.getDimension( + R.styleable.MyLock_dotSpacing, + CustomViewTools().getPx(getContext(), R.dimen.default_dot_spacing) + ).toInt() + mFillDrawable = typedArray.getResourceId( + R.styleable.MyLock_dotFilledBackground, + R.drawable.shape_oval_white + ) + mEmptyDrawable = typedArray.getResourceId( + R.styleable.MyLock_dotEmptyBackground, + R.drawable.shape_oval_gray + ) + mPinLength = typedArray.getInt(R.styleable.MyLock_pinLength, DEFAULT_PIN_LENGTH) + } finally { + typedArray.recycle() + } + initView(context) + } + + private fun emptyDot(dot: View) { + dot.setBackgroundResource(mEmptyDrawable) + dot.animate().scaleX(1.0f).scaleY(1.0f).setDuration(100).start() + } + + private fun fillDot(dot: View) { + dot.setBackgroundResource(mFillDrawable) + dot.animate().scaleX(1.2f).scaleY(1.2f).setDuration(100).start() + } + + fun updateDot(length: Int) { + mPreviousLength = if (length > 0) { + if (length > mPreviousLength) { + fillDot(getChildAt(length - 1)) + } else { + emptyDot(getChildAt(length)) + } + length + } else { + for (i in 0 until childCount) { + val v = getChildAt(i) + emptyDot(v) + } + 0 + } + } + + companion object { + private const val DEFAULT_PIN_LENGTH = 4 + } +} diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/KeyboardView.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/KeyboardView.kt new file mode 100644 index 0000000..9082b77 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/KeyboardView.kt @@ -0,0 +1,178 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +import android.content.Context +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.tools.CustomViewTools +import com.kitobochi.softapp.timberlock.ui.adapter.KeyboardAdapter + +class KeyboardView : RecyclerView { + private var mPin = "" + var pinLength = 0 + private set + private var mHorizontalSpacing = 0 + private var mVerticalSpacing = 0 + private var mTextColor = 0 + private var mTextSize = 0 + private var mButtonSize = 0 + private var mButtonBgDraw: Drawable? = null + private var mAdapter: KeyboardAdapter? = null + private var mPinLockListener: ListenerLock? = null + private var mCustomBundle: CustomBundle? = null + var isShowDeleteButton = false + private set + private var mMyDots: InputStateView? = null + private val numberClickListener: KeyboardAdapter.OnNumberClickListener = + object : KeyboardAdapter.OnNumberClickListener { + override fun onNumberClicked(keyValue: Int) { + if (mPin.length < pinLength) { + mPin += keyValue.toString() + if (isIndicatorDotsAttached) { + mMyDots?.updateDot(mPin.length) + } + if (mPin.length == 1) { + mAdapter?.setPinLength(mPin.length) + mAdapter?.notifyItemChanged(mAdapter!!.itemCount - 1) + } + if (mPinLockListener != null) { + if (mPin.length == pinLength) { + mPinLockListener!!.onInPutComplete(mPin) + } else { + } + } + } else { + if (!isShowDeleteButton) { + resetPinLockView() + mPin += keyValue.toString() + if (isIndicatorDotsAttached) { + mMyDots?.updateDot(mPin.length) + } + if (mPinLockListener != null) { +// mPinLockListener.onPinChange(mPin.length(), mPin); + } + } else { + mPinLockListener?.onInPutComplete(mPin) + } + } + } + } + private val mOnDeleteClickListener: KeyboardAdapter.OnDeleteClickListener = + object : KeyboardAdapter.OnDeleteClickListener { + override fun onDeleteClicked() { + if (mPin.length > 0) { + mPin = mPin.substring(0, mPin.length - 1) + if (isIndicatorDotsAttached) { + mMyDots?.updateDot(mPin.length) + } + if (mPin.length == 0) { + mAdapter?.setPinLength(mPin.length) + mAdapter?.notifyItemChanged(mAdapter!!.itemCount - 1) + } + if (mPinLockListener != null) { + if (mPin.length == 0) { +// mPinLockListener.onEmpty(); + clearInternalPin() + } else { +// mPinLockListener.onPinChange(mPin.length(), mPin); + } + } + } else { + if (mPinLockListener != null) { + } + } + } + } + + constructor(context: Context?) : super(context!!) { + init(null, 0) + } + + constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) { + init(attrs, 0) + } + + constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context!!, attrs, defStyle) { + init(attrs, defStyle) + } + + private fun init(attributeSet: AttributeSet?, defStyle: Int) { + val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.MyLock) + try { + pinLength = typedArray.getInt(R.styleable.MyLock_pinLength, DEFAULT_PWD_LENGTH) + mHorizontalSpacing = typedArray.getDimension( + R.styleable.MyLock_keypadHorizontalSpacing, CustomViewTools().getPx( + context, R.dimen.default_horizontal_spacing + ) + ).toInt() + mVerticalSpacing = typedArray.getDimension( + R.styleable.MyLock_keypadVerticalSpacing, + CustomViewTools().getPx(context, R.dimen.default_vertical_spacing) + ).toInt() + mTextColor = + typedArray.getColor( + R.styleable.MyLock_keypadTextColor, + CustomViewTools().getColor(context, R.color.white) + ) + mTextSize = typedArray.getDimension( + R.styleable.MyLock_keypadTextSize, + CustomViewTools().getPx(context, R.dimen.default_text_size) + ).toInt() + mButtonSize = typedArray.getDimension( + R.styleable.MyLock_keypadButtonSize, + CustomViewTools().getPx(context, R.dimen.default_button_size) + ).toInt() + mButtonBgDraw = typedArray.getDrawable(R.styleable.MyLock_keypadButtonBackgroundDrawable) + isShowDeleteButton = typedArray.getBoolean(R.styleable.MyLock_keypadShowDeleteButton, true) + } finally { + typedArray.recycle() + } + mCustomBundle = CustomBundle() + mCustomBundle!!.textColor = mTextColor + mCustomBundle!!.textSize = mTextSize + mCustomBundle!!.buttonSize = mButtonSize + mCustomBundle!!.backgroundDrawable = mButtonBgDraw + mCustomBundle!!.isShowDeleteButton = isShowDeleteButton + initView() + } + + private fun initView() { + mAdapter = KeyboardAdapter() + setLayoutManager(GridLayoutManager(context, 3)) + mAdapter!!.setOnItemClickListener(numberClickListener) + mAdapter!!.setOnDeleteClickListener(mOnDeleteClickListener) + mAdapter!!.setCustomizationOptions(mCustomBundle) + setAdapter(mAdapter) + addItemDecoration(LockSpace(mHorizontalSpacing, mVerticalSpacing, 3, false)) + setOverScrollMode(OVER_SCROLL_NEVER) + } + + fun setPinLockListener(pinLockListener: ListenerLock?) { + mPinLockListener = pinLockListener + } + + private fun clearInternalPin() { + mPin = "" + } + + fun resetPinLockView() { + clearInternalPin() + mAdapter?.setPinLength(mPin.length) + mAdapter?.notifyItemChanged(mAdapter!!.getItemCount() - 1) + mMyDots?.updateDot(mPin.length) + } + + val isIndicatorDotsAttached: Boolean + get() = mMyDots != null + + fun attachIndicatorDots(mMyDots: InputStateView?) { + this.mMyDots = mMyDots + } + + companion object { + private const val DEFAULT_PWD_LENGTH = 4 + } +} + diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/ListenerLock.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/ListenerLock.kt new file mode 100644 index 0000000..6c9f2cc --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/ListenerLock.kt @@ -0,0 +1,6 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +interface ListenerLock { + fun onInPutComplete(pin: String) + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/LockSpace.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/LockSpace.kt new file mode 100644 index 0000000..f4408f2 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/LockSpace.kt @@ -0,0 +1,35 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ItemDecoration + + +class LockSpace( + private val HSpace: Int, + private val mVSpace: Int, + private val mSpanCount: Int, + private val mInclude: Boolean +) : + ItemDecoration() { + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + val position = parent.getChildAdapterPosition(view) + val column = position % mSpanCount + if (mInclude) { + outRect.left = HSpace - column * HSpace / mSpanCount + outRect.right = (column + 1) * HSpace / mSpanCount + if (position < mSpanCount) { + outRect.top = mVSpace + } + outRect.bottom = mVSpace + } else { + outRect.left = column * HSpace / mSpanCount + outRect.right = HSpace - (column + 1) * HSpace / mSpanCount + if (position >= mSpanCount) { + outRect.top = mVSpace + } + } + } +} + diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/onPermssionListener.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/onPermssionListener.kt new file mode 100644 index 0000000..cc2f1f5 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/customview/onPermssionListener.kt @@ -0,0 +1,5 @@ +package com.kitobochi.softapp.timberlock.ui.customview + +interface onPermssionListener { + fun onToSetting() +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/AppListFragment.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/AppListFragment.kt new file mode 100644 index 0000000..60a3364 --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/AppListFragment.kt @@ -0,0 +1,58 @@ +package com.kitobochi.softapp.timberlock.ui.fragment + +import android.app.AlertDialog +import android.util.Log +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import com.kitobochi.softapp.timberlock.ad.AdListener +import com.kitobochi.softapp.timberlock.ad.AdMsgListener +import com.kitobochi.softapp.timberlock.databinding.FragmentApplistBinding +import com.kitobochi.softapp.timberlock.db.AppDatabase +import com.kitobochi.softapp.timberlock.ui.adapter.AppListAdapter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class AppListFragment( + private val isSystem: Boolean +) : BaseFragment() { + + private lateinit var binding: FragmentApplistBinding + override fun getFragmentView(): View { + binding = FragmentApplistBinding.inflate(layoutInflater) + return binding.root + } + + override fun initView() { + super.initView() + initAppList() + } + + private fun initAppList() { + val adapter = AppListAdapter(requireContext(), object : AdMsgListener { + override fun msg(msg: String) { +// Log.e("------", "回调成功") + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle("Successfully set") + builder.setMessage(msg) + builder.setPositiveButton("OK") { dialog, _ -> + dialog.dismiss() + } + val alertDialog = builder.create() + alertDialog.show() + } + }) + binding.appList.adapter = adapter + binding.appList.layoutManager = LinearLayoutManager(requireContext()) + + CoroutineScope(Dispatchers.IO).launch { + val data = AppDatabase.database.getAppDao().findByType(isSystem, false) + withContext(Dispatchers.Main) { + if (data != null) { + adapter.updateSystemApp(data) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/BaseFragment.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/BaseFragment.kt new file mode 100644 index 0000000..532598d --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/BaseFragment.kt @@ -0,0 +1,27 @@ +package com.kitobochi.softapp.timberlock.ui.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment + +abstract class BaseFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View? { + return getFragmentView() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initView() + } + + open fun initView() { + } + + abstract fun getFragmentView(): View + +} \ No newline at end of file diff --git a/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/SettingFragment.kt b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/SettingFragment.kt new file mode 100644 index 0000000..ff71a1e --- /dev/null +++ b/app/src/main/java/com/kitobochi/softapp/timberlock/ui/fragment/SettingFragment.kt @@ -0,0 +1,61 @@ +package com.kitobochi.softapp.timberlock.ui.fragment + +import android.content.Intent +import android.net.Uri +import android.view.View +import com.kitobochi.softapp.timberlock.App +import com.kitobochi.softapp.timberlock.R +import com.kitobochi.softapp.timberlock.databinding.FragmentSettingBinding +import com.kitobochi.softapp.timberlock.tools.LockServiceManager +import com.kitobochi.softapp.timberlock.ui.activity.SetPwdActivity + +class SettingFragment : BaseFragment(), View.OnClickListener { + + private val IS_SHOW_AD = "IS_SHOW_AD" + private lateinit var binding: FragmentSettingBinding + override fun getFragmentView(): View { + binding = FragmentSettingBinding.inflate(layoutInflater) + return binding.root + } + + override fun initView() { + super.initView() + initButton() + } + + private fun initButton() { + binding.settingRating.setOnClickListener(this) + binding.settingShare.setOnClickListener(this) + binding.settingPassword.setOnClickListener(this) +// binding.settingInit.setOnClickListener(this) + } + + override fun onClick(v: View?) { + when (v) { + binding.settingRating -> { + val url = getString(R.string.setting_link) + (activity?.packageName ?: "") + val intent = Intent(Intent.ACTION_VIEW) + intent.setData(Uri.parse(url)) + startActivity(intent) + } + + binding.settingShare -> { + val url = getString(R.string.setting_link) + (activity?.packageName ?: "") + val intent = Intent(Intent.ACTION_SEND) + intent.setType("text/plain") + intent.putExtra(Intent.EXTRA_TEXT, url) + startActivity(intent) + } + + binding.settingPassword -> { + val intent = Intent(requireContext(), SetPwdActivity::class.java) + intent.putExtra(IS_SHOW_AD, true) + startActivity(intent) + } + +// binding.settingInit -> { +//// LockServiceManager().toSetUsagePermission(requireActivity(), App().reqCodeUsage) +// } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/selector_switch.xml b/app/src/main/res/drawable/selector_switch.xml new file mode 100644 index 0000000..b2721de --- /dev/null +++ b/app/src/main/res/drawable/selector_switch.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_text_color.xml b/app/src/main/res/drawable/selector_text_color.xml new file mode 100644 index 0000000..d3686ab --- /dev/null +++ b/app/src/main/res/drawable/selector_text_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_oval_gray.xml b/app/src/main/res/drawable/shape_oval_gray.xml new file mode 100644 index 0000000..e14ca3b --- /dev/null +++ b/app/src/main/res/drawable/shape_oval_gray.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_oval_white.xml b/app/src/main/res/drawable/shape_oval_white.xml new file mode 100644 index 0000000..522eb16 --- /dev/null +++ b/app/src/main/res/drawable/shape_oval_white.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_pink_r30.xml b/app/src/main/res/drawable/shape_pink_r30.xml new file mode 100644 index 0000000..c13433e --- /dev/null +++ b/app/src/main/res/drawable/shape_pink_r30.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_pwd_bg.xml b/app/src/main/res/drawable/shape_pwd_bg.xml new file mode 100644 index 0000000..1c44823 --- /dev/null +++ b/app/src/main/res/drawable/shape_pwd_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_pwd_ok.xml b/app/src/main/res/drawable/shape_pwd_ok.xml new file mode 100644 index 0000000..e65a265 --- /dev/null +++ b/app/src/main/res/drawable/shape_pwd_ok.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_rect_r12.xml b/app/src/main/res/drawable/shape_rect_r12.xml new file mode 100644 index 0000000..4e00bda --- /dev/null +++ b/app/src/main/res/drawable/shape_rect_r12.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_white_switch.xml b/app/src/main/res/drawable/shape_white_switch.xml new file mode 100644 index 0000000..4d90158 --- /dev/null +++ b/app/src/main/res/drawable/shape_white_switch.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_yellow_r30.xml b/app/src/main/res/drawable/shape_yellow_r30.xml new file mode 100644 index 0000000..836849c --- /dev/null +++ b/app/src/main/res/drawable/shape_yellow_r30.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_yellow_switch.xml b/app/src/main/res/drawable/shape_yellow_switch.xml new file mode 100644 index 0000000..9a54a42 --- /dev/null +++ b/app/src/main/res/drawable/shape_yellow_switch.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/svg_back.xml b/app/src/main/res/drawable/svg_back.xml new file mode 100644 index 0000000..70aa52a --- /dev/null +++ b/app/src/main/res/drawable/svg_back.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/svg_delete.xml b/app/src/main/res/drawable/svg_delete.xml new file mode 100644 index 0000000..c98ae91 --- /dev/null +++ b/app/src/main/res/drawable/svg_delete.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/svg_rating.xml b/app/src/main/res/drawable/svg_rating.xml new file mode 100644 index 0000000..2364cee --- /dev/null +++ b/app/src/main/res/drawable/svg_rating.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/svg_reset_password.xml b/app/src/main/res/drawable/svg_reset_password.xml new file mode 100644 index 0000000..02b457f --- /dev/null +++ b/app/src/main/res/drawable/svg_reset_password.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/svg_set.xml b/app/src/main/res/drawable/svg_set.xml new file mode 100644 index 0000000..13a28e7 --- /dev/null +++ b/app/src/main/res/drawable/svg_set.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/svg_share.xml b/app/src/main/res/drawable/svg_share.xml new file mode 100644 index 0000000..09015cf --- /dev/null +++ b/app/src/main/res/drawable/svg_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/svg_switch.xml b/app/src/main/res/drawable/svg_switch.xml new file mode 100644 index 0000000..0ea74e2 --- /dev/null +++ b/app/src/main/res/drawable/svg_switch.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/thumb_sw.xml b/app/src/main/res/drawable/thumb_sw.xml new file mode 100644 index 0000000..198a7fc --- /dev/null +++ b/app/src/main/res/drawable/thumb_sw.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..bc34a18 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_setpwd.xml b/app/src/main/res/layout/activity_setpwd.xml new file mode 100644 index 0000000..00a4993 --- /dev/null +++ b/app/src/main/res/layout/activity_setpwd.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_start.xml b/app/src/main/res/layout/activity_start.xml new file mode 100644 index 0000000..0dd97d8 --- /dev/null +++ b/app/src/main/res/layout/activity_start.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_applist.xml b/app/src/main/res/layout/fragment_applist.xml new file mode 100644 index 0000000..25e0237 --- /dev/null +++ b/app/src/main/res/layout/fragment_applist.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_setting.xml b/app/src/main/res/layout/fragment_setting.xml new file mode 100644 index 0000000..93145ab --- /dev/null +++ b/app/src/main/res/layout/fragment_setting.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_app.xml b/app/src/main/res/layout/item_app.xml new file mode 100644 index 0000000..14e6a4b --- /dev/null +++ b/app/src/main/res/layout/item_app.xml @@ -0,0 +1,40 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_delete.xml b/app/src/main/res/layout/item_delete.xml new file mode 100644 index 0000000..04f2f79 --- /dev/null +++ b/app/src/main/res/layout/item_delete.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_number.xml b/app/src/main/res/layout/item_number.xml new file mode 100644 index 0000000..ea3ec4c --- /dev/null +++ b/app/src/main/res/layout/item_number.xml @@ -0,0 +1,15 @@ + + + +