diff --git a/.gitignore b/.gitignore index 5ef1324..5df9671 100644 --- a/.gitignore +++ b/.gitignore @@ -1,79 +1,79 @@ -# Built application files -*.apk -*.aar -*.ap_ -*.aab - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ -# Uncomment the following line in case you need and you don't have the release build type files in your app -release/ -app/debug - -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - -# IntelliJ -*.iml -.idea/ - -# Keystore files -# Uncomment the following lines if you do not want to check your keystore files in. -#*.jks -#*.keystore - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild -.cxx/ - -# Google Services (e.g. APIs or Firebase) -# google-services.json - -# Freeline -freeline.py -freeline/ -freeline_project_description.json - -# fastlane -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output -fastlane/readme.md - -# Version control -vcs.xml - -# lint -lint/intermediates/ -lint/generated/ -lint/outputs/ -lint/tmp/ -# lint/reports/ - -# Android Profiling +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +release/ +app/debug + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/ + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling *.hprof \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/JsonConfig.kt b/app/src/main/java/com/tsng/hidemyapplist/JsonConfig.kt index bca7886..b8e4881 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/JsonConfig.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/JsonConfig.kt @@ -1,30 +1,30 @@ -package com.tsng.hidemyapplist - -import com.google.gson.Gson - -class JsonConfig { - class Template { - val WhiteList = false - val EnableAllHooks = false - val ExcludeSystemApps = false - val HideApps = setOf() - val ApplyHooks = setOf() - } - - var HookSelf = false - var DetailLog = false - var MaxLogSize = 512 - var Scope = mapOf() - var Templates = mutableMapOf() - - override fun toString(): String { - return Gson().toJson(this) - } - - companion object { - @JvmStatic - fun fromJson(str: String): JsonConfig { - return Gson().fromJson(str, JsonConfig::class.java) - } - } +package com.tsng.hidemyapplist + +import com.google.gson.Gson + +class JsonConfig { + class Template { + val WhiteList = false + val EnableAllHooks = false + val ExcludeSystemApps = false + val HideApps = setOf() + val ApplyHooks = setOf() + } + + var HookSelf = false + var DetailLog = false + var MaxLogSize = 512 + var Scope = mapOf() + var Templates = mutableMapOf() + + override fun toString(): String { + return Gson().toJson(this) + } + + companion object { + @JvmStatic + fun fromJson(str: String): JsonConfig { + return Gson().fromJson(str, JsonConfig::class.java) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ProvidePreferenceService.kt b/app/src/main/java/com/tsng/hidemyapplist/ProvidePreferenceService.kt index 6f14572..9fd7a34 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ProvidePreferenceService.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ProvidePreferenceService.kt @@ -1,41 +1,41 @@ -package com.tsng.hidemyapplist - -import android.app.Service -import android.content.Context -import android.content.Intent -import android.os.IBinder -import com.google.gson.Gson -import kotlin.concurrent.thread - -class ProvidePreferenceService : Service() { - companion object { - @JvmStatic - fun sendConfig(context: Context) { - val json = JsonConfig() - json.HookSelf = context.getSharedPreferences("Settings", MODE_PRIVATE).getBoolean("HookSelf", false) - json.DetailLog = context.getSharedPreferences("Settings", MODE_PRIVATE).getBoolean("DetailLog", false) - json.MaxLogSize = context.getSharedPreferences("Settings", MODE_PRIVATE).getString("MaxLogSize", "512").toInt() - json.Scope = context.getSharedPreferences("Scope", MODE_PRIVATE).all as Map - for (template in context.getSharedPreferences("Templates", MODE_PRIVATE).getStringSet("List", setOf())) { - val obj = context.getSharedPreferences("tpl_$template", MODE_PRIVATE).all - json.Templates[template] = Gson().fromJson(Gson().toJson(obj), JsonConfig.Template::class.java) - } - try { - context.packageManager.getInstallerPackageName("providePreference#$json") - } catch (e: IllegalArgumentException) { } - } - } - - override fun onBind(intent: Intent): IBinder? { - return null - } - - override fun onCreate() { - thread { - while (true) { - sendConfig(this) - Thread.sleep(1000) - } - } - } +package com.tsng.hidemyapplist + +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.IBinder +import com.google.gson.Gson +import kotlin.concurrent.thread + +class ProvidePreferenceService : Service() { + companion object { + @JvmStatic + fun sendConfig(context: Context) { + val json = JsonConfig() + json.HookSelf = context.getSharedPreferences("Settings", MODE_PRIVATE).getBoolean("HookSelf", false) + json.DetailLog = context.getSharedPreferences("Settings", MODE_PRIVATE).getBoolean("DetailLog", false) + json.MaxLogSize = context.getSharedPreferences("Settings", MODE_PRIVATE).getString("MaxLogSize", "512").toInt() + json.Scope = context.getSharedPreferences("Scope", MODE_PRIVATE).all as Map + for (template in context.getSharedPreferences("Templates", MODE_PRIVATE).getStringSet("List", setOf())) { + val obj = context.getSharedPreferences("tpl_$template", MODE_PRIVATE).all + json.Templates[template] = Gson().fromJson(Gson().toJson(obj), JsonConfig.Template::class.java) + } + try { + context.packageManager.getInstallerPackageName("providePreference#$json") + } catch (e: IllegalArgumentException) { } + } + } + + override fun onBind(intent: Intent): IBinder? { + return null + } + + override fun onCreate() { + thread { + while (true) { + sendConfig(this) + Thread.sleep(1000) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/LogActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/LogActivity.kt index a43e253..3aad52f 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/LogActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/LogActivity.kt @@ -1,181 +1,181 @@ -package com.tsng.hidemyapplist.ui - -import android.content.Intent -import android.os.Bundle -import android.view.* -import android.widget.TextView -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.FileProvider -import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.RecyclerView -import com.tsng.hidemyapplist.BuildConfig -import com.tsng.hidemyapplist.R -import com.tsng.hidemyapplist.xposed.XposedUtils -import kotlinx.android.synthetic.main.fragment_log_raw.* -import kotlinx.android.synthetic.main.toolbar.* -import java.io.File -import java.io.FileWriter -import java.text.SimpleDateFormat -import java.util.* - -class LogActivity : AppCompatActivity() { - /* ----- NOT COMPLETED YET ----- */ - open class MLog(val level: Int, val tool: Int) { - /* level: D/I/E tool: Xposed/Native */ - companion object { - const val DEBUG = 0 - const val INFO = 1 - const val ERROR = 2 - const val XPOSED = 10 - const val NATIVE = 11 - const val SERVICE_INFO = 100 - const val INTERCEPTION = 101 - } - } - - class ServiceLog(level: Int, val message: String) : MLog(level, XPOSED) - - open class InterceptionLog( - level: Int, - tool: Int, - val caller: String, - val method: String - ) : MLog(level, tool) - - class PKMSLog(level: Int, caller: String, method: String, val requests: Set) : InterceptionLog(level, XPOSED, caller, method) - - class FileLog(level: Int, tool: Int, caller: String, method: String, val request: String) : InterceptionLog(level, tool, caller, method) - - class LogAdapter(val logList: List) - : RecyclerView.Adapter() { - - inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { - val logLevel: TextView = view.findViewById(R.id.log_level) - val logTool: TextView = view.findViewById(R.id.log_tool) - } - - override fun getItemViewType(position: Int): Int { - return when (logList[position].javaClass) { - ServiceLog::javaClass -> MLog.SERVICE_INFO - else -> -1 - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val layout = when (viewType) { - MLog.SERVICE_INFO -> R.layout.log_service - MLog.INTERCEPTION -> R.layout.log_interception - else -> null - } - val view = LayoutInflater.from(parent.context) - .inflate(layout!!, parent, false) - return ViewHolder(view) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val log = logList[position] - holder.logLevel.text = when (log.level) { - MLog.DEBUG -> "D" - MLog.INFO -> "I" - MLog.ERROR -> "E" - else -> null - } - holder.logTool.text = when (log.tool) { - MLog.XPOSED -> "Xposed" - MLog.NATIVE -> "Native" - else -> null - } - } - - override fun getItemCount(): Int { - return logList.size - } - } - /* ----------------------------- */ - - var rawLogs: String? = null - var showRawLogs: Boolean = true - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.toolbar_logs, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.toolbar_refresh -> { - rawLogs = XposedUtils.getLogs(this) - - replaceFragment(RawFragment()) - // replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) - true - } - R.id.toolbar_export -> { - val date = SimpleDateFormat("MM-dd_HH-mm-ss", Locale.getDefault()).format(Date()) - File(cacheDir.path + "/logs").let { if (!it.exists()) it.mkdir() } - val tmp = File(cacheDir.path + "/logs/hma_logs_$date.log") - FileWriter(tmp).use { - it.write(rawLogs) - } - val intent = Intent(Intent.ACTION_SEND).apply { - type = "text/*" - val uri = FileProvider.getUriForFile(this@LogActivity, "com.tsng.hidemyapplist.fileprovider", tmp) - putExtra(Intent.EXTRA_STREAM, uri) - } - startActivity(Intent.createChooser(intent, title)) - true - } - R.id.toolbar_clean -> { - XposedUtils.cleanLogs(this) - rawLogs = null - - replaceFragment(RawFragment()) - // replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) - true - } - /* - R.id.toolbar_raw_logs -> { - item.isChecked = !item.isChecked - showRawLogs = item.isChecked - replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) - true - } - */ - else -> super.onOptionsItemSelected(item) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_log) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - rawLogs = XposedUtils.getLogs(this) - replaceFragment(RawFragment()) - } - - private fun replaceFragment(fragment: Fragment) { - supportFragmentManager - .beginTransaction() - .replace(R.id.log_container, fragment) - .commit() - } - - class RawFragment : Fragment() { - private lateinit var activity: LogActivity - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_log_raw, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - activity = requireActivity() as LogActivity - log_tv_raw.text = activity.rawLogs - } - } +package com.tsng.hidemyapplist.ui + +import android.content.Intent +import android.os.Bundle +import android.view.* +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.FileProvider +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.RecyclerView +import com.tsng.hidemyapplist.BuildConfig +import com.tsng.hidemyapplist.R +import com.tsng.hidemyapplist.xposed.XposedUtils +import kotlinx.android.synthetic.main.fragment_log_raw.* +import kotlinx.android.synthetic.main.toolbar.* +import java.io.File +import java.io.FileWriter +import java.text.SimpleDateFormat +import java.util.* + +class LogActivity : AppCompatActivity() { + /* ----- NOT COMPLETED YET ----- */ + open class MLog(val level: Int, val tool: Int) { + /* level: D/I/E tool: Xposed/Native */ + companion object { + const val DEBUG = 0 + const val INFO = 1 + const val ERROR = 2 + const val XPOSED = 10 + const val NATIVE = 11 + const val SERVICE_INFO = 100 + const val INTERCEPTION = 101 + } + } + + class ServiceLog(level: Int, val message: String) : MLog(level, XPOSED) + + open class InterceptionLog( + level: Int, + tool: Int, + val caller: String, + val method: String + ) : MLog(level, tool) + + class PKMSLog(level: Int, caller: String, method: String, val requests: Set) : InterceptionLog(level, XPOSED, caller, method) + + class FileLog(level: Int, tool: Int, caller: String, method: String, val request: String) : InterceptionLog(level, tool, caller, method) + + class LogAdapter(val logList: List) + : RecyclerView.Adapter() { + + inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val logLevel: TextView = view.findViewById(R.id.log_level) + val logTool: TextView = view.findViewById(R.id.log_tool) + } + + override fun getItemViewType(position: Int): Int { + return when (logList[position].javaClass) { + ServiceLog::javaClass -> MLog.SERVICE_INFO + else -> -1 + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val layout = when (viewType) { + MLog.SERVICE_INFO -> R.layout.log_service + MLog.INTERCEPTION -> R.layout.log_interception + else -> null + } + val view = LayoutInflater.from(parent.context) + .inflate(layout!!, parent, false) + return ViewHolder(view) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val log = logList[position] + holder.logLevel.text = when (log.level) { + MLog.DEBUG -> "D" + MLog.INFO -> "I" + MLog.ERROR -> "E" + else -> null + } + holder.logTool.text = when (log.tool) { + MLog.XPOSED -> "Xposed" + MLog.NATIVE -> "Native" + else -> null + } + } + + override fun getItemCount(): Int { + return logList.size + } + } + /* ----------------------------- */ + + var rawLogs: String? = null + var showRawLogs: Boolean = true + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.toolbar_logs, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.toolbar_refresh -> { + rawLogs = XposedUtils.getLogs(this) + + replaceFragment(RawFragment()) + // replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) + true + } + R.id.toolbar_export -> { + val date = SimpleDateFormat("MM-dd_HH-mm-ss", Locale.getDefault()).format(Date()) + File(cacheDir.path + "/logs").let { if (!it.exists()) it.mkdir() } + val tmp = File(cacheDir.path + "/logs/hma_logs_$date.log") + FileWriter(tmp).use { + it.write(rawLogs) + } + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/*" + val uri = FileProvider.getUriForFile(this@LogActivity, "com.tsng.hidemyapplist.fileprovider", tmp) + putExtra(Intent.EXTRA_STREAM, uri) + } + startActivity(Intent.createChooser(intent, title)) + true + } + R.id.toolbar_clean -> { + XposedUtils.cleanLogs(this) + rawLogs = null + + replaceFragment(RawFragment()) + // replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) + true + } + /* + R.id.toolbar_raw_logs -> { + item.isChecked = !item.isChecked + showRawLogs = item.isChecked + replaceFragment(if (showRawLogs) BuiltifulFragment() else RawFragment()) + true + } + */ + else -> super.onOptionsItemSelected(item) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_log) + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + rawLogs = XposedUtils.getLogs(this) + replaceFragment(RawFragment()) + } + + private fun replaceFragment(fragment: Fragment) { + supportFragmentManager + .beginTransaction() + .replace(R.id.log_container, fragment) + .commit() + } + + class RawFragment : Fragment() { + private lateinit var activity: LogActivity + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_log_raw, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + activity = requireActivity() as LogActivity + log_tv_raw.text = activity.rawLogs + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt index b832fb4..1bb2490 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/ScopeManageActivity.kt @@ -1,149 +1,149 @@ -package com.tsng.hidemyapplist.ui - -import android.content.pm.ApplicationInfo -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.SearchView -import androidx.preference.ListPreference -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.iterator -import com.tsng.hidemyapplist.R -import kotlinx.android.synthetic.main.appselect.* -import kotlinx.android.synthetic.main.toolbar.* -import java.text.Collator -import java.util.* -import kotlin.collections.set -import kotlin.concurrent.thread - -class ScopeManageActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.appselect) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - if (savedInstanceState == null) { - supportFragmentManager - .beginTransaction() - .replace(R.id.appselect_container, SelectAppsFragment()) - .commit() - } - } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - - class SelectAppsFragment : PreferenceFragmentCompat() { - private lateinit var map: MutableMap - private lateinit var templates: Set - - private var showSystemApps = false - private var refreshThread: Thread? = null - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.toolbar_appselect, menu) - val searchView = menu.findItem(R.id.toolbar_search).actionView as SearchView - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String): Boolean { - return true - } - - override fun onQueryTextChange(newText: String): Boolean { - val sl = newText.toLowerCase(Locale.getDefault()) - for (pref in preferenceScreen) - pref.isVisible = pref.title.toString().toLowerCase(Locale.getDefault()).contains(sl) - return false - } - }) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.toolbar_show_system_apps -> { - item.isChecked = !item.isChecked - showSystemApps = item.isChecked - requireActivity().refresh_layout.autoRefresh() - true - } - else -> super.onOptionsItemSelected(item) - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setHasOptionsMenu(true) - preferenceManager.sharedPreferencesName = "Scope" - setPreferencesFromResource(R.xml.empty_preferences, rootKey) - map = preferenceManager.sharedPreferences.all as MutableMap - templates = setOf("") + - requireActivity().getSharedPreferences("Templates", MODE_PRIVATE).getStringSet("List", setOf())!! - requireActivity().refresh_layout.apply { - setOnRefreshListener { refresh() } - autoRefresh() - } - } - - override fun onDestroy() { - refreshThread?.let { - it.interrupt() - while (it.isAlive) - Thread.sleep(50) - } - super.onDestroy() - } - - private fun refresh() { - refreshThread = thread { - try { - val packages = requireActivity().packageManager.getInstalledPackages(0) - if (!showSystemApps) - packages.removeAll { it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 && !map.contains(it.packageName) } - packages.sortWith { o1, o2 -> - if (Thread.interrupted()) throw InterruptedException() - val l1 = o1.applicationInfo.loadLabel(requireActivity().packageManager) as String - val l2 = o2.applicationInfo.loadLabel(requireActivity().packageManager) as String - if (map.containsKey(o1.packageName) xor map.containsKey(o2.packageName)) - if (map.containsKey(o2.packageName)) 1 - else -1 - else - Collator.getInstance(Locale.getDefault()).compare(l1, l2) - } - preferenceScreen.removeAll() - for (pkg in packages) { - if (Thread.interrupted()) throw InterruptedException() - preferenceScreen.addPreference(ListPreference(context).apply { - dialogTitle = getString(R.string.template_select) - title = if (pkg.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) - getString(R.string.template_is_system_app) + " - " + pkg.applicationInfo.loadLabel(requireActivity().packageManager) - else - pkg.applicationInfo.loadLabel(requireActivity().packageManager) - icon = pkg.applicationInfo.loadIcon(requireActivity().packageManager) - key = pkg.packageName - entries = templates.toTypedArray() - entryValues = templates.toTypedArray() - if (map.containsKey(pkg.packageName)) - summary = map[pkg.packageName] - setOnPreferenceChangeListener { _, newValue -> - if (newValue.equals("")) { - summary = null - map.remove(pkg.packageName) - value = "" - preferenceManager.sharedPreferences.edit().remove(pkg.packageName).apply() - false - } else { - summary = newValue as String - map[pkg.packageName] = newValue - true - } - } - }) - } - requireActivity().refresh_layout.finishRefresh() - } catch (e: InterruptedException) { } - } - } - } +package com.tsng.hidemyapplist.ui + +import android.content.pm.ApplicationInfo +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.SearchView +import androidx.preference.ListPreference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.iterator +import com.tsng.hidemyapplist.R +import kotlinx.android.synthetic.main.appselect.* +import kotlinx.android.synthetic.main.toolbar.* +import java.text.Collator +import java.util.* +import kotlin.collections.set +import kotlin.concurrent.thread + +class ScopeManageActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.appselect) + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + if (savedInstanceState == null) { + supportFragmentManager + .beginTransaction() + .replace(R.id.appselect_container, SelectAppsFragment()) + .commit() + } + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + class SelectAppsFragment : PreferenceFragmentCompat() { + private lateinit var map: MutableMap + private lateinit var templates: Set + + private var showSystemApps = false + private var refreshThread: Thread? = null + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.toolbar_appselect, menu) + val searchView = menu.findItem(R.id.toolbar_search).actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + val sl = newText.toLowerCase(Locale.getDefault()) + for (pref in preferenceScreen) + pref.isVisible = pref.title.toString().toLowerCase(Locale.getDefault()).contains(sl) + return false + } + }) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.toolbar_show_system_apps -> { + item.isChecked = !item.isChecked + showSystemApps = item.isChecked + requireActivity().refresh_layout.autoRefresh() + true + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setHasOptionsMenu(true) + preferenceManager.sharedPreferencesName = "Scope" + setPreferencesFromResource(R.xml.empty_preferences, rootKey) + map = preferenceManager.sharedPreferences.all as MutableMap + templates = setOf("") + + requireActivity().getSharedPreferences("Templates", MODE_PRIVATE).getStringSet("List", setOf())!! + requireActivity().refresh_layout.apply { + setOnRefreshListener { refresh() } + autoRefresh() + } + } + + override fun onDestroy() { + refreshThread?.let { + it.interrupt() + while (it.isAlive) + Thread.sleep(50) + } + super.onDestroy() + } + + private fun refresh() { + refreshThread = thread { + try { + val packages = requireActivity().packageManager.getInstalledPackages(0) + if (!showSystemApps) + packages.removeAll { it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 && !map.contains(it.packageName) } + packages.sortWith { o1, o2 -> + if (Thread.interrupted()) throw InterruptedException() + val l1 = o1.applicationInfo.loadLabel(requireActivity().packageManager) as String + val l2 = o2.applicationInfo.loadLabel(requireActivity().packageManager) as String + if (map.containsKey(o1.packageName) xor map.containsKey(o2.packageName)) + if (map.containsKey(o2.packageName)) 1 + else -1 + else + Collator.getInstance(Locale.getDefault()).compare(l1, l2) + } + preferenceScreen.removeAll() + for (pkg in packages) { + if (Thread.interrupted()) throw InterruptedException() + preferenceScreen.addPreference(ListPreference(context).apply { + dialogTitle = getString(R.string.template_select) + title = if (pkg.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) + getString(R.string.template_is_system_app) + " - " + pkg.applicationInfo.loadLabel(requireActivity().packageManager) + else + pkg.applicationInfo.loadLabel(requireActivity().packageManager) + icon = pkg.applicationInfo.loadIcon(requireActivity().packageManager) + key = pkg.packageName + entries = templates.toTypedArray() + entryValues = templates.toTypedArray() + if (map.containsKey(pkg.packageName)) + summary = map[pkg.packageName] + setOnPreferenceChangeListener { _, newValue -> + if (newValue.equals("")) { + summary = null + map.remove(pkg.packageName) + value = "" + preferenceManager.sharedPreferences.edit().remove(pkg.packageName).apply() + false + } else { + summary = newValue as String + map[pkg.packageName] = newValue + true + } + } + }) + } + requireActivity().refresh_layout.finishRefresh() + } catch (e: InterruptedException) { } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/SettingsActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/SettingsActivity.kt index 0c10dfd..48a3a50 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/SettingsActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/SettingsActivity.kt @@ -1,85 +1,85 @@ -package com.tsng.hidemyapplist.ui - -import android.content.ComponentName -import android.content.pm.PackageManager -import android.os.Bundle -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.SwitchPreferenceCompat -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.topjohnwu.superuser.Shell -import com.tsng.hidemyapplist.R -import com.tsng.hidemyapplist.xposed.XposedUtils -import kotlinx.android.synthetic.main.toolbar.* - -class SettingsActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_settings) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - if (savedInstanceState == null) - supportFragmentManager - .beginTransaction() - .replace(R.id.settings_container, SettingsFragment()) - .commit() - } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - - class SettingsFragment : PreferenceFragmentCompat() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - preferenceManager.sharedPreferencesName = "Settings" - setPreferencesFromResource(R.xml.settings_preferences, rootKey) - preferenceScreen.findPreference("MaxLogSize")?.apply { - summary = entry - setOnPreferenceChangeListener { preference, newValue -> - summary = (preference as ListPreference).run { entries[findIndexOfValue(newValue as String)] } - true - } - } - preferenceScreen.findPreference("HideIcon")?.setOnPreferenceChangeListener { _, newValue -> - val component = ComponentName(requireContext(), "com.tsng.hidemyapplist.MainActivityLauncher") - val status = if (newValue == true) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED - requireActivity().packageManager.setComponentEnabledSetting(component, status, PackageManager.DONT_KILL_APP) - true - } - preferenceScreen.findPreference("StopSystemService")?.setOnPreferenceClickListener { - if (XposedUtils.getServiceVersion(requireContext()) != 0) { - MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.settings_is_clean_env) - .setMessage(R.string.settings_is_clean_env_summary) - .setPositiveButton(R.string.accept) { _, _ -> - XposedUtils.stopSystemService(requireContext(), true) - Toast.makeText(requireContext(), R.string.settings_stop_system_service, Toast.LENGTH_SHORT).show() - } - .setNegativeButton(R.string.cancel) { _, _ -> - XposedUtils.stopSystemService(requireContext(), false) - Toast.makeText(requireContext(), R.string.settings_stop_system_service, Toast.LENGTH_SHORT).show() - } - .show() - } else Toast.makeText(requireContext(), R.string.xposed_service_off, Toast.LENGTH_SHORT).show() - true - } - preferenceScreen.findPreference("ForceCleanEnv")?.setOnPreferenceClickListener { - MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.settings_force_clean_env) - .setMessage(R.string.settings_is_clean_env_summary) - .setPositiveButton(R.string.accept) { _, _ -> - val result = Shell.su("rm -rf /data/misc/hide_my_applist /data/misc/hma_selinux_test").exec().isSuccess - if (result) Toast.makeText(requireContext(), R.string.settings_force_clean_env_toast_success, Toast.LENGTH_SHORT).show() - else Toast.makeText(requireContext(), R.string.settings_force_clean_env_toast_fail, Toast.LENGTH_SHORT).show() - } - .setNegativeButton(R.string.cancel, null) - .show() - true - } - } - } +package com.tsng.hidemyapplist.ui + +import android.content.ComponentName +import android.content.pm.PackageManager +import android.os.Bundle +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreferenceCompat +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.topjohnwu.superuser.Shell +import com.tsng.hidemyapplist.R +import com.tsng.hidemyapplist.xposed.XposedUtils +import kotlinx.android.synthetic.main.toolbar.* + +class SettingsActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_settings) + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + if (savedInstanceState == null) + supportFragmentManager + .beginTransaction() + .replace(R.id.settings_container, SettingsFragment()) + .commit() + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + class SettingsFragment : PreferenceFragmentCompat() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + preferenceManager.sharedPreferencesName = "Settings" + setPreferencesFromResource(R.xml.settings_preferences, rootKey) + preferenceScreen.findPreference("MaxLogSize")?.apply { + summary = entry + setOnPreferenceChangeListener { preference, newValue -> + summary = (preference as ListPreference).run { entries[findIndexOfValue(newValue as String)] } + true + } + } + preferenceScreen.findPreference("HideIcon")?.setOnPreferenceChangeListener { _, newValue -> + val component = ComponentName(requireContext(), "com.tsng.hidemyapplist.MainActivityLauncher") + val status = if (newValue == true) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED + requireActivity().packageManager.setComponentEnabledSetting(component, status, PackageManager.DONT_KILL_APP) + true + } + preferenceScreen.findPreference("StopSystemService")?.setOnPreferenceClickListener { + if (XposedUtils.getServiceVersion(requireContext()) != 0) { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.settings_is_clean_env) + .setMessage(R.string.settings_is_clean_env_summary) + .setPositiveButton(R.string.accept) { _, _ -> + XposedUtils.stopSystemService(requireContext(), true) + Toast.makeText(requireContext(), R.string.settings_stop_system_service, Toast.LENGTH_SHORT).show() + } + .setNegativeButton(R.string.cancel) { _, _ -> + XposedUtils.stopSystemService(requireContext(), false) + Toast.makeText(requireContext(), R.string.settings_stop_system_service, Toast.LENGTH_SHORT).show() + } + .show() + } else Toast.makeText(requireContext(), R.string.xposed_service_off, Toast.LENGTH_SHORT).show() + true + } + preferenceScreen.findPreference("ForceCleanEnv")?.setOnPreferenceClickListener { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.settings_force_clean_env) + .setMessage(R.string.settings_is_clean_env_summary) + .setPositiveButton(R.string.accept) { _, _ -> + val result = Shell.su("rm -rf /data/misc/hide_my_applist /data/misc/hma_selinux_test").exec().isSuccess + if (result) Toast.makeText(requireContext(), R.string.settings_force_clean_env_toast_success, Toast.LENGTH_SHORT).show() + else Toast.makeText(requireContext(), R.string.settings_force_clean_env_toast_fail, Toast.LENGTH_SHORT).show() + } + .setNegativeButton(R.string.cancel, null) + .show() + true + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java index 7d4bfec..965107d 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateManageActivity.java @@ -1,93 +1,93 @@ -package com.tsng.hidemyapplist.ui; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; - -import androidx.appcompat.app.AppCompatActivity; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.tsng.hidemyapplist.R; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -public class TemplateManageActivity extends AppCompatActivity { - - Set templates; - ArrayAdapter adapter; - SharedPreferences list_pref; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_template_manage); - setSupportActionBar(findViewById(R.id.toolbar)); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - InitTemplateList(); - findViewById(R.id.xposed_btn_new_template).setOnClickListener(v -> { - final EditText ev = new EditText(this); - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.template_new) - .setView(ev) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.accept, ((dialog, which) -> { - String name = ev.getText().toString(); - if (templates.contains(name) || name.isEmpty() || name.contains("/")) - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(R.string.template_name_invalid) - .setPositiveButton(R.string.accept, null) - .show(); - else { - templates.add(name); - adapter.add(name); - list_pref.edit().putStringSet("List", new HashSet<>(templates)).apply(); - EditTemplate(name); - } - })).setCancelable(false).show(); - }); - } - - @Override - public boolean onSupportNavigateUp() { - onBackPressed(); - return true; - } - - private void InitTemplateList() { - list_pref = getSharedPreferences("Templates", Context.MODE_PRIVATE); - templates = new HashSet<>(list_pref.getStringSet("List", new HashSet<>())); - ListView lv = findViewById(R.id.xposed_lv_template); - adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>(templates)); - lv.setAdapter(adapter); - lv.setOnItemClickListener((parent, view, position, id) -> EditTemplate(((TextView) view).getText().toString())); - lv.setOnItemLongClickListener((parent, view, position, id) -> { - String s = ((TextView) view).getText().toString(); - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.template_delete_confirm) - .setMessage(s) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.accept, ((dialog, which) -> { - templates.remove(s); - adapter.remove(s); - deleteSharedPreferences("tpl_" + s); - list_pref.edit().putStringSet("List", new HashSet<>(templates)).apply(); - })).show(); - return true; - }); - } - - private void EditTemplate(String name) { - Intent intent = new Intent(this, TemplateSettingsActivity.class); - intent.putExtra("template", name); - startActivity(intent); - } - +package com.tsng.hidemyapplist.ui; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.tsng.hidemyapplist.R; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class TemplateManageActivity extends AppCompatActivity { + + Set templates; + ArrayAdapter adapter; + SharedPreferences list_pref; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_template_manage); + setSupportActionBar(findViewById(R.id.toolbar)); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + InitTemplateList(); + findViewById(R.id.xposed_btn_new_template).setOnClickListener(v -> { + final EditText ev = new EditText(this); + new MaterialAlertDialogBuilder(this) + .setTitle(R.string.template_new) + .setView(ev) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.accept, ((dialog, which) -> { + String name = ev.getText().toString(); + if (templates.contains(name) || name.isEmpty() || name.contains("/")) + new MaterialAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(R.string.template_name_invalid) + .setPositiveButton(R.string.accept, null) + .show(); + else { + templates.add(name); + adapter.add(name); + list_pref.edit().putStringSet("List", new HashSet<>(templates)).apply(); + EditTemplate(name); + } + })).setCancelable(false).show(); + }); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + private void InitTemplateList() { + list_pref = getSharedPreferences("Templates", Context.MODE_PRIVATE); + templates = new HashSet<>(list_pref.getStringSet("List", new HashSet<>())); + ListView lv = findViewById(R.id.xposed_lv_template); + adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>(templates)); + lv.setAdapter(adapter); + lv.setOnItemClickListener((parent, view, position, id) -> EditTemplate(((TextView) view).getText().toString())); + lv.setOnItemLongClickListener((parent, view, position, id) -> { + String s = ((TextView) view).getText().toString(); + new MaterialAlertDialogBuilder(this) + .setTitle(R.string.template_delete_confirm) + .setMessage(s) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.accept, ((dialog, which) -> { + templates.remove(s); + adapter.remove(s); + deleteSharedPreferences("tpl_" + s); + list_pref.edit().putStringSet("List", new HashSet<>(templates)).apply(); + })).show(); + return true; + }); + } + + private void EditTemplate(String name) { + Intent intent = new Intent(this, TemplateSettingsActivity.class); + intent.putExtra("template", name); + startActivity(intent); + } + } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt index 7441724..62ba37f 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/ui/TemplateSettingsActivity.kt @@ -1,172 +1,172 @@ -package com.tsng.hidemyapplist.ui - -import android.annotation.SuppressLint -import android.content.pm.ApplicationInfo -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.SearchView -import androidx.preference.CheckBoxPreference -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.iterator -import com.tsng.hidemyapplist.R -import kotlinx.android.synthetic.main.appselect.* -import kotlinx.android.synthetic.main.toolbar.* -import java.text.Collator -import java.util.* -import kotlin.concurrent.thread - - -class TemplateSettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { - private var template: String? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.appselect) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - template = intent.getStringExtra("template") - if (savedInstanceState == null) { - supportFragmentManager - .beginTransaction() - .replace(R.id.appselect_container, SettingsFragment().apply { - arguments = Bundle().apply { putString("template", template) } - }) - .commit() - } - } - - override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean { - val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment) - fragment.arguments = Bundle().apply { putString("template", template) } - supportFragmentManager - .beginTransaction() - .replace(R.id.appselect_container, fragment) - .addToBackStack(null) - .commit() - return true - } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true - } - - class SettingsFragment : PreferenceFragmentCompat() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - preferenceManager.sharedPreferencesName = "tpl_" + arguments?.getString("template") - setPreferencesFromResource(R.xml.template_preferences, rootKey) - } - } - - class HideAppsFragment : PreferenceFragmentCompat() { - private lateinit var list: MutableSet - - private var showSystemApps = false - private var refreshThread: Thread? = null - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.toolbar_appselect, menu) - menu.findItem(R.id.toolbar_select_all_apps).isVisible = true - val searchView = menu.findItem(R.id.toolbar_search).actionView as SearchView - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String): Boolean { - return true - } - - override fun onQueryTextChange(newText: String): Boolean { - val sl = newText.toLowerCase(Locale.getDefault()) - for (pref in preferenceScreen) - pref.isVisible = pref.title.toString().toLowerCase(Locale.getDefault()).contains(sl) - return false - } - }) - } - - @SuppressLint("RestrictedApi") - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.toolbar_show_system_apps -> { - item.isChecked = !item.isChecked - showSystemApps = item.isChecked - requireActivity().refresh_layout.autoRefresh() - true - } - R.id.toolbar_select_all_apps -> { - var anti = true - for (pref in preferenceScreen) - if (!(pref as CheckBoxPreference).isChecked) anti = false - for (pref in preferenceScreen) - if (!(anti xor (pref as CheckBoxPreference).isChecked)) - pref.performClick() - true - } - else -> super.onOptionsItemSelected(item) - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setHasOptionsMenu(true) - preferenceManager.sharedPreferencesName = "tpl_" + arguments?.getString("template") - setPreferencesFromResource(R.xml.empty_preferences, rootKey) - list = preferenceManager.sharedPreferences.getStringSet("HideApps", setOf())!!.toMutableSet() - requireActivity().refresh_layout.apply { - setOnRefreshListener { refresh() } - autoRefresh() - } - } - - override fun onDestroy() { - refreshThread?.let { - it.interrupt() - while (it.isAlive) - Thread.sleep(50) - } - super.onDestroy() - } - - private fun refresh() { - refreshThread = thread { - try { - val packages = requireActivity().packageManager.getInstalledPackages(0) - if (!showSystemApps) - packages.removeAll { it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 && !list.contains(it.packageName) } - packages.sortWith { o1, o2 -> - if (Thread.interrupted()) throw InterruptedException() - val l1 = o1.applicationInfo.loadLabel(requireActivity().packageManager) as String - val l2 = o2.applicationInfo.loadLabel(requireActivity().packageManager) as String - if (list.contains(o1.packageName) xor list.contains(o2.packageName)) - if (list.contains(o2.packageName)) 1 - else -1 - else - Collator.getInstance(Locale.getDefault()).compare(l1, l2) - } - preferenceScreen.removeAll() - for (pkg in packages) { - if (Thread.interrupted()) throw InterruptedException() - preferenceScreen.addPreference(CheckBoxPreference(context).apply { - title = if (pkg.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) - getString(R.string.template_is_system_app) + " - " + pkg.applicationInfo.loadLabel(requireActivity().packageManager) - else - pkg.applicationInfo.loadLabel(requireActivity().packageManager) - icon = pkg.applicationInfo.loadIcon(requireActivity().packageManager) - isChecked = list.contains(pkg.packageName) - setOnPreferenceChangeListener { _, newValue -> - if (newValue == true) - list.add(pkg.packageName) - else - list.remove(pkg.packageName) - preferenceManager.sharedPreferences.edit().putStringSet("HideApps", list.toSet()).apply() - true - } - }) - } - requireActivity().refresh_layout.finishRefresh() - } catch (e: InterruptedException) { } - } - } - } +package com.tsng.hidemyapplist.ui + +import android.annotation.SuppressLint +import android.content.pm.ApplicationInfo +import android.os.Bundle +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.SearchView +import androidx.preference.CheckBoxPreference +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.iterator +import com.tsng.hidemyapplist.R +import kotlinx.android.synthetic.main.appselect.* +import kotlinx.android.synthetic.main.toolbar.* +import java.text.Collator +import java.util.* +import kotlin.concurrent.thread + + +class TemplateSettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + private var template: String? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.appselect) + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + template = intent.getStringExtra("template") + if (savedInstanceState == null) { + supportFragmentManager + .beginTransaction() + .replace(R.id.appselect_container, SettingsFragment().apply { + arguments = Bundle().apply { putString("template", template) } + }) + .commit() + } + } + + override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean { + val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment) + fragment.arguments = Bundle().apply { putString("template", template) } + supportFragmentManager + .beginTransaction() + .replace(R.id.appselect_container, fragment) + .addToBackStack(null) + .commit() + return true + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + + class SettingsFragment : PreferenceFragmentCompat() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + preferenceManager.sharedPreferencesName = "tpl_" + arguments?.getString("template") + setPreferencesFromResource(R.xml.template_preferences, rootKey) + } + } + + class HideAppsFragment : PreferenceFragmentCompat() { + private lateinit var list: MutableSet + + private var showSystemApps = false + private var refreshThread: Thread? = null + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.toolbar_appselect, menu) + menu.findItem(R.id.toolbar_select_all_apps).isVisible = true + val searchView = menu.findItem(R.id.toolbar_search).actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return true + } + + override fun onQueryTextChange(newText: String): Boolean { + val sl = newText.toLowerCase(Locale.getDefault()) + for (pref in preferenceScreen) + pref.isVisible = pref.title.toString().toLowerCase(Locale.getDefault()).contains(sl) + return false + } + }) + } + + @SuppressLint("RestrictedApi") + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.toolbar_show_system_apps -> { + item.isChecked = !item.isChecked + showSystemApps = item.isChecked + requireActivity().refresh_layout.autoRefresh() + true + } + R.id.toolbar_select_all_apps -> { + var anti = true + for (pref in preferenceScreen) + if (!(pref as CheckBoxPreference).isChecked) anti = false + for (pref in preferenceScreen) + if (!(anti xor (pref as CheckBoxPreference).isChecked)) + pref.performClick() + true + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setHasOptionsMenu(true) + preferenceManager.sharedPreferencesName = "tpl_" + arguments?.getString("template") + setPreferencesFromResource(R.xml.empty_preferences, rootKey) + list = preferenceManager.sharedPreferences.getStringSet("HideApps", setOf())!!.toMutableSet() + requireActivity().refresh_layout.apply { + setOnRefreshListener { refresh() } + autoRefresh() + } + } + + override fun onDestroy() { + refreshThread?.let { + it.interrupt() + while (it.isAlive) + Thread.sleep(50) + } + super.onDestroy() + } + + private fun refresh() { + refreshThread = thread { + try { + val packages = requireActivity().packageManager.getInstalledPackages(0) + if (!showSystemApps) + packages.removeAll { it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0 && !list.contains(it.packageName) } + packages.sortWith { o1, o2 -> + if (Thread.interrupted()) throw InterruptedException() + val l1 = o1.applicationInfo.loadLabel(requireActivity().packageManager) as String + val l2 = o2.applicationInfo.loadLabel(requireActivity().packageManager) as String + if (list.contains(o1.packageName) xor list.contains(o2.packageName)) + if (list.contains(o2.packageName)) 1 + else -1 + else + Collator.getInstance(Locale.getDefault()).compare(l1, l2) + } + preferenceScreen.removeAll() + for (pkg in packages) { + if (Thread.interrupted()) throw InterruptedException() + preferenceScreen.addPreference(CheckBoxPreference(context).apply { + title = if (pkg.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) + getString(R.string.template_is_system_app) + " - " + pkg.applicationInfo.loadLabel(requireActivity().packageManager) + else + pkg.applicationInfo.loadLabel(requireActivity().packageManager) + icon = pkg.applicationInfo.loadIcon(requireActivity().packageManager) + isChecked = list.contains(pkg.packageName) + setOnPreferenceChangeListener { _, newValue -> + if (newValue == true) + list.add(pkg.packageName) + else + list.remove(pkg.packageName) + preferenceManager.sharedPreferences.edit().putStringSet("HideApps", list.toSet()).apply() + true + } + }) + } + requireActivity().refresh_layout.finishRefresh() + } catch (e: InterruptedException) { } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt index 173c0d9..4ee53a9 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedEntry.kt @@ -1,31 +1,31 @@ -package com.tsng.hidemyapplist.xposed - -import com.tsng.hidemyapplist.xposed.XposedUtils.APPNAME -import com.tsng.hidemyapplist.xposed.hooks.PackageManagerService -import de.robv.android.xposed.IXposedHookLoadPackage -import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodReplacement -import de.robv.android.xposed.XposedHelpers -import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam - -class XposedEntry : IXposedHookLoadPackage, IXposedHookZygoteInit { - companion object { - lateinit var modulePath: String - } - - override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { - modulePath = startupParam.modulePath - } - - override fun handleLoadPackage(lpp: LoadPackageParam) { - if (lpp.packageName == APPNAME) { - XposedHelpers.findAndHookMethod("com.tsng.hidemyapplist.MainActivity", lpp.classLoader, "isModuleActivated", object : XC_MethodReplacement() { - override fun replaceHookedMethod(param: MethodHookParam): Any { - return true; - } - }) - } - if (lpp.packageName == "android") - PackageManagerService().handleLoadPackage(lpp) - } +package com.tsng.hidemyapplist.xposed + +import com.tsng.hidemyapplist.xposed.XposedUtils.APPNAME +import com.tsng.hidemyapplist.xposed.hooks.PackageManagerService +import de.robv.android.xposed.IXposedHookLoadPackage +import de.robv.android.xposed.IXposedHookZygoteInit +import de.robv.android.xposed.XC_MethodReplacement +import de.robv.android.xposed.XposedHelpers +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam + +class XposedEntry : IXposedHookLoadPackage, IXposedHookZygoteInit { + companion object { + lateinit var modulePath: String + } + + override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { + modulePath = startupParam.modulePath + } + + override fun handleLoadPackage(lpp: LoadPackageParam) { + if (lpp.packageName == APPNAME) { + XposedHelpers.findAndHookMethod("com.tsng.hidemyapplist.MainActivity", lpp.classLoader, "isModuleActivated", object : XC_MethodReplacement() { + override fun replaceHookedMethod(param: MethodHookParam): Any { + return true; + } + }) + } + if (lpp.packageName == "android") + PackageManagerService().handleLoadPackage(lpp) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedUtils.kt b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedUtils.kt index 152565d..22ca05f 100644 --- a/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedUtils.kt +++ b/app/src/main/java/com/tsng/hidemyapplist/xposed/XposedUtils.kt @@ -1,63 +1,63 @@ -package com.tsng.hidemyapplist.xposed - -import android.content.Context -import com.tsng.hidemyapplist.BuildConfig -import de.robv.android.xposed.XposedHelpers - -object XposedUtils { - const val resultNo = "HMA No" - const val resultYes = "HMA Yes" - const val resultIllegal = "HMA Illegal" - const val APPNAME = BuildConfig.APPLICATION_ID - - @JvmStatic - fun stopSystemService(context: Context, cleanEnv: Boolean) { - try { - context.packageManager.getInstallerPackageName("stopSystemService#$cleanEnv") - } catch (e: IllegalArgumentException) { - } - } - - @JvmStatic - fun getServiceVersion(context: Context): Int { - return try { - context.packageManager.getInstallerPackageName("checkHMAServiceVersion").toInt() - } catch (e: IllegalArgumentException) { - 0 - } - } - - @JvmStatic - fun getServeTimes(context: Context): Int { - return try { - context.packageManager.getInstallerPackageName("getServeTimes").toInt() - } catch (e: IllegalArgumentException) { - 0 - } - } - - @JvmStatic - fun getLogs(context: Context): String? { - return try { - context.packageManager.getInstallerPackageName("getLogs") - } catch (e: IllegalArgumentException) { - null - } - } - - @JvmStatic - fun cleanLogs(context: Context) { - try { - context.packageManager.getInstallerPackageName("cleanLogs") - } catch (e: IllegalArgumentException) { - } - } - - @JvmStatic - fun getRecursiveField(entry: Any, list: List): Any? { - var field: Any? = entry - for (it in list) - field = XposedHelpers.getObjectField(field, it) ?: return null - return field - } +package com.tsng.hidemyapplist.xposed + +import android.content.Context +import com.tsng.hidemyapplist.BuildConfig +import de.robv.android.xposed.XposedHelpers + +object XposedUtils { + const val resultNo = "HMA No" + const val resultYes = "HMA Yes" + const val resultIllegal = "HMA Illegal" + const val APPNAME = BuildConfig.APPLICATION_ID + + @JvmStatic + fun stopSystemService(context: Context, cleanEnv: Boolean) { + try { + context.packageManager.getInstallerPackageName("stopSystemService#$cleanEnv") + } catch (e: IllegalArgumentException) { + } + } + + @JvmStatic + fun getServiceVersion(context: Context): Int { + return try { + context.packageManager.getInstallerPackageName("checkHMAServiceVersion").toInt() + } catch (e: IllegalArgumentException) { + 0 + } + } + + @JvmStatic + fun getServeTimes(context: Context): Int { + return try { + context.packageManager.getInstallerPackageName("getServeTimes").toInt() + } catch (e: IllegalArgumentException) { + 0 + } + } + + @JvmStatic + fun getLogs(context: Context): String? { + return try { + context.packageManager.getInstallerPackageName("getLogs") + } catch (e: IllegalArgumentException) { + null + } + } + + @JvmStatic + fun cleanLogs(context: Context) { + try { + context.packageManager.getInstallerPackageName("cleanLogs") + } catch (e: IllegalArgumentException) { + } + } + + @JvmStatic + fun getRecursiveField(entry: Any, list: List): Any? { + var field: Any? = entry + for (it in list) + field = XposedHelpers.getObjectField(field, it) ?: return null + return field + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_detection.xml b/app/src/main/res/layout/activity_detection.xml index 5ff29fe..eab5618 100644 --- a/app/src/main/res/layout/activity_detection.xml +++ b/app/src/main/res/layout/activity_detection.xml @@ -1,47 +1,47 @@ - - - - - - - - - -