commit 6cde51f782d332d41dc56276f01d257191f91f57 Author: xsean Date: Mon Oct 20 09:54:56 2025 +0800 first diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.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 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..8f00030 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..280aad6 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +MyAndriodInfo \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..63c9977 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..3c0304c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..6d0ee1c --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ec985a3 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file 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.kts b/app/build.gradle.kts new file mode 100644 index 0000000..d3c9b06 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,81 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + id("com.google.devtools.ksp") version "2.0.0-1.0.24" +} + +android { + namespace = "com.xyzshell.myandriodinfo" + compileSdk = 35 + + defaultConfig { + applicationId = "com.xyzshell.myandriodinfo" + minSdk = 29 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + ndk { + abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a")) + } + } + + buildTypes { + release { + isMinifyEnabled = false + 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 + prefab = true + aidl = true + } + + externalNativeBuild { + cmake { + path = file("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + ndkVersion = "25.2.9519653" +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.lifecycle.livedata.ktx) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.navigation.fragment.ktx) + implementation(libs.androidx.navigation.ui.ktx) + implementation(libs.kotlinx.serialization.json) + // implementation(com.bytedance.android.shadowhook) + // implementation("org.nanohttpd:nanohttpd:2.3.1") + implementation(libs.json.json) + implementation(libs.androidx.webkit) + implementation(libs.play.services.appset) + implementation(libs.play.services.ads.identifier) + implementation(libs.squareup.okhttp) + // 引入注解 + implementation(project(":ksp-annotations")) + // 引入KSP处理器 + ksp(project(":ksp-processor")) + + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/app/src/androidTest/java/com/xyzshell/myandriodinfo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/xyzshell/myandriodinfo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..7ec7f68 --- /dev/null +++ b/app/src/androidTest/java/com/xyzshell/myandriodinfo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.xyzshell.myandriodinfo + +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.xyzshell.myandriodinfo", 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..24f64e3 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..b571122 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,40 @@ + +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html. +# For more examples on how to use CMake, see https://github.com/android/ndk-samples. + +# Sets the minimum CMake version required for this project. +cmake_minimum_required(VERSION 3.22.1) + +# Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, +# Since this is the top level CMakeLists.txt, the project name is also accessible +# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level +# build script scope). +project("myandriodinfo") + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. +# +# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define +# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} +# is preferred for the same purpose. +# +# In order to load a library into your app from Java/Kotlin, you must call +# System.loadLibrary() and pass the name of the library defined here; +# for GameActivity/NativeActivity derived applications, the same library name must be +# used in the AndroidManifest.xml file. +add_library(${CMAKE_PROJECT_NAME} SHARED + # List C/C++ source files with relative paths to this CMakeLists.txt. + myandriodinfo.cpp) + +# Specifies libraries CMake should link to your target library. You +# can link libraries from various origins, such as libraries defined in this +# build script, prebuilt third-party libraries, or Android system libraries. +target_link_libraries(${CMAKE_PROJECT_NAME} + # List libraries link to the target library + android + log) + + diff --git a/app/src/main/cpp/myandriodinfo.cpp b/app/src/main/cpp/myandriodinfo.cpp new file mode 100644 index 0000000..3789ded --- /dev/null +++ b/app/src/main/cpp/myandriodinfo.cpp @@ -0,0 +1,17 @@ +// Write C++ code here. +// +// Do not forget to dynamically load the C++ library into your application. +// +// For instance, +// +// In MainActivity.java: +// static { +// System.loadLibrary("myandriodinfo"); +// } +// +// Or, in MainActivity.kt: +// companion object { +// init { +// System.loadLibrary("myandriodinfo") +// } +// } \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/MainActivity.kt b/app/src/main/java/com/xyzshell/myandriodinfo/MainActivity.kt new file mode 100644 index 0000000..60fa295 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/MainActivity.kt @@ -0,0 +1,42 @@ +package com.xyzshell.myandriodinfo + +import android.content.pm.PackageManager +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupActionBarWithNavController +import androidx.navigation.ui.setupWithNavController +import com.google.android.material.bottomnavigation.BottomNavigationView + +import com.xyzshell.myandriodinfo.databinding.ActivityMainBinding + + +class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + val navView: BottomNavigationView = binding.navView + + val navController = findNavController(R.id.nav_host_fragment_activity_main) + // Passing each menu ID as a set of Ids because each + // menu should be considered as top level destinations. + val appBarConfiguration = AppBarConfiguration( + setOf( + R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications + ) + ) + setupActionBarWithNavController(navController, appBarConfiguration) + navView.setupWithNavController(navController) + + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/service/HttpSender.kt b/app/src/main/java/com/xyzshell/myandriodinfo/service/HttpSender.kt new file mode 100644 index 0000000..e19f40e --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/service/HttpSender.kt @@ -0,0 +1,48 @@ +package com.xyzshell.myandriodinfo.service + +import android.util.Log +import okhttp3.Call +import okhttp3.Callback +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import okio.IOException +import org.json.JSONObject +import org.json.JSONStringer + + + +class HttpSender { + private val mediaType = "application/json".toMediaType() + private val client = OkHttpClient() + + fun post(url:String, obj:JSONObject){ + val jsonString = obj.toString() + val body = jsonString.toRequestBody(mediaType) + val request = Request.Builder() + .url(url) + .post(body) + .build() + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.e("NetworkManager", "POST request failed", e) + + } + + override fun onResponse(call: Call, response: Response) { + val body = response.body?.string() + println(body) + if (response.isSuccessful) { + Log.d("NetworkManager", "POST request successful: $body") + + } else { + Log.e("NetworkManager", "POST request failed with code: ${response.code}") + + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/service/JsonSerializer.kt b/app/src/main/java/com/xyzshell/myandriodinfo/service/JsonSerializer.kt new file mode 100644 index 0000000..7cd503b --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/service/JsonSerializer.kt @@ -0,0 +1,22 @@ +package com.xyzshell.myandriodinfo.service + +import kotlinx.serialization.json.Json +import kotlinx.serialization.encodeToString + + +class JsonSerializer { + companion object { + val json = Json { + prettyPrint = true + ignoreUnknownKeys = true + } + + inline fun toJson(obj: T): String { + return json.encodeToString(obj) + } + + inline fun fromJson(jsonString: String): T { + return json.decodeFromString(jsonString) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/service/TestData.kt b/app/src/main/java/com/xyzshell/myandriodinfo/service/TestData.kt new file mode 100644 index 0000000..585b32b --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/service/TestData.kt @@ -0,0 +1,7 @@ +package com.xyzshell.myandriodinfo.service + +import com.xyzshell.ksp_annotations.AutoBuilder + +@AutoBuilder +data class TestData(val name: String, val age: Int) { +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardFragment.kt new file mode 100644 index 0000000..3a7d777 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardFragment.kt @@ -0,0 +1,42 @@ +package com.xyzshell.myandriodinfo.ui.dashboard + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.xyzshell.myandriodinfo.databinding.FragmentDashboardBinding + +class DashboardFragment : Fragment() { + + private var _binding: FragmentDashboardBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val dashboardViewModel = + ViewModelProvider(this).get(DashboardViewModel::class.java) + + _binding = FragmentDashboardBinding.inflate(inflater, container, false) + val root: View = binding.root + + val textView: TextView = binding.textDashboard + dashboardViewModel.text.observe(viewLifecycleOwner) { + textView.text = it + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardViewModel.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardViewModel.kt new file mode 100644 index 0000000..b8512f2 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/dashboard/DashboardViewModel.kt @@ -0,0 +1,13 @@ +package com.xyzshell.myandriodinfo.ui.dashboard + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class DashboardViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is dashboard Fragment" + } + val text: LiveData = _text +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AdvertisingIdClient.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AdvertisingIdClient.kt new file mode 100644 index 0000000..26100e8 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AdvertisingIdClient.kt @@ -0,0 +1,105 @@ +//package com.xyzshell.myandriodinfo.ui.home +// +//import android.content.ComponentName +//import android.content.Context +//import android.content.Intent +//import android.content.ServiceConnection +//import android.os.IBinder +//import android.os.IInterface +//import android.os.Looper +//import android.os.Parcel +//import android.os.RemoteException +//import java.util.concurrent.LinkedBlockingQueue +// +// class AdvertisingIdClient { +// @Throws(Exception::class) +// fun GetGoogleAdId(context: Context): String? { +// if (Looper.getMainLooper() == Looper.myLooper()) { +// return "Cannot call in the main thread, You must call in the other thread" +// } +// val pm = context.packageManager +// pm.getPackageInfo("com.android.vending", 0) +// val connection: AdvertisingConnection = AdvertisingConnection() +// val intent = Intent( +// "com.google.android.gms.ads.identifier.service.START" +// ) +// intent.setPackage("com.google.android.gms") +// if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) { +// try { +// val adInterface: AdvertisingInterface = AdvertisingInterface( +// connection.binder +// ) +// return adInterface.id +// } finally { +// context.unbindService(connection) +// } +// } +// return "" +// } +// +// class AdvertisingConnection : ServiceConnection { +// var retrieved: Boolean = false +// private val queue = LinkedBlockingQueue(1) +// +// override fun onServiceConnected(name: ComponentName, service: IBinder) { +// try { +// queue.put(service) +// } catch (localInterruptedException: InterruptedException) { +// } +// } +// +// override fun onServiceDisconnected(name: ComponentName) { +// } +// +// @get:Throws(InterruptedException::class) +// val binder: IBinder +// get() { +// check(!this.retrieved) +// this.retrieved = true +// return queue.take() +// } +// } +// +// class AdvertisingInterface(private val binder: IBinder) : IInterface { +// override fun asBinder(): IBinder { +// return binder +// } +// +// @get:Throws(RemoteException::class) +// val id: String? +// get() { +// val data = Parcel.obtain() +// val reply = Parcel.obtain() +// val id: String? +// try { +// data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService") +// binder.transact(1, data, reply, 0) +// reply.readException() +// id = reply.readString() +// } finally { +// reply.recycle() +// data.recycle() +// } +// return id +// } +// +// @Throws(RemoteException::class) +// fun isLimitAdTrackingEnabled(paramBoolean: Boolean): Boolean { +// val data = Parcel.obtain() +// val reply = Parcel.obtain() +// val limitAdTracking: Boolean +// try { +// data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService") +// data.writeInt(if (paramBoolean) 1 else 0) +// binder.transact(2, data, reply, 0) +// reply.readException() +// limitAdTracking = 0 != reply.readInt() +// } finally { +// reply.recycle() +// data.recycle() +// } +// return limitAdTracking +// } +// } +// +//} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfo.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfo.kt new file mode 100644 index 0000000..2f538e7 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfo.kt @@ -0,0 +1,412 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.adservices.AdServicesState +import android.annotation.SuppressLint +import android.app.ActivityManager +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.ApplicationInfo +import android.content.pm.ConfigurationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.res.Configuration +import android.graphics.Rect +import android.hardware.Sensor +import android.hardware.SensorManager +import android.media.AudioManager +import android.net.ConnectivityManager +import android.net.wifi.WifiManager +import android.os.Build +import android.os.Environment +import android.os.PowerManager +import android.os.Process +import android.os.SystemClock +import android.os.ext.SdkExtensions +import android.provider.Settings +import android.telephony.TelephonyManager +import android.util.DisplayMetrics +import android.view.RoundedCorner +import android.view.WindowManager +import android.widget.ExpandableListView +import android.widget.ListView +import androidx.annotation.RequiresExtension +import com.google.android.gms.ads.identifier.AdvertisingIdClient +import com.google.android.gms.appset.AppSet +import com.google.android.gms.appset.AppSetIdClient +import com.google.android.gms.appset.AppSetIdInfo +import com.google.android.gms.tasks.Task +import java.io.File +import java.net.NetworkInterface +import java.util.Date +import java.util.Locale +import java.util.TimeZone +import java.util.concurrent.Executors + + + +class AppInfo(private val context:Context, private val listView: ExpandableListView) { + + private val mkv: MutableMap = mutableMapOf() + + private lateinit var adapter: MyListViewAdapter + private val activityManager: ActivityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + private val connectivityManager = this.context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + private val packageManager: PackageManager = this.context.packageManager + private val applicationInfo: ApplicationInfo = this.context.applicationInfo + private val audioManager:AudioManager = this.context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + private val windowManager = this.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + private val telephonyManager = this.context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + private val packageInfo:PackageInfo = + this.packageManager.getPackageInfo(this.context.packageName,0) + private val powerManager = this.context.getSystemService(Context.POWER_SERVICE) as PowerManager + private val wifiManager = this.context.getSystemService(Context.WIFI_SERVICE) as WifiManager + fun initList() { + val groups = GroupInfo() + mkv.forEach { + groups.set("信息", it.key, it.value.name, it.value.desc) + } + + val sp = SystemProp().getInfo() + sp.kv.forEach { + groups.set("SystemProperties", it.key, it.key, it.value) + } + + BuildProp().getInfo().kv.forEach { + groups.set("BUILD", it.key, it.key, it.value) + } + GpuInfo().getInfo() + adapter = MyListViewAdapter(this.context, groups) + this.listView.setAdapter(this.adapter) + } + + private fun setMkv(k: String, name: String, value: Any) { + mkv[k] = AppInfoItem(name, value) + } + + fun setAppInfo() { + val v = packageManager.getApplicationLabel(applicationInfo) + var install_name = packageManager.getInstallerPackageName(applicationInfo.packageName) + if(install_name == null) { + install_name = "" + } + setMkv("app_name", "App Name", v) + setMkv("install_name", "install name", install_name) + this.packageInfo.versionName?.let { setMkv("app_version", "Version Name", it) } + setMkv("app_version_code", "Version Code", this.packageInfo.versionCode) + setMkv("firstInstallTime", "安装时间", this.packageInfo.firstInstallTime) + setMkv("package_name", "Package Name", applicationInfo.packageName) + setMkv("target_sdk", "Target SDK", applicationInfo.targetSdkVersion) + setMkv("idfv", "idfv", "") + setMkv("idfv_scope", "idfv scope", -1) + val client = AppSet.getClient(this.context) as AppSetIdClient + val task: Task = client.appSetIdInfo as Task + task.addOnSuccessListener { + // Determine current scope of app set ID. + val scope: Int = it.scope + + // Read app set ID value, which uses version 4 of the + // universally unique identifier (UUID) format. + val id: String = it.id + + setMkv("idfv", "idfv", id) + setMkv("idfv_scope", "idfv scope", scope) + initList() + } + } + + private fun setFsLm() { + val v = File(applicationInfo.sourceDir).lastModified() + setMkv("fslm", "app安装文件时间", v) + } + + fun setPermissionInfo() { + val ps_tpg = checkPermission("android.permission.ACCESS_ADSERVICES_TOPICS") + setMkv("ps_tpg","允许应用访问用户的兴趣话题信息", ps_tpg) + val ps_apg = checkPermission("android.permission.ACCESS_ADSERVICES_ATTRIBUTION") + setMkv("ps_apg", "广告归因追踪", ps_apg) + var ps_aipg = checkPermission("android.permission.ACCESS_ADSERVICES_AD_ID") + setMkv("ps_aipg", "广告ID访问", ps_aipg) + val ps_capg = checkPermission("android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE") + setMkv("ps_capg", "允许应用创建和管理自定义广告受众群体",ps_capg) + } + + fun setNetworkInfo() { + setMkv("connectivity", "网络状态", + connectivityManager.restrictBackgroundStatus != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED) + val sb = StringBuilder() + val interfaces = NetworkInterface.getNetworkInterfaces() + if (interfaces != null) { + for (intf in interfaces) { + try { + if (!intf.isUp || intf.isLoopback) continue + sb.append("name: ${intf.name}, displayName: ${intf.displayName},") + val addresses = intf.inetAddresses + for (addr in addresses) { + sb.append("address: ${addr.hostAddress}\n") + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + setMkv("NetworkInterface", "网络状态", sb.toString()) + } + + fun setBuildInfo() { + setMkv("VERSION.SDK_INT","Build.VERSION.SDK_INT", Build.VERSION.SDK_INT) + setMkv("TAGS","Build.TAGS", Build.TAGS) + setMkv("SUPPORTED_ABIS","Build.SUPPORTED_ABIS", Build.SUPPORTED_ABIS) + setMkv("CPU_ABI","Build.CPU_ABI", Build.CPU_ABI) + setMkv("CPU_ABI2","Build.CPU_ABI2", Build.CPU_ABI2) + setMkv("MANUFACTURER","Build.MANUFACTURER",Build.MANUFACTURER) + setMkv("BRAND","Build.BRAND",Build.BRAND) + setMkv("HARDWARE","Build.HARDWARE",Build.HARDWARE) + setMkv("MODEL","Build.MODEL",Build.MODEL) + setMkv("DEVICE","Build.DEVICE",Build.DEVICE) + setMkv("Build.VERSION", "os version", Build.VERSION.RELEASE) + } + + fun setFont() { + setMkv("font_scale", "Font Scale", Settings.System.getFloat(this.context.contentResolver,"font_scale")) + + } + + fun setLocal() { + setMkv("tz", "TimeZone", + Math.round(TimeZone.getDefault().getOffset(Date().time) * 10.0 / 3600000.0) / 10.0) + setMkv("tz_offset", "tz_offset",Math.round( + TimeZone.getDefault().getOffset( + Date().time + ) * 10.0 / 3600000.0 + ) / 10.0) + setMkv("local","local",Locale.getDefault().toString()) + val localeList = this.context.resources.configuration.locales + val stringBuilder = StringBuilder() + for (i in 0 until localeList.size()) { + val locale = localeList.get(i) + stringBuilder.append("Locale: ${locale.toString()}, Language: ${locale.language}, Country: ${locale.country}\n") + } + + setMkv("local_list", "Locale List", stringBuilder.toString()) + } + + fun setScreen() { + val screen_brightness = Settings.System.getInt(this.context.contentResolver, Settings.System.SCREEN_BRIGHTNESS) / 255.0F * 100.0F + setMkv("screen_brightness","屏幕亮度", screen_brightness) + setMkv("screen_orientation", "屏幕方向", this.context.resources.configuration.orientation) + + val rect = Rect() + windowManager.defaultDisplay.getRectSize(rect) + val displayMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(displayMetrics) + val sb = StringBuilder() + sb.append("w:${rect.width()},h:${rect.height()}\n") + sb.append("W:${displayMetrics.widthPixels},H: ${displayMetrics.heightPixels}\n") + sb.append("density:${displayMetrics.density}\n") + sb.append("densityDpi:${displayMetrics.densityDpi}\n") + sb.append("xdpi:${displayMetrics.xdpi},ydpi:${displayMetrics.ydpi}\n") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + sb.append("tl${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)}\n") + sb.append("tr${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT)}\n") + sb.append("bl${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT)}\n") + sb.append("br${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT)}\n") + } + setMkv("screen", "屏幕", sb.toString()) + + } + + fun setDisk() { + setMkv("disk_free","磁盘剩余", Environment.getDataDirectory().freeSpace) + setMkv("disk_total", "磁盘", Environment.getDataDirectory().totalSpace) + } + + + fun getProcessName():String { + try { + val packageManager = context.packageManager + val applicationInfo = packageManager.getApplicationInfo( + context.packageName, + PackageManager.GET_META_DATA // 0x80 + ) + val metaData = applicationInfo.metaData + + try { + val processName = applicationInfo.processName + return processName + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + return "" + } + fun getProcessName1():String { + val pid = Process.myPid() + val activityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val runningManager = activityManager.runningAppProcesses + runningManager?.forEach { + if(it.pid == pid) { + return it.processName + } + } + return "" + } + + fun setSystem() { + setMkv("pc", "Processors", Runtime.getRuntime().availableProcessors()) + setMkv("boot_ms","bt_ms", System.currentTimeMillis() - SystemClock.elapsedRealtime()) + setMkv("processName1", "Process Name", getProcessName()) + setMkv("processName2", "Process Name 1", getProcessName1()) + val b1 = packageManager.hasSystemFeature("com.google.android.play.feature.HPE_EXPERIENCE") + val b2 = packageManager.hasSystemFeature(PackageManager.FEATURE_PC) + val kb = this.context.resources.configuration.keyboard + var is_pc = true + if(kb != Configuration.KEYBOARD_QWERTY || (!b1 && !b2)) { + is_pc = false + } + setMkv("is_pc", "is pc", is_pc) + } + + fun setMem() { + val memoryInfo = ActivityManager.MemoryInfo() + activityManager.getMemoryInfo(memoryInfo) + val sb = StringBuilder() + setMkv("availMem", "可用内存", memoryInfo.availMem) + setMkv("totalMem", "总内存", memoryInfo.totalMem) + setMkv("threshold", "threshold", memoryInfo.threshold) + setMkv("lowMemory", "lowMemory", memoryInfo.lowMemory) + setMkv("GlEsVersion", "GlEsVersion", activityManager.deviceConfigurationInfo.glEsVersion) + + + } + + fun setSensor() { + val sensorManager = this.context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + val isGYROSCOPE = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null + setMkv("isGYROSCOPE","陀螺仪", isGYROSCOPE) + } + + + fun setBatteryInfo() { + val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) + val intent = this.context.registerReceiver(null, intentFilter) + var level = -1 + var scale = -1 + var adn = -1 + var status = -1 + if(intent!=null) { + level = intent.getIntExtra("level", -1) + setMkv("battery_level", "电池Level", level) + scale = intent.getIntExtra("scale", -1) + setMkv("battery_scale", "电池scale", level) + if(level > 0 && scale > 0) { + adn = ((level / scale * 100.0F).toInt()) + setMkv("battery_adn", "电池adn", adn) + } + status = intent.getIntExtra("status", -1) + setMkv("battery_status", "电池状态", status) + } + var plugged = false + if(intent != null) { + // stay_on_while_plugged_in + val plugged1:Int = intent.getIntExtra("plugged", -1) + if(plugged1 > 0) { + plugged = true + } + setMkv("battery_plugged", "电池充电", plugged) + } + setMkv("isPowerSaveMode", "Power Save Mode", powerManager.isPowerSaveMode) + // setMkv("sowpie","插电模式:sowpie", Settings.Global.getInt(this.context.contentResolver, "stay_on_while_plugged_in", -1) > 0) + } + + + fun setAudio() { + setMkv("MusicActive", "MusicActive", audioManager.isMusicActive) + setMkv("volume", "volume", audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) + setMkv("SpeakerphoneOn","SpeakerphoneOn", audioManager.isSpeakerphoneOn) + setMkv("ringerMode", "ringerMode", audioManager.ringerMode) + val sb = StringBuilder() + val arrayOfAudioDeviceInfo = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS) + for (i in arrayOfAudioDeviceInfo.indices) { + val audioDeviceInfo = arrayOfAudioDeviceInfo[i] + if (audioDeviceInfo != null) { + // 3,7,8 + // public static final int TYPE_BLUETOOTH_A2DP = 8; + // public static final int TYPE_BLUETOOTH_SCO = 7; + // public static final int TYPE_WIRED_HEADSET = 3; + sb.append("name: " + audioDeviceInfo.productName + ", type: " + audioDeviceInfo.type + "\n") + } + } + sb.append("isWiredHeadsetOn:${audioManager.isWiredHeadsetOn()}\n") + sb.append("isBluetoothScoOn:${audioManager.isBluetoothScoOn()}\n") + sb.append("isBluetoothA2dpOn:${audioManager.isBluetoothA2dpOn()}\n") + setMkv("AudioDeviceInfo", "AudioDeviceInfo", sb.toString()) + } + + @SuppressLint("HardwareIds") + fun setPhoneInfo() { + setMkv("simCountryIso","Country Iso",telephonyManager.simCountryIso.toUpperCase(Locale.ENGLISH)) + setMkv("NetworkOperatorName","NetworkOperatorName",telephonyManager.networkOperatorName) + setMkv("NetworkOperator","NetworkOperator",telephonyManager.networkOperator) + var manufacturerCode = "" + if (!telephonyManager.manufacturerCode.isNullOrEmpty()) { + manufacturerCode = telephonyManager.manufacturerCode.toString() + } + setMkv("ManufacturerCode","ManufacturerCode",manufacturerCode) + try { + setMkv("tel_deviceId","Telephony DeviceId",telephonyManager.getDeviceId()) + }catch (e:Throwable) { + e.printStackTrace() + } + + } + + fun checkPermission(key:String):Boolean { + return this.context.packageManager.checkPermission(key,this.context.packageName) == PackageManager.PERMISSION_GRANTED + } + + fun GetAppInfo() : AppInfo { + setAppInfo() + setFsLm() + setPermissionInfo() + setSystem() + setMem() + setNetworkInfo() + setBuildInfo() + setFont() + setLocal() + setScreen() + setDisk() + setPhoneInfo() + setAudio() + setBatteryInfo() + setSensor() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) >= 4) { + setAD_SERVICES() + } + initAdid() + return this + } + + @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4) + fun setAD_SERVICES() { + val v = AdServicesState.isAdServicesStateEnabled() + setMkv("isAdServicesStateEnabled", "Android Ad Services",v ) + } + + fun initAdid() { + setMkv("adid", "Ad Id", "") + Executors.newSingleThreadExecutor().execute { + try { + val adid = AdvertisingIdClient(this.context).info + setMkv("adid", "Ad Id", adid.id?:"") + initList() + + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfoItem.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfoItem.kt new file mode 100644 index 0000000..90a1088 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/AppInfoItem.kt @@ -0,0 +1,5 @@ +package com.xyzshell.myandriodinfo.ui.home + +class AppInfoItem(val name:String, val v: Any) { + var desc: String = "属性值:${v}" +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/BuildProp.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/BuildProp.kt new file mode 100644 index 0000000..035e088 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/BuildProp.kt @@ -0,0 +1,93 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.os.Build +import android.util.ArraySet +import com.xyzshell.myandriodinfo.service.HttpSender + +import org.json.JSONArray +import org.json.JSONObject + +class BuildProp { + + val kv = mutableMapOf() + val js_build = JSONObject() + val js_ver = JSONObject() + val js_verc = JSONObject() + + private fun call(name:String, obj: Any, js: JSONObject) { + if (obj is Array<*>) { + val jarr = JSONArray() + for (item in obj) { + if (item != null) { + jarr.put(item) + } else { + jarr.put("") + } + } + kv[name] = jarr.toString() + js.put(name, jarr) + + } else { + var v = "" + v = obj.toString() + kv[name] = v + + if(obj is ArraySet<*>) { + val tjs = JSONObject() + tjs.put("type", obj.javaClass.name) + val jarr = JSONArray() + for (item in obj) { + if (item != null) { + jarr.put(item) + } else { + jarr.put("") + } + } + tjs.put("val", jarr) + js.put(name, tjs) + } else { + js.put(name, obj) + } + + } + } + + fun getInfo() : BuildProp { + val buildCls = Build::class.java + val fi = buildCls.declaredFields + for (it in fi) { + val obj = it.get(null) + call(it.name, obj, js_build) + + } + + val buildVerCLs = Build.VERSION::class.java + val vfi = buildVerCLs.declaredFields + for (it in vfi) { + val obj =it.get(null) + call(it.name, obj, js_ver) + } + + val buildVerCode = Build.VERSION_CODES::class.java + val vcfi = buildVerCode.declaredFields + for (it in vcfi) { + val obj =it.get(null) + call(it.name, obj, js_verc) + } + val js = JSONObject() + js.put("BUILD", js_build) + js.put("BUILD.VERSION", js_ver) + js.put("BUILD.VERSION_CODES", js_ver) + try { + HttpSender().post("http://192.168.1.100:9999/devices/android", js) + }catch (e:Throwable) { + e.printStackTrace() + } + + return this + } + + private fun runOnUiThread(any: Any) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GpuInfo.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GpuInfo.kt new file mode 100644 index 0000000..d216e59 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GpuInfo.kt @@ -0,0 +1,26 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.opengl.GLES10 +import android.opengl.GLES10Ext +import android.opengl.GLES20 +import android.opengl.GLES30 +import android.opengl.GLES32 +import com.xyzshell.myandriodinfo.service.HttpSender +import org.json.JSONObject + +class GpuInfo { + fun getInfo() { + //GLES10.glGetString(GLES10.GL_VENDOR) + val gl_vendor = GLES20.glGetString(GLES20.GL_VENDOR) + val gl_version = GLES20.glGetString(GLES20.GL_VERSION) + val gl_renderer = GLES20.glGetString(GLES20.GL_RENDERER) + val gl_extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS) + + val js = JSONObject() + js.put("GL_VENDOR", gl_vendor) + js.put("GL_VERSION", gl_version) + js.put("GL_RENDERER", gl_renderer) + js.put("GL_EXTENSIONS", gl_extensions) + HttpSender().post("http://192.168.1.100:9999/devices/android", js) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GroupInfo.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GroupInfo.kt new file mode 100644 index 0000000..81f8bc9 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/GroupInfo.kt @@ -0,0 +1,40 @@ +package com.xyzshell.myandriodinfo.ui.home + +class GroupInfo { + private val groups: MutableMap = mutableMapOf() + + private val groupKeys get() = groups.keys.toList() + private var nextId = 1L + + val size get() = groups.size + + fun getGroup(position: Int) : Group { + val key = groupKeys[position] + return groups[key]!! + } + + fun set(groupName: String, key:String, name: String, value: Any) { + var group = groups[groupName] + if (group == null) { + group = Group(nextId++, groupName, "") + groups[groupName] = group + } + group.addItem(key, AppInfoItem(name, value)) + } + + class Group(val id: Long, var name: String, var desc: String) { + private val items: MutableMap = mutableMapOf() + private val keys get() = items.keys.toList() + + val size get() = items.size + + fun get(position: Int) : AppInfoItem { + val key = keys[position] + return items[key] ?: AppInfoItem("", "") + } + + fun addItem(key: String, item: AppInfoItem) { + items[key] = item + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeFragment.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeFragment.kt new file mode 100644 index 0000000..7577138 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeFragment.kt @@ -0,0 +1,41 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ExpandableListView +import android.widget.ListView +import androidx.fragment.app.Fragment +import com.xyzshell.myandriodinfo.databinding.FragmentHomeBinding + +class HomeFragment : Fragment() { + + private var _binding: FragmentHomeBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + + + _binding = FragmentHomeBinding.inflate(inflater, container, false) + val root: View = binding.root + + val listView: ExpandableListView = binding.infoList + + context?.let { it1 -> AppInfo(it1, listView).GetAppInfo() }?.initList() + + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeViewModel.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeViewModel.kt new file mode 100644 index 0000000..5302af9 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/HomeViewModel.kt @@ -0,0 +1,13 @@ +package com.xyzshell.myandriodinfo.ui.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class HomeViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is home Fragment" + } + val text: LiveData = _text +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/MyListViewAdapter.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/MyListViewAdapter.kt new file mode 100644 index 0000000..6edcc65 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/MyListViewAdapter.kt @@ -0,0 +1,99 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseExpandableListAdapter +import android.widget.TextView +import com.xyzshell.myandriodinfo.R + +class MyListViewAdapter(context: Context, private val data: GroupInfo) : BaseExpandableListAdapter() { + private val inflater:LayoutInflater = LayoutInflater.from(context) + + + class ViewHolder() { + lateinit var titleTextView: TextView + lateinit var descriptionTextView: TextView + } + + override fun getGroupCount(): Int { + return data.size + } + + override fun getChildrenCount(groupPosition: Int): Int { + return data.getGroup(groupPosition).size + } + + override fun getGroup(groupPosition: Int): Any { + return data.getGroup(groupPosition) + } + + override fun getChild(groupPosition: Int, childPosition: Int): Any { + return data.getGroup(groupPosition).get(childPosition) + } + + override fun getGroupId(groupPosition: Int): Long { + return groupPosition.toLong() + } + + override fun getChildId(groupPosition: Int, childPosition: Int): Long { + return groupPosition * 1000 + childPosition.toLong() + } + + override fun hasStableIds(): Boolean { + return false + } + + override fun getGroupView( + groupPosition: Int, + isExpanded: Boolean, + convertView: View?, + parent: ViewGroup? + ): View { + //1.item view + + val v = inflater.inflate( + android.R.layout.simple_expandable_list_item_1, parent, false) as TextView + + //2.item data + + val group = this.getGroup(groupPosition) as GroupInfo.Group + + //3.set item data add to item view + + v.text = group.name; + + return v + } + + override fun getChildView( + groupPosition: Int, + childPosition: Int, + isLastChild: Boolean, + convertView: View?, + parent: ViewGroup? + ): View? { + val holder: ViewHolder + var ctv: View? = convertView + if (ctv == null) { + ctv = inflater.inflate(R.layout.list_view_item, parent, false); + holder = ViewHolder() + holder.titleTextView = ctv.findViewById(R.id.titleTextView); + holder.descriptionTextView = ctv.findViewById(R.id.descriptionTextView); + ctv.tag = holder + } else { + holder = ctv.tag as ViewHolder + } + val item: AppInfoItem = this.getChild(groupPosition, childPosition) as AppInfoItem + holder.titleTextView.text = item.name + holder.descriptionTextView.text = item.desc + + return ctv; + } + + override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean { + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SensorEventData.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SensorEventData.kt new file mode 100644 index 0000000..7a97ff7 --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SensorEventData.kt @@ -0,0 +1,15 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener + +class SensorEventData: SensorEventListener { + override fun onSensorChanged(p0: SensorEvent?) { + TODO("Not yet implemented") + } + + override fun onAccuracyChanged(p0: Sensor?, p1: Int) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SystemProp.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SystemProp.kt new file mode 100644 index 0000000..211429c --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/home/SystemProp.kt @@ -0,0 +1,154 @@ +package com.xyzshell.myandriodinfo.ui.home + +import android.util.ArraySet +import com.xyzshell.myandriodinfo.service.HttpSender +import org.json.JSONArray +import org.json.JSONObject + + +class SystemProp { + private fun call(name:String, obj: Any, js: JSONObject) { + if (obj is Array<*>) { + val jarr = JSONArray() + for (item in obj) { + if (item != null) { + jarr.put(item) + } else { + jarr.put("") + } + } + kv[name] = jarr.toString() + js.put(name, jarr) + + } else { + var v = "" + v = obj.toString() + kv[name] = v + + if(obj is ArraySet<*>) { + val tjs = JSONObject() + tjs.put("type", obj.javaClass.name) + val jarr = JSONArray() + for (item in obj) { + if (item != null) { + jarr.put(item) + } else { + jarr.put("") + } + } + tjs.put("val", jarr) + js.put(name, tjs) + } else { + js.put(name, obj) + } + + } + } + private val keys = listOf( + "ro.product.model", + "ro.product.name", + "ro.product.device", + "ro.product.board", + "ro.product.manufacturer", + "ro.bootloader", + "ro.build.product", + "ro.product.brand", + "ro.build.fingerprint", + "ro.build.description", + "gsm.version.baseband", + "ro.csc.active", + "ro.knox.warranty", + "ro.product.mfg_date", + "ro.product.code", + "drm.service.enabled", + "ro.vendor.mtk_widevine_drm_l1_support", + "ro.vendor.mtk_widevine_drm_l3_support", + "ro.serialno", + "ro.boot.serialno", + "gsf.id", + "ro.gms.version", + "ro.build.id", + "ro.build.version.release", + "ro.build.version.sdk", + "ro.build.version.security_patch", + "ro.kernel.version", + "ro.csc.country_code", + "ro.csc.sales_code", + "ro.csc.countryiso_code", + "ro.product.model.full", + "ro.product.model_code", + "ro.product.full_name", + "ril.product_code", + "ril.official_cscver", + "ro.csc.omcnw_code", + "ro.csc.omcnw_code2", + "ro.hardware", + "ro.product.cpu.abi", + "ro.product.cpu.abilist", + "ro.product.cpu.abilist64", + "ro.product.cpu.abilist32", + "ro.treble.enabled", + "ro.debuggable", + "ro.secure", + "ro.build.type", + "ro.build.tags", + "ro.build.date.utc", + "ro.sf.lcd_density", + "ro.sf.physical_density", + "vendor.display.lcd_density", + "qemu.sf.lcd_density", + "ro.display.max_brightness", + "vendor.display.brightness_max", + "ro.vendor.display.brightness_max", + "vendor.display.hdr_support", + "ro.vendor.display.hdr10_support", + "vendor.display.hdr10plus_support", + "vendor.display.hlg_support", + "vendor.display.dolby_vision_support", + "ro.surface_flinger.refresh_rate_switching", + "vendor.display.refresh_rate_switching", + "ro.vendor.display.refresh_rates", + "vendor.display.supported_refresh_rates", + "vendor.display.wide_color_support", + "ro.vendor.display.wcg_support", + "vendor.display.color_gamut", + "vendor.display.p3_support", + "ro.vendor.display.p3_support", + "ro.surface_flinger.has_wide_color_display", + "ro.surface_flinger.wcg_composition_dataspace", + "ro.surface_flinger.use_color_management", + "ro.vendor.display.peak_brightness", + "ro.product.cpu.abi", + "ro.product.cpu.abilist", + "ro.product.cpu.abilist64", + "ro.product.cpu.abilist32", + "ro.chipname", + "ro.board.platform", + "ro.hardware", + "ro.boot.ddr_type" + ) + + private val mkv = mutableMapOf() + + val kv get() = mkv + + fun getInfo(): SystemProp { + val cls = Class.forName("android.os.SystemProperties") + val method = cls.getMethod("get", String::class.java) + val js = JSONObject() + keys.forEach { k -> + method.invoke(null, k)?.let { + call(k, it, js) + } + } + try { + HttpSender().post("http://192.168.1.100:9999/devices/android", js) + }catch (e:Throwable) { + e.printStackTrace() + } + + return this + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsFragment.kt new file mode 100644 index 0000000..e25be0b --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsFragment.kt @@ -0,0 +1,42 @@ +package com.xyzshell.myandriodinfo.ui.notifications + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.xyzshell.myandriodinfo.databinding.FragmentNotificationsBinding + +class NotificationsFragment : Fragment() { + + private var _binding: FragmentNotificationsBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val notificationsViewModel = + ViewModelProvider(this).get(NotificationsViewModel::class.java) + + _binding = FragmentNotificationsBinding.inflate(inflater, container, false) + val root: View = binding.root + + val textView: TextView = binding.textNotifications + notificationsViewModel.text.observe(viewLifecycleOwner) { + textView.text = it + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsViewModel.kt b/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsViewModel.kt new file mode 100644 index 0000000..544f11c --- /dev/null +++ b/app/src/main/java/com/xyzshell/myandriodinfo/ui/notifications/NotificationsViewModel.kt @@ -0,0 +1,13 @@ +package com.xyzshell.myandriodinfo.ui.notifications + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class NotificationsViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is notifications Fragment" + } + val text: LiveData = _text +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 0000000..46fc8de --- /dev/null +++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 0000000..f8bb0b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + 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/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..78b75c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + 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..f683555 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml new file mode 100644 index 0000000..166ab0e --- /dev/null +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..971aa33 --- /dev/null +++ b/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml new file mode 100644 index 0000000..d417935 --- /dev/null +++ b/app/src/main/res/layout/fragment_notifications.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_view_item.xml b/app/src/main/res/layout/list_view_item.xml new file mode 100644 index 0000000..70301fa --- /dev/null +++ b/app/src/main/res/layout/list_view_item.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..fb6d040 --- /dev/null +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml new file mode 100644 index 0000000..7e8220b --- /dev/null +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..e6d1d57 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..e00c2dd --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..46c28a6 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + MyAndriodInfo + 信息列表 + Dashboard + Notifications + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..f76a2e9 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..eed53e4 --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,8 @@ + + + + 192.168.1.100 + 10.0.2.2 + localhost + + \ No newline at end of file diff --git a/app/src/test/java/com/xyzshell/myandriodinfo/ExampleUnitTest.kt b/app/src/test/java/com/xyzshell/myandriodinfo/ExampleUnitTest.kt new file mode 100644 index 0000000..ca83e64 --- /dev/null +++ b/app/src/test/java/com/xyzshell/myandriodinfo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.xyzshell.myandriodinfo + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..33c46f6 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,8 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.jetbrains.kotlin.jvm) apply false + alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.android.library) apply false +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..f99d723 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,101 @@ +[versions] +accompanistSystemuicontroller = "0.36.0" +activityCompose = "1.10.1" +adaptive = "1.1.0" +agp = "8.6.1" +apiVersion = "82" +datastore = "1.1.7" +datastorePreferences = "1.1.7" +googleSymbolProcessingApi = "2.0.0-1.0.24" +gson = "2.13.1" +jsonVersion = "20250517" +kotlin = "2.0.0" +coreKtx = "1.16.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +appcompat = "1.7.1" +kotlinpoet = "1.15.3" +kotlinpoetKsp = "1.15.3" +kotlinxSerializationJson = "1.6.2" +lifecycleViewmodelCompose = "2.9.2" +material = "1.12.0" +constraintlayout = "2.2.1" +lifecycleLivedataKtx = "2.9.2" +lifecycleViewmodelKtx = "2.9.2" +navigationFragmentKtx = "2.9.3" +navigationUiKtx = "2.9.3" +protobufJava = "4.29.0" +squareupOkhttp = "4.12.0" +webkit = "1.14.0" +playServicesAppset = "16.1.0" +playServicesAdsIdentifier = "18.2.0" +jetbrainsKotlinJvm = "2.0.0" +runtimeAndroid = "1.8.3" +uiToolingPreviewAndroid = "1.8.3" +material3Android = "1.3.2" +lifecycleRuntimeKtx = "2.9.2" +composeBom = "2024.04.01" +koin = "4.1.0" + +[libraries] +accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" } +adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "adaptive" } +androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } +androidx-adaptive = { module = "androidx.compose.material3.adaptive:adaptive" } +androidx-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout" } +androidx-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation" } +androidx-compose-material3-adaptive-adaptive = { module = "androidx.compose.material3.adaptive:adaptive" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } +androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } +androidx-foundation = { module = "androidx.compose.foundation:foundation" } +androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" } +androidx-material-icons-core = { module = "androidx.compose.material:material-icons-core" } +androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } +androidx-material3 = { module = "androidx.compose.material3:material3" } +androidx-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata" } +androidx-runtime-rxjava2 = { module = "androidx.compose.runtime:runtime-rxjava2" } +androidx-ui = { module = "androidx.compose.ui:ui" } +androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } +androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } +google-symbol-processing-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "googleSymbolProcessingApi" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +json-json = { module = "org.json:json", version.ref = "jsonVersion" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoetKsp" } +kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } +koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } +androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" } +androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } +androidx-webkit = { group = "androidx.webkit", name = "webkit", version.ref = "webkit" } +play-services-appset = { group = "com.google.android.gms", name = "play-services-appset", version.ref = "playServicesAppset" } +play-services-ads-identifier = { group = "com.google.android.gms", name = "play-services-ads-identifier", version.ref = "playServicesAdsIdentifier" } +protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobufJava" } +squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "squareupOkhttp" } +androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" } +androidx-ui-tooling-preview-android = { group = "androidx.compose.ui", name = "ui-tooling-preview-android", version.ref = "uiToolingPreviewAndroid" } +androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" } +xposed-api = { module = "de.robv.android.xposed:api", version.ref = "apiVersion" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +android-library = { id = "com.android.library", version.ref = "agp" } + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a233444 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Aug 04 16:31:54 CST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ksp-annotations/.gitignore b/ksp-annotations/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/ksp-annotations/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/ksp-annotations/build.gradle b/ksp-annotations/build.gradle new file mode 100644 index 0000000..2af7bd8 --- /dev/null +++ b/ksp-annotations/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} \ No newline at end of file diff --git a/ksp-annotations/src/main/java/com/xyzshell/ksp_annotations/AutoBuilder.kt b/ksp-annotations/src/main/java/com/xyzshell/ksp_annotations/AutoBuilder.kt new file mode 100644 index 0000000..fee85a0 --- /dev/null +++ b/ksp-annotations/src/main/java/com/xyzshell/ksp_annotations/AutoBuilder.kt @@ -0,0 +1,5 @@ +package com.xyzshell.ksp_annotations + +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.SOURCE) +annotation class AutoBuilder \ No newline at end of file diff --git a/ksp-processor/.gitignore b/ksp-processor/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/ksp-processor/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/ksp-processor/build.gradle b/ksp-processor/build.gradle new file mode 100644 index 0000000..e66f121 --- /dev/null +++ b/ksp-processor/build.gradle @@ -0,0 +1,21 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + implementation project(':ksp-annotations') + implementation libs.google.symbol.processing.api + implementation libs.kotlinpoet + implementation libs.kotlinpoet.ksp +} \ No newline at end of file diff --git a/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessor.kt b/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessor.kt new file mode 100644 index 0000000..9a4cd82 --- /dev/null +++ b/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessor.kt @@ -0,0 +1,118 @@ +package com.xyzshell.ksp_processor + +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.* +import com.google.devtools.ksp.validate +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.ksp.writeTo +import com.xyzshell.ksp_annotations.AutoBuilder + +class AutoBuilderProcessor( + private val codeGenerator: CodeGenerator, + private val logger: KSPLogger +) : SymbolProcessor { + + override fun process(resolver: Resolver): List { + val symbols = resolver.getSymbolsWithAnnotation(AutoBuilder::class.qualifiedName!!) + val ret = symbols.filter { !it.validate() }.toList() + + symbols + .filter { it is KSClassDeclaration && it.validate() } + .forEach { it -> + generateBuilderClass(it as KSClassDeclaration) + } + + return ret + } + + private fun generateBuilderClass(classDeclaration: KSClassDeclaration) { + val packageName = classDeclaration.containingFile!!.packageName.asString() + val className = classDeclaration.simpleName.asString() + val builderClassName = "${className}Builder" + + logger.info("Generating builder for $className") + + // 获取类的构造函数参数 + val constructor = classDeclaration.primaryConstructor + if (constructor == null) { + logger.error("Class $className must have a primary constructor", classDeclaration) + return + } + + val properties = constructor.parameters + + // 创建Builder类 + val builderClass = TypeSpec.classBuilder(builderClassName) + .addKdoc("Auto-generated builder for %L", className) + + // 添加属性字段 + properties.forEach { param -> + val paramName = param.name!!.asString() + val paramType = param.type.resolve() + val typeName = paramType.toClassName() + + builderClass.addProperty( + PropertySpec.builder(paramName, typeName.copy(nullable = true)) + .mutable() + .initializer("null") + .addModifiers(KModifier.PRIVATE) + .build() + ) + } + + // 添加setter方法 + properties.forEach { param -> + val paramName = param.name!!.asString() + val paramType = param.type.resolve() + val typeName = paramType.toClassName() + + val setterMethod = FunSpec.builder(paramName) + .addParameter(paramName, typeName) + .returns(ClassName(packageName, builderClassName)) + .addStatement("this.%L = %L", paramName, paramName) + .addStatement("return this") + .build() + + builderClass.addFunction(setterMethod) + } + + // 添加build方法 + val buildMethod = FunSpec.builder("build") + .returns(ClassName(packageName, className)) + .apply { + val paramNames = properties.map { it.name!!.asString() } + val paramChecks = paramNames.map { paramName -> + "checkNotNull($paramName) { \"$paramName must be set\" }" + } + + addStatement( + "return %T(%L)", + ClassName(packageName, className), + paramChecks.joinToString(", ") + ) + } + .build() + + builderClass.addFunction(buildMethod) + + // 添加静态工厂方法 + val companionObject = TypeSpec.companionObjectBuilder() + .addFunction( + FunSpec.builder("builder") + .returns(ClassName(packageName, builderClassName)) + .addStatement("return %T()", ClassName(packageName, builderClassName)) + .build() + ) + .build() + + builderClass.addType(companionObject) + + // 生成文件 + val file = FileSpec.builder(packageName, builderClassName) + .addType(builderClass.build()) + .build() + + file.writeTo(codeGenerator, Dependencies(true, classDeclaration.containingFile!!)) + } +} \ No newline at end of file diff --git a/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessorProvider.kt b/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessorProvider.kt new file mode 100644 index 0000000..bda4c68 --- /dev/null +++ b/ksp-processor/src/main/java/com/xyzshell/ksp_processor/AutoBuilderProcessorProvider.kt @@ -0,0 +1,14 @@ +package com.xyzshell.ksp_processor + +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +class AutoBuilderProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + return AutoBuilderProcessor( + codeGenerator = environment.codeGenerator, + logger = environment.logger + ) + } +} \ No newline at end of file diff --git a/ksp-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/ksp-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 0000000..0944169 --- /dev/null +++ b/ksp-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +com.xyzshell.ksp_processor.AutoBuilderProcessorProvider \ No newline at end of file diff --git a/mydev/.gitignore b/mydev/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/mydev/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/mydev/build.gradle.kts b/mydev/build.gradle.kts new file mode 100644 index 0000000..d3d1207 --- /dev/null +++ b/mydev/build.gradle.kts @@ -0,0 +1,82 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) +} + +android { + namespace = "com.xyzshell.mydev" + compileSdk = 35 + + defaultConfig { + applicationId = "com.xyzshell.mydev" + minSdk = 29 + //noinspection OldTargetApi + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + 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 { + compose = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.runtime.android) + implementation(libs.androidx.ui.tooling.preview.android) + implementation(libs.androidx.ui) + implementation(libs.androidx.foundation) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3.android) + implementation(libs.adaptive) + implementation(libs.androidx.adaptive.layout) + implementation(libs.androidx.adaptive.navigation) + implementation(libs.play.services.ads.identifier) + implementation(libs.play.services.appset) + implementation(libs.kotlinx.serialization.json) + implementation(libs.accompanist.systemuicontroller) + implementation(libs.protobuf.java) + debugImplementation(libs.androidx.ui.tooling) + testImplementation(libs.junit) + + implementation(libs.androidx.material.icons.core) + // Optional - Add full set of material icons + implementation(libs.androidx.material.icons.extended) + // Optional - Add window size utils + implementation(libs.androidx.adaptive) + + // Optional - Integration with activities + implementation(libs.androidx.activity.compose) + // Optional - Integration with ViewModels + implementation(libs.androidx.lifecycle.viewmodel.compose) + // Optional - Integration with LiveData + implementation(libs.androidx.runtime.livedata) + // Optional - Integration with RxJava + implementation(libs.androidx.runtime.rxjava2) + + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/mydev/proguard-rules.pro b/mydev/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/mydev/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/mydev/src/androidTest/java/com/xyzshell/mydev/ExampleInstrumentedTest.kt b/mydev/src/androidTest/java/com/xyzshell/mydev/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..975f002 --- /dev/null +++ b/mydev/src/androidTest/java/com/xyzshell/mydev/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.xyzshell.mydev + +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.xyzshell.mydev", appContext.packageName) + } +} \ No newline at end of file diff --git a/mydev/src/main/AndroidManifest.xml b/mydev/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2105549 --- /dev/null +++ b/mydev/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/Info.kt b/mydev/src/main/java/com/xyzshell/mydev/Info.kt new file mode 100644 index 0000000..c03aeaa --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/Info.kt @@ -0,0 +1,9 @@ +package com.xyzshell.mydev + +// 数据类 +typealias Callback = () -> String +data class InfoItem( + val propertyName: String, + val propertyValue: String, + val callback: Callback? = null +) diff --git a/mydev/src/main/java/com/xyzshell/mydev/InfoData.kt b/mydev/src/main/java/com/xyzshell/mydev/InfoData.kt new file mode 100644 index 0000000..1c72cbb --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/InfoData.kt @@ -0,0 +1,450 @@ +package com.xyzshell.mydev + +import android.adservices.AdServicesState +import android.annotation.SuppressLint +import android.app.ActivityManager +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.res.Configuration +import android.graphics.Rect +import android.hardware.Sensor +import android.hardware.SensorManager +import android.media.AudioManager +import android.net.ConnectivityManager +import android.os.Build +import android.os.Environment +import android.os.PowerManager +import android.os.Process +import android.os.SystemClock +import android.os.ext.SdkExtensions +import android.provider.Settings +import android.telephony.TelephonyManager +import android.util.DisplayMetrics +import android.view.RoundedCorner +import android.view.WindowManager +import androidx.annotation.RequiresExtension +import com.google.android.gms.ads.identifier.AdvertisingIdClient +import com.google.android.gms.appset.AppSet +import com.google.android.gms.appset.AppSetIdClient +import com.google.android.gms.appset.AppSetIdInfo +import com.google.android.gms.tasks.Task +import com.xyzshell.mydev.data.SystemPropKeys +import com.xyzshell.mydev.utils.DeviceInfo +import com.xyzshell.mydev.utils.MemoryInfoType +import java.io.BufferedReader +import java.io.File +import java.io.IOException +import java.io.InputStreamReader +import java.net.NetworkInterface +import java.util.Date +import java.util.Locale +import java.util.TimeZone +import java.util.concurrent.Executors + + +class InfoData(private val context:Context) { + + private val activityManager: ActivityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + private val connectivityManager = this.context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + private val packageManager: PackageManager = this.context.packageManager + private val applicationInfo: ApplicationInfo = this.context.applicationInfo + private val audioManager: AudioManager = this.context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + + private val windowManager = this.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + private val telephonyManager = this.context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + private val packageInfo: PackageInfo = + this.packageManager.getPackageInfo(this.context.packageName,0) + private val powerManager = this.context.getSystemService(Context.POWER_SERVICE) as PowerManager + + private fun getStr(obj: Any) : String { + var info = "" + if(obj!=null) { + info = if (obj is Array<*>) { + obj.joinToString(",") + } else { + obj.toString() + } + } + return info + } + fun getInfo(): List { + val cls = Class.forName("android.os.SystemProperties") + val method = cls.getMethod("get", String::class.java) + val infos = mutableListOf() + SystemPropKeys.forEach { k -> + method.invoke(null, k)?.let { + infos.add(InfoItem(k, getStr(it))) + } + } + + return infos + } + + fun getPropInfo(): List { + val reg = Regex("^\\[(.+)].+\\[(.+)]$") + val res = mutableListOf() + try { + val process: java.lang.Process? = Runtime.getRuntime().exec("getprop") + if(process!=null) { + val reader = BufferedReader(InputStreamReader(process.inputStream)) + var line: String? + while ((reader.readLine().also { line = it }) != null) { + val a = reg.find(line!!)?.groupValues + if(a!=null && a.size == 3) { + res.add(InfoItem(a[1], a[2])) + } + } + } + } catch (e: IOException) { + e.printStackTrace() + } + return res + } + + private val allInfos = mutableMapOf() + private fun setMkv(k: String, name: String, value: Any) { + allInfos[k] = InfoItem(name, value.toString()) + } + + fun setAppInfo() { + val v = packageManager.getApplicationLabel(applicationInfo) + var install_name = packageManager.getInstallerPackageName(applicationInfo.packageName) + if(install_name == null) { + install_name = "" + } + setMkv("app_name", "App Name", v) + setMkv("install_name", "install name", install_name) + this.packageInfo.versionName?.let { setMkv("app_version", "Version Name", it) } + setMkv("app_version_code", "Version Code", this.packageInfo.versionCode) + setMkv("firstInstallTime", "安装时间", this.packageInfo.firstInstallTime) + setMkv("package_name", "Package Name", applicationInfo.packageName) + setMkv("target_sdk", "Target SDK", applicationInfo.targetSdkVersion) + setMkv("idfv", "idfv", "") + setMkv("idfv_scope", "idfv scope", -1) + + } + + private fun setFsLm() { + val v = File(applicationInfo.sourceDir).lastModified() + setMkv("fslm", "app安装文件时间", v) + } + + fun setPermissionInfo() { + val ps_tpg = checkPermission("android.permission.ACCESS_ADSERVICES_TOPICS") + setMkv("ps_tpg","允许应用访问用户的兴趣话题信息", ps_tpg) + val ps_apg = checkPermission("android.permission.ACCESS_ADSERVICES_ATTRIBUTION") + setMkv("ps_apg", "广告归因追踪", ps_apg) + var ps_aipg = checkPermission("android.permission.ACCESS_ADSERVICES_AD_ID") + setMkv("ps_aipg", "广告ID访问", ps_aipg) + val ps_capg = checkPermission("android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE") + setMkv("ps_capg", "允许应用创建和管理自定义广告受众群体",ps_capg) + } + + fun setNetworkInfo() { + setMkv("connectivity", "网络状态", + connectivityManager.restrictBackgroundStatus != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED) + val sb = StringBuilder() + val interfaces = NetworkInterface.getNetworkInterfaces() + if (interfaces != null) { + for (intf in interfaces) { + try { + if (!intf.isUp || intf.isLoopback) continue + sb.append("name: ${intf.name}, displayName: ${intf.displayName},") + val addresses = intf.inetAddresses + for (addr in addresses) { + sb.append("address: ${addr.hostAddress}\n") + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + setMkv("NetworkInterface", "网络状态", sb.toString()) + } + + + fun setFont() { + setMkv("font_scale", "Font Scale", Settings.System.getFloat(this.context.contentResolver,"font_scale")) + + } + + fun setLocal() { + setMkv("tz", "TimeZone", + Math.round(TimeZone.getDefault().getOffset(Date().time) * 10.0 / 3600000.0) / 10.0) + setMkv("tz_offset", "tz_offset",Math.round( + TimeZone.getDefault().getOffset( + Date().time + ) * 10.0 / 3600000.0 + ) / 10.0) + setMkv("local","local", Locale.getDefault().toString()) + val localeList = this.context.resources.configuration.locales + val stringBuilder = StringBuilder() + for (i in 0 until localeList.size()) { + val locale = localeList.get(i) + stringBuilder.append("Locale: ${locale.toString()}, Language: ${locale.language}, Country: ${locale.country}\n") + } + + setMkv("local_list", "Locale List", stringBuilder.toString()) + } + + fun setScreen() { + val screen_brightness = Settings.System.getInt(this.context.contentResolver, Settings.System.SCREEN_BRIGHTNESS) / 255.0F * 100.0F + setMkv("screen_brightness","屏幕亮度", screen_brightness) + setMkv("screen_orientation", "屏幕方向", this.context.resources.configuration.orientation) + + val rect = Rect() + windowManager.defaultDisplay.getRectSize(rect) + val displayMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(displayMetrics) + val sb = StringBuilder() + sb.append("w:${rect.width()},h:${rect.height()}\n") + sb.append("W:${displayMetrics.widthPixels},H: ${displayMetrics.heightPixels}\n") + sb.append("density:${displayMetrics.density}\n") + sb.append("densityDpi:${displayMetrics.densityDpi}\n") + sb.append("xdpi:${displayMetrics.xdpi},ydpi:${displayMetrics.ydpi}\n") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + sb.append("tl${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)}\n") + sb.append("tr${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT)}\n") + sb.append("bl${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT)}\n") + sb.append("br${windowManager.defaultDisplay.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT)}\n") + } + setMkv("screen", "屏幕", sb.toString()) + + } + + fun setDisk() { + setMkv("disk_free","磁盘剩余", Environment.getDataDirectory().freeSpace) + setMkv("disk_total", "磁盘", Environment.getDataDirectory().totalSpace) + } + + + fun getProcessName():String { + try { + val packageManager = context.packageManager + val applicationInfo = packageManager.getApplicationInfo( + context.packageName, + PackageManager.GET_META_DATA // 0x80 + ) + val metaData = applicationInfo.metaData + + try { + val processName = applicationInfo.processName + return processName + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + return "" + } + fun getProcessName1():String { + val pid = Process.myPid() + val activityManager = this.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val runningManager = activityManager.runningAppProcesses + runningManager?.forEach { + if(it.pid == pid) { + return it.processName + } + } + return "" + } + + fun setSystem() { + setMkv("pc", "Processors", Runtime.getRuntime().availableProcessors()) + setMkv("boot_ms","bt_ms", System.currentTimeMillis() - SystemClock.elapsedRealtime()) + setMkv("processName1", "Process Name", getProcessName()) + setMkv("processName2", "Process Name 1", getProcessName1()) + val b1 = packageManager.hasSystemFeature("com.google.android.play.feature.HPE_EXPERIENCE") + val b2 = packageManager.hasSystemFeature(PackageManager.FEATURE_PC) + val kb = this.context.resources.configuration.keyboard + var is_pc = true + if(kb != Configuration.KEYBOARD_QWERTY || (!b1 && !b2)) { + is_pc = false + } + setMkv("is_pc", "is pc", is_pc) + } + + fun setMem() { + val memoryInfo = ActivityManager.MemoryInfo() + activityManager.getMemoryInfo(memoryInfo) + val sb = StringBuilder() + setMkv("availMem", "可用内存", memoryInfo.availMem) + setMkv("totalMem", "总内存", memoryInfo.totalMem) + setMkv("threshold", "threshold", memoryInfo.threshold) + setMkv("lowMemory", "lowMemory", memoryInfo.lowMemory) + setMkv("GlEsVersion", "GlEsVersion", activityManager.deviceConfigurationInfo.glEsVersion) + + + } + + fun setSensor() { + val sensorManager = this.context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + val isGYROSCOPE = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null + setMkv("isGYROSCOPE","陀螺仪", isGYROSCOPE) + } + + + fun setBatteryInfo() { + val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) + val intent = this.context.registerReceiver(null, intentFilter) + var level = -1 + var scale = -1 + var adn = -1 + var status = -1 + if(intent!=null) { + level = intent.getIntExtra("level", -1) + setMkv("battery_level", "电池Level", level) + scale = intent.getIntExtra("scale", -1) + setMkv("battery_scale", "电池scale", scale) + if(level > 0 && scale > 0) { + adn = (((level.toFloat() / scale.toFloat()) * 100.0F).toInt()) + setMkv("battery_adn", "电池adn", adn) + } + status = intent.getIntExtra("status", -1) + setMkv("battery_status", "电池状态", status) + } + var plugged = false + if(intent != null) { + // stay_on_while_plugged_in + val plugged1:Int = intent.getIntExtra("plugged", -1) + if(plugged1 > 0) { + plugged = true + } + setMkv("battery_plugged", "电池充电", plugged) + } + setMkv("isPowerSaveMode", "Power Save Mode", powerManager.isPowerSaveMode) + // setMkv("sowpie","插电模式:sowpie", Settings.Global.getInt(this.context.contentResolver, "stay_on_while_plugged_in", -1) > 0) + } + + + fun setAudio() { + setMkv("MusicActive", "MusicActive", audioManager.isMusicActive) + setMkv("volume", "volume", audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) + setMkv("SpeakerphoneOn","SpeakerphoneOn", audioManager.isSpeakerphoneOn) + setMkv("ringerMode", "ringerMode", audioManager.ringerMode) + val sb = StringBuilder() + val arrayOfAudioDeviceInfo = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS) + for (i in arrayOfAudioDeviceInfo.indices) { + val audioDeviceInfo = arrayOfAudioDeviceInfo[i] + if (audioDeviceInfo != null) { + // 3,7,8 + // public static final int TYPE_BLUETOOTH_A2DP = 8; + // public static final int TYPE_BLUETOOTH_SCO = 7; + // public static final int TYPE_WIRED_HEADSET = 3; + sb.append("name: " + audioDeviceInfo.productName + ", type: " + audioDeviceInfo.type + "\n") + } + } + sb.append("isWiredHeadsetOn:${audioManager.isWiredHeadsetOn()}\n") + sb.append("isBluetoothScoOn:${audioManager.isBluetoothScoOn()}\n") + sb.append("isBluetoothA2dpOn:${audioManager.isBluetoothA2dpOn()}\n") + setMkv("AudioDeviceInfo", "AudioDeviceInfo", sb.toString()) + } + + @SuppressLint("HardwareIds") + fun setPhoneInfo() { + setMkv("simCountryIso","Country Iso",telephonyManager.simCountryIso.toUpperCase(Locale.ENGLISH)) + setMkv("NetworkOperatorName","NetworkOperatorName",telephonyManager.networkOperatorName) + setMkv("NetworkOperator","NetworkOperator",telephonyManager.networkOperator) + var manufacturerCode = "" + if (!telephonyManager.manufacturerCode.isNullOrEmpty()) { + manufacturerCode = telephonyManager.manufacturerCode.toString() + } + setMkv("ManufacturerCode","ManufacturerCode",manufacturerCode) + try { + // setMkv("tel_deviceId","Telephony DeviceId",telephonyManager.getDeviceId()) + }catch (e:Throwable) { + e.printStackTrace() + } + + } + + fun checkPermission(key:String):Boolean { + return this.context.packageManager.checkPermission(key,this.context.packageName) == PackageManager.PERMISSION_GRANTED + } + + fun GetAppInfo() { + setAppInfo() + setFsLm() + setPermissionInfo() + setSystem() + setMem() + setNetworkInfo() + setFont() + setLocal() + setScreen() + setDisk() + setPhoneInfo() + setAudio() + setBatteryInfo() + setSensor() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && SdkExtensions.getExtensionVersion( + SdkExtensions.AD_SERVICES) >= 4) { + setAD_SERVICES() + } + initAdid() + } + + val AllInfos get() = allInfos.values.toList() + + @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4) + fun setAD_SERVICES() { + val v = AdServicesState.isAdServicesStateEnabled() + setMkv("isAdServicesStateEnabled", "Android Ad Services",v ) + } + + fun initAdid() { + setMkv("adid", "Ad Id", "") + setMkv("ApiLevel", "ApiLevel", DeviceInfo.instance.ApiLevel) + setMkv("ApkDigest", "ApkDigest", DeviceInfo.instance.ApkDigest) + setMkv("ApkDigestSize", "ApkDigestSize", DeviceInfo.instance.ApkDigestSize) + setMkv("ApkDigestTimeout", "ApkDigestTimeout", DeviceInfo.instance.ApkDigestTimeout) + setMkv("TimeZone1", "TimeZone", TimeZone.getDefault().id) + DeviceInfo.instance.getMemoryInfo(MemoryInfoType.FREE_MEMORY) + } + + fun loadAsyncData(onUpdate: (List) -> Unit) { + DeviceInfo.instance.onAdInit { + allInfos["GAID"] = InfoItem("GAID",DeviceInfo.instance.AdvertisingTrackingId) + allInfos["LimitedAdTracking"] = InfoItem("LimitedAdTracking",DeviceInfo.instance.LimitedAdTracking.toString()) + onUpdate(allInfos.values.toList()) + } + Executors.newSingleThreadExecutor().execute { + try { + val adid = AdvertisingIdClient(this.context).info + if (adid.id != null) { + allInfos["adid"] = InfoItem("Ad Id", adid.id!!) + } + DeviceInfo.instance.getApkDigest() + setMkv("ApkDigest", "ApkDigest", DeviceInfo.instance.ApkDigest) + setMkv("ApkDigestSize", "ApkDigestSize", DeviceInfo.instance.ApkDigestSize) + setMkv("ApkDigestTimeout", "ApkDigestTimeout", DeviceInfo.instance.ApkDigestTimeout) + setMkv( "CertificateFingerprint", "CertificateFingerprint", DeviceInfo.instance.getCertificateFingerprint()) + setMkv( "connectionType", "connectionType", DeviceInfo.instance.getConnectionType()) + onUpdate(allInfos.values.toList()) + + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + } + val client = AppSet.getClient(this.context) as AppSetIdClient + val task: Task = client.appSetIdInfo as Task + task.addOnSuccessListener { + // Determine current scope of app set ID. + val scope: Int = it.scope + + // Read app set ID value, which uses version 4 of the + // universally unique identifier (UUID) format. + val id: String = it.id + allInfos["idfv"] = InfoItem("idfv", it.id) + allInfos["idfv_scope"] = InfoItem("idfv_scope", it.scope.toString()) + onUpdate(allInfos.values.toList()) + + } + } + +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/MainActivity.kt b/mydev/src/main/java/com/xyzshell/mydev/MainActivity.kt new file mode 100644 index 0000000..9317316 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/MainActivity.kt @@ -0,0 +1,294 @@ +package com.xyzshell.mydev + +import android.annotation.SuppressLint +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.view.ViewGroup +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.unit.times +import com.xyzshell.mydev.utils.DeviceInfo +import com.xyzshell.mydev.utils.ProtobufExtensionsKt + + +class MainActivity : ComponentActivity() { + private lateinit var infos:InfoData + @SuppressLint("QueryPermissionsNeeded") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val isAndroid15 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM //VANILLA_ICE_CREAM是35 + DeviceInfo.instance.init(this.applicationContext) + infos = InfoData(this.applicationContext) + val t = ProtobufExtensionsKt().fromBase64("EpoDEpcDfMK7VlzA4rkFO61o03LOZRMV3qg-q6xuwRLaqgLASA0AHNCtUXZcIPszSRkfJ2lql3TMcvAd4ug3C1Q_TsDU5R3jV_d4ms0pCu2e9xao_zX8StWgFqGpM2v_k7hWK3tmN8r3T9tPW0qgX4yPA6dsssCyaS8IggHTaijlVJZ4afGfgh9tcASLnmBoQY5ivNpkAUyLCEvMk4ZdQa7j4MqukZi82g6WmIqPLVaS-UEZXSVLuymI8cyT9aIHZQjeQVH8xqE_LbtGw5kl_jK7oo7W7abwh8qWvyubA1x0IILG1ArfMjdTc9jZDiLl0cTFy8PkiKhnyaE9sO8_vmyMWl4h6aW2ZwoTnPnwn24WROcqktXcCIk2X1ToLTOGxnL8cDD6AH7V25dLYt41GgttM-9DcQchxJ_fRJaDOJ0UtHXSAFnlQbEVs5yWD8CNbR2SzFW7AJnmrf4bRfLzThn4m_c28T3qUuBHkCKrXxOvE1K2fLWcaQ41i4OR8xrwEZr-iSgNrVqr2obs54cb7g0blXiIZIDRoAhD5sU=",true) + val t1 = ProtobufExtensionsKt().toUUID(t) + setContent { + MaterialTheme { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()) + .fillMaxWidth().statusBarsPadding().navigationBarsPadding(), + ) { + Spacer(modifier = Modifier.height(36.dp)) + Button({ + val uri = Uri.parse("https://uutool.cn/ua/") + val intent = Intent(Intent.ACTION_VIEW, uri) + //intent.setClass(this@MainActivity, ViewBrowseActivity::class.java) + //intent.setData(uri) + //intent.addCategory(Intent.CATEGORY_BROWSABLE) + //startActivity(intent) + //intent.setPackage("com.android.chrome") + //startActivity(intent) + startActivity(Intent.createChooser(intent, "选择浏览器")) + if (intent.resolveActivity(packageManager) != null) { + startActivity(intent) + } else { + // 如果没有浏览器应用可用,显示一个提示 + Log.i("App Info","没有可用的浏览器应用") + } + }) { Text("查看浏览器UserAgent") } + Row(Modifier.padding(10.dp)) { + TextField("", onValueChange = { + + }, Modifier.fillMaxWidth().padding(1.dp), placeholder = {Text("输入名称")}) + } + BaseInfo(infos) + Spacer(modifier = Modifier.height(6.dp)) + BuildInfo() + Spacer(modifier = Modifier.height(16.dp)) + BuildVerInfo() + Spacer(modifier = Modifier.height(6.dp)) + BuildVerCodiInfo() + Spacer(modifier = Modifier.height(6.dp)) + SystemPropInfo(infos) + } + } + } + } +} + + +@Composable +fun BaseInfo(infoData: InfoData) { + infoData.GetAppInfo() + var stateData by remember { mutableStateOf(infoData.AllInfos) } + // 模拟异步数据加载 + LaunchedEffect(Unit) { + infoData.loadAsyncData { updatedItems -> + stateData = updatedItems + } + } + InfoBox("基本信息", stateData) +} + +@Composable +fun SystemPropInfo(infoData: InfoData) { + val infos = infoData.getPropInfo() + InfoBox("System Properties", infos) +} + +@Composable +fun BuildInfo() { + val buildCls = Build::class.java + val fi = buildCls.declaredFields + val infos = mutableListOf() + for (it in fi) { + val obj = it.get(null) + val info = getStr(obj) + infos.add(InfoItem(it.name, info)) + } + InfoBox("Build Info", infos) + +} + +@Composable +fun BuildVerInfo() { + val buildVerCLs = Build.VERSION::class.java + val vfi = buildVerCLs.declaredFields + val infos = mutableListOf() + for (it in vfi) { + val obj =it.get(null) + val info = getStr(obj) + infos.add(InfoItem(it.name, info)) + } + InfoBox("Build Ver Info", infos) +} + +@Composable +fun BuildVerCodiInfo() { + val buildVerCode = Build.VERSION_CODES::class.java + val vcfi = buildVerCode.declaredFields + val infos = mutableListOf() + for (it in vcfi) { + val obj =it.get(null) + val info = getStr(obj) + infos.add(InfoItem(it.name, info)) + } + InfoBox("Build Ver Code Info", infos) +} + + +private fun getStr(obj: Any) : String { + var info = "" + if(obj!=null) { + info = if (obj is Array<*>) { + obj.joinToString(",") + } else { + obj.toString() + } + } + return info +} +@Composable +fun InfoBox(title:String,infoItems: List) { + Column { + Text(title, modifier = Modifier.padding(16.dp)) + HorizontalDivider(thickness = 2.dp) + InfoListScreen(infoItems) + } +} + +@Composable +fun InfoListScreen(infoItems: List) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + infoItems.forEach { item -> + BoxItem(item) + } + } +} + +@Composable +fun BoxItem(item: InfoItem) { + Card() { + AdaptiveInfoLayoutWithMeasure(item = item) + } +} + +// 如果你需要更精确的测量,可以使用这个版本 +@SuppressLint("UnusedBoxWithConstraintsScope") +@Composable +fun AdaptiveInfoLayoutWithMeasure(item: InfoItem) { + var useVerticalLayout by remember { mutableStateOf(false) } + + BoxWithConstraints { + val maxWidth = maxWidth + val density = LocalDensity.current + + // 简单的启发式判断:如果文本长度超过屏幕宽度的一半,使用垂直布局 + val textWidth = with(density) { + item.propertyValue.length * 8.dp // 大概估算每个字符8dp宽度 + } + + useVerticalLayout = textWidth > maxWidth * 0.6f || item.propertyValue.length > 20 + + if (useVerticalLayout) { + // 垂直布局 + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Text( + text = item.propertyName, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = item.propertyValue, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + lineHeight = 20.sp + ) + } + } else { + // 水平布局 + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = item.propertyName, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.weight(1f) + ) + + Spacer(modifier = Modifier.width(16.dp)) + + Text( + text = item.propertyValue, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.weight(2f), + textAlign = TextAlign.End, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + } +} + + + +// 预览 +@Preview(showBackground = true) +@Composable +fun InfoListPreview() { + MaterialTheme { + // InfoListScreen() + } +} + diff --git a/mydev/src/main/java/com/xyzshell/mydev/ViewBrowseActivity.kt b/mydev/src/main/java/com/xyzshell/mydev/ViewBrowseActivity.kt new file mode 100644 index 0000000..eb50eb4 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/ViewBrowseActivity.kt @@ -0,0 +1,10 @@ +package com.xyzshell.mydev + +import android.os.Bundle +import androidx.activity.ComponentActivity + +class ViewBrowseActivity: ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/ViewDataItem.kt b/mydev/src/main/java/com/xyzshell/mydev/ViewDataItem.kt new file mode 100644 index 0000000..9c62d47 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/ViewDataItem.kt @@ -0,0 +1,7 @@ +package com.xyzshell.mydev + +class ViewDataItem { + val name: String = "" + val value: String = "" + +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/biz/CollectData.kt b/mydev/src/main/java/com/xyzshell/mydev/biz/CollectData.kt new file mode 100644 index 0000000..cfe980d --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/biz/CollectData.kt @@ -0,0 +1,11 @@ +package com.xyzshell.mydev.biz + +import android.os.Build + + +class CollectData { + private val buildId: String get() = Build.ID + private val model: String get() = Build.MODEL + private val device: String get() = Build.DEVICE + +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/data/AndroidInfo.kt b/mydev/src/main/java/com/xyzshell/mydev/data/AndroidInfo.kt new file mode 100644 index 0000000..c767069 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/data/AndroidInfo.kt @@ -0,0 +1,184 @@ +package com.xyzshell.mydev.data + +data class AndroidInfo( + val id: String, + val device:DeviceInfo, + val system: SystemInfo +) + +class DeviceInfo { + /** + * 设备型号 + */ + val model: String = "" + + // '产品名称'") + val product: String = "" + + // '设备代号'") + val device: String = "" + + // '主板名称'") + val board: String = "" + + // '制造商'") + val manufacturer: String = "" + + // '品牌'") + val brand: String = "" + + // '硬件标识'") + val hardware: String = "" + + // '认证用制造商'") + val manufacturerForAttestation: String = "" + + // '产品代码'") + val productCode: String = "" + + // '产品全名'") + val productFullName: String = "" + + // '产品制造日期'") + val productMfgDate: String = "" + + // CPU相关 +// 'CPU架构'") + val cpuAbi: String = "" + + // 'CPU核心数'") + val cpuCores: Int = 0 + + // '芯片名称'") + val chipName: String = "" + + // 'SoC制造商'") + val socManufacturer: String = "" + + // 'SoC型号'") + val socModel: String = "" + + // '主板平台'") + val boardPlatform: String = "" + + // GPU相关 +// 'GPU厂商'") + val gpuVendor: String = "" + + // 'GPU型号'") + val gpuModel: String = "" + + // 'GPU渲染器'") + val gpuRenderer: String = "" + + // 'OpenGL版本'") + val openglVersion: String = "" + + // 'OpenGL扩展'") + val openglExtensions: String = "" + + // 'Vulkan版本'") + val vulkanVersion: String = "" + + // 屏幕相关 +// '屏幕宽度像素'") + val widthPixels: Int = 0 + + // '屏幕高度像素'") + val heightPixels: Int = 0 + + // '密度DPI'") + val densityDpi: Int = 0 + + // '物理DPI'") + val dpi: Int = 0 + + // 存储内存 +// '总存储空间'") + val totalSpace: Long = 0 + + // '总内存'") + val totalMemory: Long = 0 + + // 基带相关 +// '基带版本'") + val radio: String = "" + + // 'RIL产品代码'") + val rilProductCode: String = "" + + // 'RIL官方CSC版本'") + val rilOfficialCscver: String = "" + +} + + +class SystemInfo { + // 系统版本信息 + // '发布版本,如Android 13, 14等'") + val orRelease: String = "" + + // 'SDK版本整数'") + val sdkInt: Int= 0 + + // '代号,如TIRAMISU, UPSIDE_DOWN_CAKE等'") + val codename: String = "" + + // '基础OS版本'") + val baseOs: String = "" + + // '增量版本'") + val incremental: String = "" + + // '安全补丁日期'") + val securityPatch: String = "" + + // 构建信息 + // '构建ID'") + val buildId: String = "" + + // '系统指纹'") + val fingerprint: String = "" + + // '显示版本'") + val display: String = "" + + // '构建主机'") + val host: String = "" + + // '构建标签'") + val tags: String = "" + + // '构建类型,如user, userdebug等'") + val type: String = "" + + // '构建用户'") + val user: String = "" + + // '构建时间戳'") + val time: Long = 0 + + // 系统组件 + // '引导程序版本'") + val bootloader: String = "" + + // '内核版本'") + val kernelVersion: String = "" + + // '厂商API版本'") + val vendorApi: Int = 0 + + // Google服务 + // 'GSF ID'") + val gsfId: String = "" + + // 'GMS版本'") + val gmsVersion: String = "" + + // 系统标识 + // 'Android ID'") + val androidId: String = "" + + // '用户代理字符串'") + val userAgent: String = "" +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/data/DataKeys.kt b/mydev/src/main/java/com/xyzshell/mydev/data/DataKeys.kt new file mode 100644 index 0000000..7313506 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/data/DataKeys.kt @@ -0,0 +1,851 @@ +package com.xyzshell.mydev.data + +val SystemPropKeys = setOf( + "ro.product.system.brand", + "ro.product.system.device", + "ro.product.system.manufacturer", + "ro.product.system.model", + "ro.product.system.name", + "ro.system.product.cpu.abilist", + "ro.system.product.cpu.abilist32", + "ro.system.product.cpu.abilist64", + "ro.system.build.date", + "ro.system.build.date.utc", + "ro.system.build.fingerprint", + "ro.system.build.id", + "ro.system.build.tags", + "ro.system.build.type", + "ro.system.build.version.incremental", + "ro.system.build.version.release", + "ro.system.build.version.release_or_codename", + "ro.system.build.version.sdk", + "ro.system.build.version.sdk_minor", + + + + + "ro.build.fingerprint", + "ro.build.id", + "ro.build.display.id", + "ro.build.version.incremental", + "ro.build.version.sdk", + "ro.build.version.sdk_minor", + "ro.build.version.preview_sdk", + "ro.build.version.preview_sdk_fingerprint", + "ro.build.version.codename", + "ro.build.version.all_codenames", + "ro.build.version.known_codenames", + "ro.build.version.release", + "ro.build.version.release_or_codename", + "ro.build.version.release_or_preview_display", + "ro.build.version.security_patch", + "ro.build.version.base_os", + "ro.build.version.min_supported_target_sdk", + "ro.build.date", + "ro.build.date.utc", + "ro.build.type", + "ro.build.user", + "ro.build.host", + "ro.build.tags", + "ro.build.flavor", + "ro.lineage.device", + + + "ro.product.cpu.abi", + "ro.product.locale", + "ro.wifi.channels", + + "ro.build.product", + + "ro.build.description", + + + + + "ro.treble.enabled", + "ro.llndk.api_level", + "ro.actionable_compatible_property.enabled", + "persist.debug.dalvik.vm.core_platform_api_policy", + "ro.postinstall.fstab.prefix", + "ro.secure", + "security.perf_harden", + "ro.allow.mock.location", + "dalvik.vm.lockprof.threshold", + "ro.debuggable", + "net.bt.name", + "ro.force.debuggable", + + + + "debug.atrace.tags.enableflags", + "persist.traced.enable", + "dalvik.vm.image-dex2oat-Xms", + "dalvik.vm.image-dex2oat-Xmx", + "dalvik.vm.dex2oat-Xms", + "dalvik.vm.dex2oat-Xmx", + "dalvik.vm.usejit", + "dalvik.vm.dexopt.secondary", + "dalvik.vm.dexopt.thermal-cutoff", + "dalvik.vm.appimageformat", + "ro.dalvik.vm.native.bridge", + "pm.dexopt.post-boot", + "pm.dexopt.first-boot", + "pm.dexopt.boot-after-ota", + "pm.dexopt.boot-after-mainline-update", + "pm.dexopt.install", + "pm.dexopt.install-fast", + "pm.dexopt.install-bulk", + "pm.dexopt.install-bulk-secondary", + "pm.dexopt.install-bulk-downgraded", + "pm.dexopt.install-bulk-secondary-downgraded", + "pm.dexopt.bg-dexopt", + "pm.dexopt.ab-ota", + "pm.dexopt.inactive", + "pm.dexopt.cmdline", + "pm.dexopt.shared", + "dalvik.vm.dex2oat-resolve-startup-strings", + "dalvik.vm.dex2oat-max-image-block-size", + "dalvik.vm.minidebuginfo", + "dalvik.vm.dex2oat-minidebuginfo", + "dalvik.vm.madvise.vdexfile.size", + "dalvik.vm.madvise.odexfile.size", + "dalvik.vm.madvise.artfile.size", + "dalvik.vm.usap_pool_enabled", + "dalvik.vm.usap_refill_threshold", + "dalvik.vm.usap_pool_size_max", + "dalvik.vm.usap_pool_size_min", + "dalvik.vm.usap_pool_refill_delay_ms", + "dalvik.vm.useartservice", + "dalvik.vm.enable_pr_dexopt", + "ro.cp_system_other_odex", + "ro.apex.updatable", + "ro.lineage.version", + "ro.lineage.display.version", + "ro.lineage.build.version", + "ro.lineage.releasetype", + "ro.lineagelegal.url", + + + + "ro.com.google.clientidbase", + "ro.adb.secure", + "persist.sys.strictmode.disable", + "ro.ota.allow_downgrade", + "ro.control_privapp_permissions", + "ro.storage_manager.enabled", + "dalvik.vm.systemuicompilerfilter", + "debug.sf.enable_transaction_tracing", + "media.recorder.show_manufacturer_and_model", + "net.tethering.noprovisioning", + + + + + + + "ro.build.backported_fixes.alias_bitset.long_list", + + + + + + "ro.product.system.brand", + "ro.product.system.device", + "ro.product.system.manufacturer", + "ro.product.system.model", + "ro.product.system.name", + "ro.system.product.cpu.abilist", + "ro.system.product.cpu.abilist32", + "ro.system.product.cpu.abilist64", + "ro.system.build.date", + "ro.system.build.date.utc", + "ro.system.build.fingerprint", + "ro.system.build.id", + "ro.system.build.tags", + "ro.system.build.type", + "ro.system.build.version.incremental", + "ro.system.build.version.release", + "ro.system.build.version.release_or_codename", + "ro.system.build.version.sdk", + "ro.system.build.version.sdk_minor", + + + + + "ro.build.fingerprint", + "ro.build.id", + "ro.build.display.id", + "ro.build.version.incremental", + "ro.build.version.sdk", + "ro.build.version.sdk_minor", + "ro.build.version.preview_sdk", + "ro.build.version.preview_sdk_fingerprint", + "ro.build.version.codename", + "ro.build.version.all_codenames", + "ro.build.version.known_codenames", + "ro.build.version.release", + "ro.build.version.release_or_codename", + "ro.build.version.release_or_preview_display", + "ro.build.version.security_patch", + "ro.build.version.base_os", + "ro.build.version.min_supported_target_sdk", + "ro.build.date", + "ro.build.date.utc", + "ro.build.type", + "ro.build.user", + "ro.build.host", + "ro.build.tags", + "ro.build.flavor", + "ro.lineage.device", + + + "ro.product.cpu.abi", + "ro.product.locale", + "ro.wifi.channels", + + "ro.build.product", + + "ro.build.description", + + + + + "ro.treble.enabled", + "ro.llndk.api_level", + "ro.actionable_compatible_property.enabled", + "persist.debug.dalvik.vm.core_platform_api_policy", + "ro.postinstall.fstab.prefix", + "ro.secure", + "security.perf_harden", + "ro.allow.mock.location", + "dalvik.vm.lockprof.threshold", + "ro.debuggable", + "net.bt.name", + "ro.force.debuggable", + + + + "debug.atrace.tags.enableflags", + "persist.traced.enable", + "dalvik.vm.image-dex2oat-Xms", + "dalvik.vm.image-dex2oat-Xmx", + "dalvik.vm.dex2oat-Xms", + "dalvik.vm.dex2oat-Xmx", + "dalvik.vm.usejit", + "dalvik.vm.dexopt.secondary", + "dalvik.vm.dexopt.thermal-cutoff", + "dalvik.vm.appimageformat", + "ro.dalvik.vm.native.bridge", + "pm.dexopt.post-boot", + "pm.dexopt.first-boot", + "pm.dexopt.boot-after-ota", + "pm.dexopt.boot-after-mainline-update", + "pm.dexopt.install", + "pm.dexopt.install-fast", + "pm.dexopt.install-bulk", + "pm.dexopt.install-bulk-secondary", + "pm.dexopt.install-bulk-downgraded", + "pm.dexopt.install-bulk-secondary-downgraded", + "pm.dexopt.bg-dexopt", + "pm.dexopt.ab-ota", + "pm.dexopt.inactive", + "pm.dexopt.cmdline", + "pm.dexopt.shared", + "dalvik.vm.dex2oat-resolve-startup-strings", + "dalvik.vm.dex2oat-max-image-block-size", + "dalvik.vm.minidebuginfo", + "dalvik.vm.dex2oat-minidebuginfo", + "dalvik.vm.madvise.vdexfile.size", + "dalvik.vm.madvise.odexfile.size", + "dalvik.vm.madvise.artfile.size", + "dalvik.vm.usap_pool_enabled", + "dalvik.vm.usap_refill_threshold", + "dalvik.vm.usap_pool_size_max", + "dalvik.vm.usap_pool_size_min", + "dalvik.vm.usap_pool_refill_delay_ms", + "dalvik.vm.useartservice", + "dalvik.vm.enable_pr_dexopt", + "ro.cp_system_other_odex", + "ro.apex.updatable", + "ro.lineage.version", + "ro.lineage.display.version", + "ro.lineage.build.version", + "ro.lineage.releasetype", + "ro.lineagelegal.url", + + + + "ro.com.google.clientidbase", + "ro.adb.secure", + "persist.sys.strictmode.disable", + "ro.ota.allow_downgrade", + "ro.control_privapp_permissions", + "ro.storage_manager.enabled", + "dalvik.vm.systemuicompilerfilter", + "debug.sf.enable_transaction_tracing", + "media.recorder.show_manufacturer_and_model", + "net.tethering.noprovisioning", + + + + + + + "ro.build.backported_fixes.alias_bitset.long_list", + + + + + "ro.product.vendor.brand", + "ro.product.vendor.device", + "ro.product.vendor.manufacturer", + "ro.product.vendor.model", + "ro.product.vendor.name", + "ro.vendor.product.cpu.abilist", + "ro.vendor.product.cpu.abilist32", + "ro.vendor.product.cpu.abilist64", + "ro.vendor.build.date", + "ro.vendor.build.date.utc", + "ro.vendor.build.fingerprint", + "ro.vendor.build.id", + "ro.vendor.build.tags", + "ro.vendor.build.type", + "ro.vendor.build.version.incremental", + "ro.vendor.build.version.release", + "ro.vendor.build.version.release_or_codename", + "ro.vendor.build.version.sdk", + "ro.vendor.build.version.sdk_minor", + + + + + "aaudio.hw_burst_min_usec", + "aaudio.mmap_exclusive_policy", + "aaudio.mmap_policy", + "audio.deep_buffer.media", + "audio.offload.video", + "audio.sys.offload.pstimeout.secs", + "audio.sys.noisy.broadcast.delay", + "persist.vendor.audio.spf_restart", + "ro.af.client_heap_size_kbyte", + "ro.audio.flinger_standbytime_ms", + "vendor.audio_hal.period_size", + "vendor.audio.adm.buffering.ms", + "vendor.audio.c2.preferred", + "vendor.audio.flac.sw.decoder.24bit", + "vendor.audio.enable.mirrorlink", + "vendor.audio.feature.a2dp_offload.enable", + "vendor.audio.feature.afe_proxy.enable", + "vendor.audio.feature.battery_listener.enable", + "vendor.audio.feature.dmabuf.cma.memory.enable", + "vendor.audio.feature.handset.profile.disable", + "vendor.audio.feature.hfp.enable", + "vendor.audio.feature.kpi_optimize.enable", + "vendor.audio.hdr.record.enable", + "vendor.audio.hw.aac.encoder", + "vendor.audio.offload.buffer.size.kb", + "vendor.audio.offload.multiple.enabled", + "vendor.audio.offload.track.enable", + "vendor.audio.safx.pbe.enabled", + "vendor.audio.ull_record_period_multiplier", + "vendor.audio.use.sw.alac.decoder", + "vendor.audio.use.sw.ape.decoder", + "vendor.audio.use.sw.mpegh.decoder", + "vendor.audio.volume.headset.gain.depcal", + "vendor.qc2audio.suspend.enabled", + "vendor.qc2audio.per_frame.flac.dec.enabled", + + "bluetooth.device.class_of_device", + "bluetooth.hardware.power.idle_cur_ma", + "bluetooth.hardware.power.operating_voltage_mv", + "bluetooth.hardware.power.rx_cur_ma", + "bluetooth.hardware.power.tx_cur_ma", + "bluetooth.profile.a2dp.source.enabled", + "bluetooth.profile.asha.central.enabled", + "bluetooth.profile.avrcp.target.enabled", + "bluetooth.profile.bas.client.enabled", + "bluetooth.profile.gatt.enabled", + "bluetooth.profile.hfp.ag.enabled", + "bluetooth.profile.hid.device.enabled", + "bluetooth.profile.hid.host.enabled", + "bluetooth.profile.map.server.enabled", + "bluetooth.profile.opp.enabled", + "bluetooth.profile.pan.nap.enabled", + "bluetooth.profile.pan.panu.enabled", + "bluetooth.profile.pbap.server.enabled", + "bluetooth.profile.sap.server.enabled", + "persist.bluetooth.a2dp_offload.disabled", + "persist.vendor.bt.aac_frm_ctl.enabled", + "persist.vendor.bt.aac_vbr_frm_ctl.enabled", + "persist.vendor.qcom.bluetooth.a2dp_offload_cap", + "persist.vendor.qcom.bluetooth.aac_frm_ctl.enabled", + "persist.vendor.qcom.bluetooth.aptxadaptiver2_1_support", + "ro.bluetooth.a2dp_offload.supported", + + "vendor.camera.aux.packageexcludelist", + + "ro.soc.manufacturer", + + "persist.vendor.dpm.vndr.idletimer.mode", + "persist.vendor.dpm.vndr.halservice.enable", + "persist.vendor.dpm.vndr.feature", + + "persist.sys.sf.color_mode", + "persist.sys.sf.color_saturation", + "vendor.display.comp_mask", + "vendor.display.disable_3d_adaptive_tm", + "vendor.display.disable_excl_rect", + "vendor.display.disable_excl_rect_partial_fb", + "vendor.display.disable_hw_recovery_dump", + "vendor.display.disable_offline_rotator", + "vendor.display.disable_scaler", + "vendor.display.disable_sdr_dimming", + "vendor.display.disable_sdr_histogram", + "vendor.display.disable_stc_dimming", + "vendor.display.enable_async_powermode", + "vendor.display.enable_async_vds_creation", + "vendor.display.enable_dpps_dynamic_fps", + "vendor.display.enable_early_wakeup", + "vendor.display.enable_hdr10_gpu_target", + "vendor.display.enable_optimize_refresh", + "vendor.display.use_smooth_motion", + "vendor.display.vds_allow_hwc", + + "drm.service.enabled", + + "ro.frp.pst", + + "persist.sys.fuse.passthrough.enable", + + "vendor.gatekeeper.disable_spu", + "vendor.gatekeeper.is_security_level_spu", + + "debug.sf.auto_latch_unsignaled", + "debug.sf.disable_client_composition_cache", + "debug.sf.early.app.duration", + "debug.sf.early.sf.duration", + "debug.sf.earlyGl.app.duration", + "debug.sf.earlyGl.sf.duration", + "debug.sf.enable_advanced_sf_phase_offset", + "debug.sf.enable_gl_backpressure", + "debug.sf.enable_hwc_vds", + "debug.sf.predict_hwc_composition_strategy", + "debug.sf.latch_unsignaled", + "debug.sf.late.app.duration", + "debug.sf.late.sf.duration", + "debug.sf.treat_170m_as_sRGB", + "debug.sf.use_phase_offsets_as_durations", + "ro.hardware.egl", + "ro.hardware.vulkan", + "ro.opengles.version", + "ro.surface_flinger.force_hwc_copy_for_virtual_displays", + "ro.surface_flinger.game_default_frame_rate_override", + "ro.surface_flinger.has_HDR_display", + "ro.surface_flinger.has_wide_color_display", + "ro.surface_flinger.max_frame_buffer_acquired_buffers", + "ro.surface_flinger.max_virtual_display_dimension", + "ro.surface_flinger.protected_contents", + "ro.surface_flinger.use_color_management", + "ro.surface_flinger.use_content_detection_for_refresh_rate", + "ro.surface_flinger.wcg_composition_dataspace", + + "ro.incremental.enable", + + "debug.c2.use_dmabufheaps", + "debug.stagefright.c2inputsurface", + "vendor.media.omx", + + "ro.netflix.bsp_rev", + + "ro.vendor.extension_library", + + "persist.radio.multisim.config", + "persist.vendor.radio.apm_sim_not_pwdn", + "persist.vendor.radio.custom_ecc", + "persist.vendor.radio.enableadvancedscan", + "persist.vendor.radio.procedure_bytes", + "persist.vendor.radio.rat_on", + "persist.vendor.radio.sib16_support", + "ro.telephony.default_network", + + "persist.vendor.rcs.singlereg.feature", + + "persist.vendor.sensors.debug.hal", + "vendor.dynamic_sensor.setup.timeout.ms", + + "sys.usb.mtp.batchcancel", + "vendor.usb.controller", + "vendor.usb.diag.func.name", + "vendor.usb.dpl.inst.name", + "vendor.usb.qdss.inst.name", + "vendor.usb.rmnet.func.name", + "vendor.usb.rmnet.inst.name", + "vendor.usb.rndis.func.name", + "vendor.usb.use_ffs_mtp", + "vendor.usb.use_gadget_hal", + + "wifi.aware.interface", + + "zygote.critical_window.minute", + + + + + "bluetooth.device.default_name", + + "ro.surface_flinger.set_idle_timer_ms", + "ro.surface_flinger.set_touch_timer_ms", + + "vendor.usb.product_string", + + + + + + + "ro.bionic.arch", + "ro.bionic.cpu_variant", + "ro.bionic.2nd_arch", + "ro.bionic.2nd_cpu_variant", + "persist.sys.dalvik.vm.lib.2", + "dalvik.vm.isa.arm64.variant", + "dalvik.vm.isa.arm64.features", + "ro.minui.pixel_format", + "ro.boot.dynamic_partitions", + "ro.product.first_api_level", + "ro.product.debugfs_restrictions.enabled", + "ro.board.first_api_level", + "ro.board.api_level", + "ro.board.api_frozen", + "ro.vendor.build.security_patch", + "ro.product.board", + "ro.board.platform", + "ro.hwui.use_vulkan", + "ro.sf.lcd_density", + "ro.build.ab_update", + "ro.vendor.build.ab_ota_partitions", + + + + "ro.zygote", + "dalvik.vm.dex2oat64.enabled", + "keyguard.no_require_sim", + "ro.com.android.dataroaming", + "ro.config.ringtone", + + + + + "tombstoned.max_tombstone_count", + "ro.logd.size.stats", + "log.tag.stats_log", + "ro.carrier", + "ro.config.notification_sound", + "ro.config.alarm_alert", + "ro.recovery.usb.vid", + "ro.recovery.usb.adb.pid", + "ro.recovery.usb.fastboot.pid", + "ro.virtual_ab.enabled", + "dalvik.vm.heapstartsize", + "dalvik.vm.heapgrowthlimit", + "dalvik.vm.heapsize", + "dalvik.vm.heaptargetutilization", + "dalvik.vm.heapminfree", + "dalvik.vm.heapmaxfree", + "external_storage.projid.enabled", + "external_storage.casefold.enabled", + "external_storage.sdcardfs.enabled", + + + + + + + + + + + + + + "ro.product.vendor.brand", + "ro.product.vendor.device", + "ro.product.vendor.manufacturer", + "ro.product.vendor.model", + "ro.product.vendor.name", + "ro.vendor.product.cpu.abilist", + "ro.vendor.product.cpu.abilist32", + "ro.vendor.product.cpu.abilist64", + "ro.vendor.build.date", + "ro.vendor.build.date.utc", + "ro.vendor.build.fingerprint", + "ro.vendor.build.id", + "ro.vendor.build.tags", + "ro.vendor.build.type", + "ro.vendor.build.version.incremental", + "ro.vendor.build.version.release", + "ro.vendor.build.version.release_or_codename", + "ro.vendor.build.version.sdk", + "ro.vendor.build.version.sdk_minor", + + + + + "aaudio.hw_burst_min_usec", + "aaudio.mmap_exclusive_policy", + "aaudio.mmap_policy", + "audio.deep_buffer.media", + "audio.offload.video", + "audio.sys.offload.pstimeout.secs", + "audio.sys.noisy.broadcast.delay", + "persist.vendor.audio.spf_restart", + "ro.af.client_heap_size_kbyte", + "ro.audio.flinger_standbytime_ms", + "vendor.audio_hal.period_size", + "vendor.audio.adm.buffering.ms", + "vendor.audio.c2.preferred", + "vendor.audio.flac.sw.decoder.24bit", + "vendor.audio.enable.mirrorlink", + "vendor.audio.feature.a2dp_offload.enable", + "vendor.audio.feature.afe_proxy.enable", + "vendor.audio.feature.battery_listener.enable", + "vendor.audio.feature.dmabuf.cma.memory.enable", + "vendor.audio.feature.handset.profile.disable", + "vendor.audio.feature.hfp.enable", + "vendor.audio.feature.kpi_optimize.enable", + "vendor.audio.hdr.record.enable", + "vendor.audio.hw.aac.encoder", + "vendor.audio.offload.buffer.size.kb", + "vendor.audio.offload.multiple.enabled", + "vendor.audio.offload.track.enable", + "vendor.audio.safx.pbe.enabled", + "vendor.audio.ull_record_period_multiplier", + "vendor.audio.use.sw.alac.decoder", + "vendor.audio.use.sw.ape.decoder", + "vendor.audio.use.sw.mpegh.decoder", + "vendor.audio.volume.headset.gain.depcal", + "vendor.qc2audio.suspend.enabled", + "vendor.qc2audio.per_frame.flac.dec.enabled", + + "bluetooth.device.class_of_device", + "bluetooth.hardware.power.idle_cur_ma", + "bluetooth.hardware.power.operating_voltage_mv", + "bluetooth.hardware.power.rx_cur_ma", + "bluetooth.hardware.power.tx_cur_ma", + "bluetooth.profile.a2dp.source.enabled", + "bluetooth.profile.asha.central.enabled", + "bluetooth.profile.avrcp.target.enabled", + "bluetooth.profile.bas.client.enabled", + "bluetooth.profile.gatt.enabled", + "bluetooth.profile.hfp.ag.enabled", + "bluetooth.profile.hid.device.enabled", + "bluetooth.profile.hid.host.enabled", + "bluetooth.profile.map.server.enabled", + "bluetooth.profile.opp.enabled", + "bluetooth.profile.pan.nap.enabled", + "bluetooth.profile.pan.panu.enabled", + "bluetooth.profile.pbap.server.enabled", + "bluetooth.profile.sap.server.enabled", + "persist.bluetooth.a2dp_offload.disabled", + "persist.vendor.bt.aac_frm_ctl.enabled", + "persist.vendor.bt.aac_vbr_frm_ctl.enabled", + "persist.vendor.qcom.bluetooth.a2dp_offload_cap", + "persist.vendor.qcom.bluetooth.aac_frm_ctl.enabled", + "persist.vendor.qcom.bluetooth.aptxadaptiver2_1_support", + "ro.bluetooth.a2dp_offload.supported", + + "vendor.camera.aux.packageexcludelist", + + "ro.soc.manufacturer", + + "persist.vendor.dpm.vndr.idletimer.mode", + "persist.vendor.dpm.vndr.halservice.enable", + "persist.vendor.dpm.vndr.feature", + + "persist.sys.sf.color_mode", + "persist.sys.sf.color_saturation", + "vendor.display.comp_mask", + "vendor.display.disable_3d_adaptive_tm", + "vendor.display.disable_excl_rect", + "vendor.display.disable_excl_rect_partial_fb", + "vendor.display.disable_hw_recovery_dump", + "vendor.display.disable_offline_rotator", + "vendor.display.disable_scaler", + "vendor.display.disable_sdr_dimming", + "vendor.display.disable_sdr_histogram", + "vendor.display.disable_stc_dimming", + "vendor.display.enable_async_powermode", + "vendor.display.enable_async_vds_creation", + "vendor.display.enable_dpps_dynamic_fps", + "vendor.display.enable_early_wakeup", + "vendor.display.enable_hdr10_gpu_target", + "vendor.display.enable_optimize_refresh", + "vendor.display.use_smooth_motion", + "vendor.display.vds_allow_hwc", + + "drm.service.enabled", + + "ro.frp.pst", + + "persist.sys.fuse.passthrough.enable", + + "vendor.gatekeeper.disable_spu", + "vendor.gatekeeper.is_security_level_spu", + + "debug.sf.auto_latch_unsignaled", + "debug.sf.disable_client_composition_cache", + "debug.sf.early.app.duration", + "debug.sf.early.sf.duration", + "debug.sf.earlyGl.app.duration", + "debug.sf.earlyGl.sf.duration", + "debug.sf.enable_advanced_sf_phase_offset", + "debug.sf.enable_gl_backpressure", + "debug.sf.enable_hwc_vds", + "debug.sf.predict_hwc_composition_strategy", + "debug.sf.latch_unsignaled", + "debug.sf.late.app.duration", + "debug.sf.late.sf.duration", + "debug.sf.treat_170m_as_sRGB", + "debug.sf.use_phase_offsets_as_durations", + "ro.hardware.egl", + "ro.hardware.vulkan", + "ro.opengles.version", + "ro.surface_flinger.force_hwc_copy_for_virtual_displays", + "ro.surface_flinger.game_default_frame_rate_override", + "ro.surface_flinger.has_HDR_display", + "ro.surface_flinger.has_wide_color_display", + "ro.surface_flinger.max_frame_buffer_acquired_buffers", + "ro.surface_flinger.max_virtual_display_dimension", + "ro.surface_flinger.protected_contents", + "ro.surface_flinger.use_color_management", + "ro.surface_flinger.use_content_detection_for_refresh_rate", + "ro.surface_flinger.wcg_composition_dataspace", + + "ro.incremental.enable", + + "debug.c2.use_dmabufheaps", + "debug.stagefright.c2inputsurface", + "vendor.media.omx", + + "ro.netflix.bsp_rev", + + "ro.vendor.extension_library", + + "persist.radio.multisim.config", + "persist.vendor.radio.apm_sim_not_pwdn", + "persist.vendor.radio.custom_ecc", + "persist.vendor.radio.enableadvancedscan", + "persist.vendor.radio.procedure_bytes", + "persist.vendor.radio.rat_on", + "persist.vendor.radio.sib16_support", + "ro.telephony.default_network", + + "persist.vendor.rcs.singlereg.feature", + + "persist.vendor.sensors.debug.hal", + "vendor.dynamic_sensor.setup.timeout.ms", + + "sys.usb.mtp.batchcancel", + "vendor.usb.controller", + "vendor.usb.diag.func.name", + "vendor.usb.dpl.inst.name", + "vendor.usb.qdss.inst.name", + "vendor.usb.rmnet.func.name", + "vendor.usb.rmnet.inst.name", + "vendor.usb.rndis.func.name", + "vendor.usb.use_ffs_mtp", + "vendor.usb.use_gadget_hal", + + "wifi.aware.interface", + + "zygote.critical_window.minute", + + + + + "bluetooth.device.default_name", + + "ro.surface_flinger.set_idle_timer_ms", + "ro.surface_flinger.set_touch_timer_ms", + + "vendor.usb.product_string", + + + + + + + "ro.bionic.arch", + "ro.bionic.cpu_variant", + "ro.bionic.2nd_arch", + "ro.bionic.2nd_cpu_variant", + "persist.sys.dalvik.vm.lib.2", + "dalvik.vm.isa.arm64.variant", + "dalvik.vm.isa.arm64.features", + "ro.minui.pixel_format", + "ro.boot.dynamic_partitions", + "ro.product.first_api_level", + "ro.product.debugfs_restrictions.enabled", + "ro.board.first_api_level", + "ro.board.api_level", + "ro.board.api_frozen", + "ro.vendor.build.security_patch", + "ro.product.board", + "ro.board.platform", + "ro.hwui.use_vulkan", + "ro.sf.lcd_density", + "ro.build.ab_update", + "ro.vendor.build.ab_ota_partitions", + + + "ro.product.odm.brand", + "ro.product.odm.device", + "ro.product.odm.manufacturer", + "ro.product.odm.model", + "ro.product.odm.name", + "ro.odm.product.cpu.abilist", + "ro.odm.product.cpu.abilist32", + "ro.odm.product.cpu.abilist64", + "ro.odm.build.date", + "ro.odm.build.date.utc", + "ro.odm.build.fingerprint", + "ro.odm.build.id", + "ro.odm.build.tags", + "ro.odm.build.type", + "ro.odm.build.version.incremental", + "ro.odm.build.version.release", + "ro.odm.build.version.release_or_codename", + "ro.odm.build.version.sdk", + "ro.odm.build.version.sdk_minor", + + + + + "ro.config.media_vol_steps", + "ro.config.vc_call_vol_steps", + "ro.vendor.qti.va_odm.support", + + "persist.vendor.bluetooth.modem_nv_support", + + "ro.hardware.camera", + + "ro.vendor.display.sensortype", + "vendor.display.enable_rc_support", + "vendor.display.enable_rounded_corner", + "vendor.display.disable_noise_layer", + "vendor.display.force_dv_support", + + "persist.vendor.radio.force_on_dc", + "persist.vendor.radio.poweron_opt", + "persist.vendor.radio.stack_id_0", + "persist.vendor.radio.stack_id_1", + "ro.sys.reserve.integrate", + "ro.vendor.oplus.radio.project", + "ro.vendor.oplus.radio.sar_regionmark", + + "ro.build.version.svn", + + + + + ) \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/AdvertisingId.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/AdvertisingId.kt new file mode 100644 index 0000000..9d42f6a --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/AdvertisingId.kt @@ -0,0 +1,132 @@ +package com.xyzshell.mydev.utils + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import android.os.IInterface +import android.os.Parcel +import java.util.concurrent.LinkedBlockingQueue + + +class AdvertisingId private constructor() { + companion object { + private const val ADVERTISING_ID_SERVICE_NAME = + "com.google.android.gms.ads.identifier.internal.IAdvertisingIdService" + private val instance = SingletonHolder.holder + fun getAdvertisingTrackingId(): String { + return instance.advertisingIdentifier ?: "" + } + + fun getLimitedAdTracking(): Boolean { + return instance.limitedAdvertisingTracking + } + + fun init(paramContext: Context) { + instance.fetchAdvertisingId(paramContext); + } + } + + private object SingletonHolder { + val holder = AdvertisingId() + } + + private var advertisingIdentifier: String? = null + + private var limitedAdvertisingTracking = false + + + private fun fetchAdvertisingId(paramContext: Context) { + val connection = GoogleAdvertisingServiceConnection(); + val intent = Intent("com.google.android.gms.ads.identifier.service.START") + intent.setPackage("com.google.android.gms") + try { + val bool1 = paramContext.bindService( + intent, + connection, + Context.BIND_AUTO_CREATE + ) + if(bool1) { + val iBinder = connection.getBinder() + val googleAdvertisingInfo = + iBinder?.let { GoogleAdvertisingInfo(it) } + + val str = googleAdvertisingInfo?.getId() + this.advertisingIdentifier = str + val bool2 = googleAdvertisingInfo?.getEnabled(true) + if (bool2 != null) { + this.limitedAdvertisingTracking = bool2 + } + } + } finally { + paramContext.unbindService(connection) + } + } + + + class GoogleAdvertisingServiceConnection : ServiceConnection { + private var retrieved: Boolean = false + private val queue = LinkedBlockingQueue(1) + + fun getBinder(): IBinder? { + check(!this.retrieved) + this.retrieved = true + return queue.take() + } + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + try { + queue.put(service) + } catch (e: InterruptedException) { + e.printStackTrace() + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + + } + + } + + class GoogleAdvertisingInfo(private val _binder: IBinder) : IInterface { + fun getEnabled(paramBoolean: Boolean): Boolean { + val parcel1 = Parcel.obtain() + val parcel2 = Parcel.obtain() + try { + parcel1.writeInterfaceToken(ADVERTISING_ID_SERVICE_NAME) + parcel1.writeInt(if (paramBoolean) 1 else 0) + this._binder.transact(2, parcel1, parcel2, 0) + parcel2.readException() + val i = parcel2.readInt() + return i != 0 + } finally { + parcel1.recycle() + parcel2.recycle() + } + } + + fun getId(): String { + val parcel1 = Parcel.obtain() + val parcel2 = Parcel.obtain() + try { + parcel1.writeInterfaceToken(ADVERTISING_ID_SERVICE_NAME) + val iBinder = this._binder + iBinder.transact(1, parcel1, parcel2, 0) + parcel2.readException() + val b = parcel2.readString() ?: return "" + return b + } finally { + parcel2.recycle() + parcel1.recycle() + } + } + + override fun asBinder(): IBinder { + return this._binder + } + + } + + +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/DeviceInfo.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/DeviceInfo.kt new file mode 100644 index 0000000..def678d --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/DeviceInfo.kt @@ -0,0 +1,742 @@ +package com.xyzshell.mydev.utils + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageManager +import android.content.pm.Signature +import android.hardware.Sensor +import android.hardware.SensorManager +import android.media.AudioManager +import android.media.MediaCodecInfo +import android.media.MediaCodecList +import android.net.ConnectivityManager +import android.os.Build +import android.os.SystemClock +import android.os.ext.SdkExtensions +import android.provider.Settings +import android.telephony.TelephonyManager +import android.webkit.WebSettings +import androidx.core.app.ActivityCompat +import com.xyzshell.mydev.InfoItem +import org.json.JSONObject +import java.io.ByteArrayInputStream +import java.io.File +import java.io.FileInputStream +import java.io.RandomAccessFile +import java.security.MessageDigest +import java.security.cert.Certificate +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate +import java.util.Locale +import java.util.TimeZone +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.regex.Matcher +import java.util.regex.Pattern +import javax.security.auth.x500.X500Principal + + +typealias Callback = () -> Unit + +class DeviceInfo { + private var advertisingTrackingId:String = "" + private var limitedAdTracking:Boolean = false + private var adInit = false + private var adCallback: Callback? = null + private var context:Context? = null + private var apk_digest_timeout:Long = 0 + private var apk_digest_size:Long = 0 + private var apk_digest:String = "" + private var apk_digest_init:Boolean = false + private val DEBUG_CERT = X500Principal("CN=Android Debug,O=Android,C=US") + + private object SingletonHolder { + @SuppressLint("StaticFieldLeak") + val holder = DeviceInfo() + } + + companion object { + @SuppressLint("StaticFieldLeak") + val instance = SingletonHolder.holder + } + + val AdvertisingTrackingId get() = advertisingTrackingId + val LimitedAdTracking get() = limitedAdTracking + val ApiLevel get() = Build.VERSION.SDK_INT + + val ApkDigest get() = apk_digest + val ApkDigestSize get() = apk_digest_size + val ApkDigestTimeout get() = apk_digest_timeout + + fun init(ctx:Context) { + this.context = ctx + Executors.newSingleThreadExecutor().execute { + try { + AdvertisingId.init(ctx) + advertisingTrackingId = AdvertisingId.getAdvertisingTrackingId() + limitedAdTracking = AdvertisingId.getLimitedAdTracking() + adInit = true + adCallback?.let { it() } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + fun onAdInit(callback: Callback) { + if(adInit) { + callback() + } + this.adCallback = callback + } + + fun getApkDigest() { + if(this.context == null) { + return + } + try { + val startTime = System.nanoTime() + val path: String = this.context!!.packageCodePath + val file = File(path) + apk_digest_size = file.length() + val fileInputStream = FileInputStream(file) + apk_digest = Utilities.sha256(fileInputStream) + fileInputStream.close() + val l4 = System.nanoTime() - startTime + val timeUnit: TimeUnit = TimeUnit.NANOSECONDS + apk_digest_timeout= timeUnit.toMillis(l4) + apk_digest_init = true + } catch (e:Throwable) { + e.printStackTrace() + } + } + + fun getAuid(): String { + if(this.context == null) { + return "" + } + val sharedPreferences = this.context!!.getSharedPreferences("supersonic_shared_preferen", Context.MODE_PRIVATE) + return sharedPreferences.getString("auid", "") ?: "" + } + + fun getBatteryStatus():Int { + val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) + val intent = context!!.registerReceiver(null, intentFilter) + if (intent != null) { + return intent.getIntExtra("status", -1) + } + return -1 + } + + fun getBoard(): String { + return Build.BOARD + } + + fun getBootloader(): String { + return Build.BOOTLOADER + } + + fun getBrand(): String { + return Build.BRAND + } + + fun getBuildId(): String { + return Build.ID + } + + fun getBuildVersionIncremental(): String { + return Build.VERSION.INCREMENTAL + } + + fun getCPUCount(): Long { + return Runtime.getRuntime().availableProcessors().toLong() + } + fun getCertificateFingerprint(): String { + val packageManager = this.context?.packageManager + val packageName = this.context?.packageName ?: return "" + try { + val packageInfo = packageManager?.getPackageInfo(packageName, 64) + val arrayOfSignature: Array? = packageInfo!!.signatures + if (!arrayOfSignature.isNullOrEmpty()) { + val certificateFactory = CertificateFactory.getInstance("X.509") + val byteArrayInputStream = ByteArrayInputStream(arrayOfSignature[0].toByteArray()) + val certificate = certificateFactory.generateCertificate(byteArrayInputStream) + val messageDigest = MessageDigest.getInstance("SHA-1") + var arrayOfByte2 = certificate.encoded + arrayOfByte2 = messageDigest.digest(arrayOfByte2) + return Utilities.toHexString(arrayOfByte2) + } + } catch (e:Throwable) { + e.printStackTrace() + } + return "" + } + + fun getDevice(): String { + return Build.DEVICE + } + fun getFingerprint(): String { + return Build.FINGERPRINT + } + + fun getModel(): String { + return Build.MODEL + } + + fun getOsVersion(): String { + return Build.VERSION.RELEASE + } + fun getAppName() : String{ + return context?.packageName ?: "" + } + fun getProduct(): String { + return Build.PRODUCT + } + fun getManufacturer(): String { + return Build.MANUFACTURER + } + + fun getProcessInfo():Map { + val map = mutableMapOf() + val randomAccessFile1 = RandomAccessFile("/proc/self/stat","r") + randomAccessFile1.use { + map.put("stat", randomAccessFile1.readLine()) + } + return map.toMap() + } + + fun getRingerMode():Int { + if(this.context == null) { + return -1 + } + val audioManager = this.context!!.getSystemService(Context.AUDIO_SERVICE) as android.media.AudioManager + return audioManager.ringerMode + } + + fun getScreenBrightness():Int { + if(this.context == null) { + return -1 + } + return Settings.System.getInt(this.context!!.contentResolver, "screen_brightness", -1) + } + fun getScreenDensity():Int { + return context?.resources?.displayMetrics?.densityDpi ?: -1 + } + fun getScreenHeight():Int { + return context?.resources?.displayMetrics?.heightPixels ?: -1 + } + fun getScreenWidth():Int { + return context?.resources?.displayMetrics?.widthPixels ?: -1 + } + + fun getScreenLayout():Int { + return context?.resources?.configuration?.screenLayout ?: -1 + } + fun getSensorList(): List { + if(this.context == null) { + return listOf() + } + val sensorManager = this.context!!.getSystemService(Context.SENSOR_SERVICE) as SensorManager + return sensorManager.getSensorList(Sensor.TYPE_ALL) + } + + fun getStreamMaxVolume(paramInt:Int):Int { + if(this.context == null) { + return -1 + } + val audioManager = this.context!!.getSystemService(Context.AUDIO_SERVICE) as android.media.AudioManager + return audioManager.getStreamMaxVolume(paramInt) + } + fun getStreamVolume(paramInt:Int):Int { + if(this.context == null) { + return -1 + } + val audioManager = this.context!!.getSystemService(Context.AUDIO_SERVICE) as android.media.AudioManager + return audioManager.getStreamVolume(paramInt) + } + fun getSupportedAbis():Array { + if (ApiLevel < 21) { + return getOldAbiList() + } + return getNewAbiList() + } + fun getSystemProperty(paramString1: String, paramString2: String?): String { + return if ((paramString2 != null)) System.getProperty( + paramString1, + paramString2 + ) else System.getProperty(paramString1) + } + fun getTotalMemory(): Long { + return getMemoryInfo(MemoryInfoType.TOTAL_MEMORY) + } + fun getFreeSpace(paramFile: File?): Long { + if (paramFile != null) { + val bool = paramFile.exists() + if (bool) return Math.round((paramFile.freeSpace / 1024L).toFloat()) + .toLong() + } + return -1L + } + fun getTotalSpace(file: File):Long { + if(!file.exists()) { + return -1 + } + return Math.round(file.totalSpace / 1024.0) + } + fun getUptime():Long { + return SystemClock.uptimeMillis() + } + + fun hasAV1Decoder():Boolean { + return selectAllDecodeCodecs("video/av01").isNotEmpty() + } + fun hasX264Decoder():Boolean { + return selectAllDecodeCodecs("video/avc").isNotEmpty() + } + fun hasX265Decoder():Boolean { + return selectAllDecodeCodecs("video/hevc").isNotEmpty() + } + + fun isAdbEnabled():Boolean { + if(ApiLevel < 17) { + return oldAdbStatus() + } + return newAdbStatus() + } + + fun oldAdbStatus():Boolean { + val contentResolver = this.context?.contentResolver + val j = Settings.Secure.getInt(contentResolver, Settings.Global.ADB_ENABLED, 0) + return j == 1 + } + + fun newAdbStatus():Boolean { + val contentResolver = this.context?.contentResolver + val j = Settings.Global.getInt(contentResolver, Settings.Global.ADB_ENABLED, 0) + return j == 1 + } + + + fun selectAllDecodeCodecs(paramString:String):List { + val res = mutableListOf() + val count = MediaCodecList.getCodecCount() + for (i in 0 until count) { + val mediaCodecInfo: MediaCodecInfo = MediaCodecList.getCodecInfoAt(i) + if (!mediaCodecInfo.isEncoder) { + val arrayOfString: Array = mediaCodecInfo.supportedTypes + for (j in arrayOfString.indices) { + if (!arrayOfString[j].equals(paramString, ignoreCase = true)) { + continue + } + if(isHardwareAccelerated(mediaCodecInfo, paramString)) { + res.add(mediaCodecInfo) + } + } + } + } + return res + } + fun isHardwareAccelerated(paramMediaCodecInfo:MediaCodecInfo, paramString:String):Boolean { + if (ApiLevel >= 29) { + return isHardwareAcceleratedV29(paramMediaCodecInfo) + } + return isSoftwareOnly(paramMediaCodecInfo, paramString) + } + fun isHardwareAcceleratedV29(paramMediaCodecInfo:MediaCodecInfo):Boolean { + return paramMediaCodecInfo.isHardwareAccelerated + } + fun isSoftwareOnly( paramMediaCodecInfo:MediaCodecInfo, paramString:String):Boolean { + if (ApiLevel >= 29) { + return isSoftwareOnlyV29(paramMediaCodecInfo) + } + + val codecName = paramMediaCodecInfo.name.lowercase() + var isSoftware = false + + // 如果以"arc."开头,返回false(不是软件编解码器) + if (codecName.startsWith("arc.")) { + return false + } + + // 检查是否为已知的软件编解码器 + when { + codecName.startsWith("omx.google.") -> isSoftware = true + codecName.startsWith("omx.ffmpeg.") -> isSoftware = true + codecName.startsWith("omx.sec.") && codecName.contains(".sw.") -> isSoftware = true + codecName == "omx.qcom.video.decoder.hevcswvdec" -> isSoftware = true + codecName.startsWith("c2.android.") -> isSoftware = true + codecName.startsWith("c2.google.") -> isSoftware = true + // 如果不以"omx."或"c2."开头,也认为是软件编解码器 + !codecName.startsWith("omx.") && !codecName.startsWith("c2.") -> isSoftware = true + } + + return isSoftware + } + fun isSoftwareOnlyV29(paramMediaCodecInfo:MediaCodecInfo):Boolean { + return paramMediaCodecInfo.isSoftwareOnly + } + + + fun getPackageInfo(paramPackageManager: PackageManager): JSONObject { + val str1: String = getAppName() + val packageInfo = paramPackageManager.getPackageInfo(str1, 0) + val jSONObject = JSONObject() + var str2 = paramPackageManager.getInstallerPackageName(str1) + jSONObject.put("installer", str2) + var l = packageInfo.firstInstallTime + jSONObject.put("firstInstallTime", l) + l = packageInfo.lastUpdateTime + jSONObject.put("lastUpdateTime", l) + val i = packageInfo.versionCode + jSONObject.put("versionCode", i) + str2 = packageInfo.versionName + jSONObject.put("versionName", str2) + str2 = packageInfo.packageName + jSONObject.put("packageName", str2) + return jSONObject + } + + fun getConnectionType():String { + if (isUsingWifi()) { + return "wifi" + } + if (isActiveNetworkConnected()) { + return "cellular" + } + return "none" + } + + fun isUsingWifi():Boolean { + if (this.context == null) { + return false + } + val connectivityManager = + this.context!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + if (connectivityManager == null) { + return false + } + val telephonyManager = + this.context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + val networkInfo = connectivityManager.getActiveNetworkInfo() + if (networkInfo == null) { + return false + } + if (!connectivityManager.backgroundDataSetting) { + return false + } + val networkInfo1 = connectivityManager.activeNetworkInfo + if (networkInfo1 == null) { + return false + } + if (networkInfo1.isConnected && telephonyManager != null) { + + if (networkInfo.type == 1) { + return networkInfo.isConnected + } + return false + } + + return false + } + + fun isActiveNetworkConnected():Boolean { + if (this.context == null) { + return false + } + val connectivityManager = + this.context!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + if (connectivityManager == null) { + return false + } + val networkInfo = connectivityManager.activeNetworkInfo + return networkInfo != null && networkInfo.isConnected + } + + + fun getDisplayMetricDensity() : Float { + if(this.context == null) { + return -1.0f + } + return this.context!!.resources.displayMetrics.density + } + fun getElapsedRealtime() : Long { + return SystemClock.elapsedRealtime(); + } + fun getExtensionVersion():Int { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R) + } + return -1 + } + + fun getMemoryInfo(type:MemoryInfoType) : Long { + try { + val randomAccessFile = RandomAccessFile("/proc/meminfo","r") + var i = 1 + + randomAccessFile.use { + /** + * 1 total + * 2 free + */ + while (true) { + val memoryInfo = randomAccessFile.readLine() + if(memoryInfo.isNullOrEmpty()) { + break + } + if(i == 1 && type == MemoryInfoType.TOTAL_MEMORY) { + return getMemoryValueFromString(memoryInfo) + } + if(i == 2 && type == MemoryInfoType.FREE_MEMORY) { + return getMemoryValueFromString(memoryInfo) + } + if(i > 2) { + break + } + i++ + } + } + + } catch (e:Throwable) { + e.printStackTrace() + } + return 0 + } + + fun getNetworkCountryISO() : String{ + if(context == null) { + return "" + } + val telephonyManager = context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + return telephonyManager.networkCountryIso + } + fun getNetworkMetered() : Boolean { + if(context == null) { + return false + } + val connectivityManager = context!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + return connectivityManager.isActiveNetworkMetered + } + fun getNetworkOperator():String { + if(context == null) { + return "" + } + val telephonyManager = context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + return telephonyManager.networkOperator ?: "" + } + fun getNetworkOperatorName():String { + if(context == null) { + return "" + } + val telephonyManager = context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + return telephonyManager.networkOperatorName ?: "" + } + fun getNetworkType(): Int { + if(context == null) { + return -1 + } + val telephonyManager = context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + if (ActivityCompat.checkSelfPermission( + context, + Manifest.permission.READ_PHONE_STATE + ) != PackageManager.PERMISSION_GRANTED + ) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return -1 + } + return telephonyManager.getNetworkType() ?: -1 + } + fun getNewAbiList(): Array { + return Build.SUPPORTED_ABIS + } + fun getOldAbiList() : Array{ + val arrayList = mutableListOf() + arrayList.add(Build.CPU_ABI) + arrayList.add(Build.CPU_ABI2) + return arrayList.toTypedArray() + } + + fun isRooted():Boolean { + return searchPathForBinary("su") + } + + fun isAppDebuggable():Boolean { + val packageManager = this.context?.packageManager + val packageName = this.context?.packageName + val applicationInfo = packageName?.let { packageManager?.getApplicationInfo(it, 0) } + val j = applicationInfo!!.flags and 0x2 + if(j==0) { + return false + } + val packageInfo = packageManager?.getPackageInfo(packageName, 64) + val arrayOfSignature = packageInfo?.signatures + if (arrayOfSignature == null) { + return false + } + for (signature in arrayOfSignature) { + val certificateFactory = CertificateFactory.getInstance("X.509") + val byteArrayInputStream = ByteArrayInputStream(signature.toByteArray()) + val certificate: Certificate = certificateFactory.generateCertificate(byteArrayInputStream) + if (certificate is X509Certificate) { + val x500Principal1 = certificate.getSubjectX500Principal() + if (x500Principal1.equals(DEBUG_CERT)) { + return true + } + } + + + } + return false + } + + fun getLanguage() :String { + return Locale.getDefault().toString() + } + fun getAppVersion(): String? { + val str: String = this.context?.packageName ?: "" + val packageManager: PackageManager? = this.context?.packageManager + try { + val packageInfo1 = packageManager?.getPackageInfo(str, 0) + if (packageInfo1 != null) { + return packageInfo1.versionName + } + } catch (e: Throwable) { + e.printStackTrace() + } + return "" + } + fun getTimeZone() :String{ + val timeZone1 = TimeZone.getDefault() + val locale = Locale.US + return timeZone1.getDisplayName(false, 0, locale) + } + fun getTimeOffset() : Int{ + val timeZone = TimeZone.getDefault() + val l1 = System.currentTimeMillis() + return timeZone.getOffset(l1) / 1000 + } + + fun getWebViewUa() : String { + return WebSettings.getDefaultUserAgent(this.context) + } + + fun isWiredHeadsetOn(): Boolean { + val audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager + return audioManager.isWiredHeadsetOn + } + fun isUSBConnected():Boolean { + val intentFilter = IntentFilter("android.hardware.usb.action.USB_STATE") + val intent = context?.registerReceiver(null, intentFilter); + if (intent != null) { + return intent.getBooleanExtra("connected", false) + } + return false + } + fun getBatteryLevel(): Float { + if (context != null) { + val intentFilter = IntentFilter("android.intent.action.BATTERY_CHANGED") + var i = 0 + val intent = context!!.registerReceiver(null, intentFilter) + if (intent != null) { + i = -1 + val j = intent.getIntExtra("level", i) + i = intent.getIntExtra("scale", i) + val f1 = j.toFloat() + val f2 = i.toFloat() + return f1 / f2 + } + } + return -1.0f + } + private fun searchPathForBinary(exe:String):Boolean { + val str1 = System.getenv("PATH") ?: return false + val paths = str1.split(":") + for (path in paths) { + val file = File(path) + if(!file.exists()) { + continue + } + if(!file.isDirectory) { + continue + } + val arrayOfFile = file.listFiles() + if(arrayOfFile == null || arrayOfFile.isNotEmpty()) { + continue + } + for (it in arrayOfFile) { + if(it.name.equals(exe, ignoreCase = true)) { + return true + } + } + } + return false + } + + private fun getMemoryValueFromString(paramString: String?): Long { + if (paramString != null) { + val pattern: Pattern = Pattern.compile("(\\d+)") + val matcher: Matcher = pattern.matcher(paramString) + if (!matcher.find()) { + return -1L + } + val value: String = matcher.group(1) ?: return -1L + try { + return value.toLong() + } catch (e: NumberFormatException) { + e.printStackTrace() + } + } + return -1L + } + + + fun getDeviceInfoData():List { + val res = mutableListOf() + res.add(InfoItem("bundleId", this.getAppName())) + res.add(InfoItem("encrypted", this.isAppDebuggable().toString())) + res.add(InfoItem("rooted", "", callback = { this.isRooted().toString() })) + res.add(InfoItem("osVersion", this.getOsVersion())) + res.add(InfoItem("deviceModel", this.getModel())) + res.add(InfoItem("language", this.getLanguage())) + res.add(InfoItem("connectionType", this.getConnectionType())) + res.add(InfoItem("screenHeight", this.getScreenHeight().toString())) + res.add(InfoItem("screenWidth", this.getScreenWidth().toString())) + res.add(InfoItem("deviceMake", this.getManufacturer())) + res.add(InfoItem("screenDensity", this.getScreenDensity().toString())) + res.add(InfoItem("screenSize", this.getScreenLayout().toString())) + res.add(InfoItem("networkOperator", this.getNetworkOperator())) + res.add(InfoItem("networkOperatorName", this.getNetworkOperatorName())) + res.add(InfoItem("wiredHeadset", this.isWiredHeadsetOn().toString())) + res.add(InfoItem("volume", this.getStreamVolume(1).toString())) + res.add(InfoItem("deviceFreeSpace", this.getFreeSpace(this.context?.cacheDir).toString())) + res.add(InfoItem("apiLevel", this.ApiLevel.toString())) + res.add(InfoItem("networkType", this.getNetworkType().toString())) + res.add(InfoItem("networkMetered", this.getNetworkMetered().toString())) + res.add(InfoItem("bundleVersion", this.getAppVersion().toString())) + res.add(InfoItem("timeZone", this.getTimeZone())) + res.add(InfoItem("cpuCount", this.getCPUCount().toString())) + res.add(InfoItem("usbConnected", this.isUSBConnected().toString())) + res.add(InfoItem("timeZoneOffset", this.getTimeOffset().toString())) + res.add(InfoItem("webviewUa", this.getWebViewUa())) + res.add(InfoItem("apkDeveloperSigningCertificateHash", this.getCertificateFingerprint())) + res.add(InfoItem("deviceUpTime", this.getUptime().toString())) + res.add(InfoItem("deviceElapsedRealtime", this.getElapsedRealtime().toString())) + res.add(InfoItem("adbEnabled", this.isAdbEnabled().toString())) + res.add(InfoItem("androidFingerprint", this.getFingerprint())) + res.add(InfoItem("batteryStatus", this.getBatteryStatus().toString())) + res.add(InfoItem("batteryLevel", this.getBatteryLevel().toString())) + res.add(InfoItem("limitAdTracking","", callback = { this.LimitedAdTracking.toString() })) + + return res.toList() + } +} + diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/JsonSerializer.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/JsonSerializer.kt new file mode 100644 index 0000000..052d805 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/JsonSerializer.kt @@ -0,0 +1,22 @@ +package com.xyzshell.mydev.utils + +import kotlinx.serialization.json.Json +import kotlinx.serialization.encodeToString + + +class JsonSerializer { + companion object { + val json = Json { + prettyPrint = true + ignoreUnknownKeys = true + } + + inline fun toJson(obj: T): String { + return json.encodeToString(obj) + } + + inline fun fromJson(jsonString: String): T { + return json.decodeFromString(jsonString) + } + } +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/MemoryInfoType.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/MemoryInfoType.kt new file mode 100644 index 0000000..e20ccb6 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/MemoryInfoType.kt @@ -0,0 +1,5 @@ +package com.xyzshell.mydev.utils + +enum class MemoryInfoType { + FREE_MEMORY, TOTAL_MEMORY +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/ProtobufExtensionsKt.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/ProtobufExtensionsKt.kt new file mode 100644 index 0000000..0ca6f7a --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/ProtobufExtensionsKt.kt @@ -0,0 +1,49 @@ +package com.xyzshell.mydev.utils + +import android.util.Base64 +import com.google.protobuf.ByteString +import java.nio.charset.Charset +import java.util.UUID +import kotlin.jvm.internal.Intrinsics + + +class ProtobufExtensionsKt { + fun fromBase64(paramString: String?, paramBoolean: Boolean): ByteString { + val b = if (paramBoolean) { + 10 + } else { + 2 + } + val byteString: ByteString = ByteString.copyFrom(Base64.decode(paramString, b)) + Intrinsics.checkNotNullExpressionValue( + byteString, + "copyFrom(android.util.Base64.decode(this, flag))" + ) + return byteString + } + fun toISO8859String(paramByteString: ByteString): String { + val charset: Charset = Charsets.UTF_8 + val bytes = paramByteString.toByteArray() + //val str = paramByteString.toString(charset) + val str = String(bytes, charset) + return str + } + fun toUUID(paramByteString: ByteString): UUID? { + val byteBuffer = paramByteString.asReadOnlyByteBuffer() + var i = byteBuffer.remaining() + var b: Byte = 36 + if (i == b.toInt()) { + val uUID = UUID.fromString(paramByteString.toStringUtf8()) + return uUID + } + i = byteBuffer.remaining() + b = 16 + if (i == b.toInt()) { + val l1 = byteBuffer.getLong() + val l2 = byteBuffer.getLong() + val uUID = UUID(l1,l2) + return uUID + } + return null + } +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/SensorCollect.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/SensorCollect.kt new file mode 100644 index 0000000..5171053 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/SensorCollect.kt @@ -0,0 +1,58 @@ +package com.xyzshell.mydev.utils + +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import kotlin.math.abs +import kotlin.math.acos + +class SensorCollect(private val sensorManager: SensorManager): SensorEventListener { + private val sensor1:Sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)!! + private val sensor2:Sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)!! + private var gravityData: FloatArray? = null + private var gyroscopeData:Float = 1.3E-44F + init { + sensorManager.registerListener(this,sensor1,SensorManager.SENSOR_DELAY_NORMAL) + sensorManager.registerListener(this,sensor2,SensorManager.SENSOR_DELAY_NORMAL) + } + override fun onSensorChanged(event: SensorEvent?) { + val sensor: Sensor = event?.sensor ?: return + val i = sensor.type + if(i == Sensor.TYPE_GRAVITY) { + gravityData = event.values + } else { + var f1: Float = this.gyroscopeData + var f = 0.1f + f1 *= f + this.gyroscopeData = f1 + val arrayOfFloat1 = event.values + f = abs(arrayOfFloat1[0]) + val arrayOfFloat2 = event.values + var f2 = abs(arrayOfFloat2[1].toDouble()).toFloat() + f += f2 + val arrayOfFloat = event.values + val b1: Byte = 2 + f2 = 2.8E-45f + val f3: Float = abs(arrayOfFloat[b1.toInt()]) + f += f3 + f1 += f + this.gyroscopeData = f1 + } + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + TODO("Not yet implemented") + } + + fun getGravityData(): Float { + val arrayOfFloat: FloatArray? = this.gravityData + return if ((arrayOfFloat == null)) 0.0f else Math.toDegrees(acos((arrayOfFloat[2] / 9.81f).toDouble())) + .toFloat() + } + + fun getGyroscopeData(): Float { + return gyroscopeData + } + +} \ No newline at end of file diff --git a/mydev/src/main/java/com/xyzshell/mydev/utils/Utilities.kt b/mydev/src/main/java/com/xyzshell/mydev/utils/Utilities.kt new file mode 100644 index 0000000..00cd0a9 --- /dev/null +++ b/mydev/src/main/java/com/xyzshell/mydev/utils/Utilities.kt @@ -0,0 +1,43 @@ +package com.xyzshell.mydev.utils + +import java.io.ByteArrayOutputStream +import java.io.InputStream +import java.security.MessageDigest + +class Utilities { + companion object { + fun sha256(inputStream:InputStream):String { + if (inputStream == null) { + return "" + } + try { + val baos = ByteArrayOutputStream() + val messageDigest = MessageDigest.getInstance("SHA-256") + inputStream.use { + inputStream.copyTo(baos) + messageDigest.update(baos.toByteArray(), 0, baos.size()) + } + val hashBytes = messageDigest.digest() + return toHexString(hashBytes) + }catch (e:Throwable) { + e.printStackTrace() + } + return "" + } + + fun toHexString(byteBuffer:ByteArray):String { + // 將 byte 轉換爲 string + val strHexString = StringBuffer() + + // 遍歷 byte buffer + for (element in byteBuffer) { + val hex = Integer.toHexString(0xff and element.toInt()) + if (hex.length == 1) { + strHexString.append('0') + } + strHexString.append(hex) + } + return strHexString.toString() + } + } +} \ No newline at end of file diff --git a/mydev/src/main/res/drawable/ic_launcher_background.xml b/mydev/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/mydev/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mydev/src/main/res/drawable/ic_launcher_foreground.xml b/mydev/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/mydev/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mydev/src/main/res/mipmap-anydpi/ic_launcher.xml b/mydev/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/mydev/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mydev/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/mydev/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/mydev/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mydev/src/main/res/mipmap-hdpi/ic_launcher.webp b/mydev/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/mydev/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/mydev/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/mydev/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/mydev/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/mydev/src/main/res/mipmap-mdpi/ic_launcher.webp b/mydev/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/mydev/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/mydev/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/mydev/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/mydev/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/mydev/src/main/res/mipmap-xhdpi/ic_launcher.webp b/mydev/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/mydev/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/mydev/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/mydev/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/mydev/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/mydev/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/mydev/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/mydev/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/mydev/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/mydev/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/mydev/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/mydev/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/mydev/src/main/res/values-night/themes.xml b/mydev/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..e6d1d57 --- /dev/null +++ b/mydev/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/mydev/src/main/res/values/colors.xml b/mydev/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/mydev/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/mydev/src/main/res/values/strings.xml b/mydev/src/main/res/values/strings.xml new file mode 100644 index 0000000..5bd36e5 --- /dev/null +++ b/mydev/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MyDev + \ No newline at end of file diff --git a/mydev/src/main/res/values/themes.xml b/mydev/src/main/res/values/themes.xml new file mode 100644 index 0000000..f76a2e9 --- /dev/null +++ b/mydev/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/mydev/src/test/java/com/xyzshell/mydev/ExampleUnitTest.kt b/mydev/src/test/java/com/xyzshell/mydev/ExampleUnitTest.kt new file mode 100644 index 0000000..517061f --- /dev/null +++ b/mydev/src/test/java/com/xyzshell/mydev/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.xyzshell.mydev + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/myinfohook/.gitignore b/myinfohook/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/myinfohook/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/myinfohook/build.gradle.kts b/myinfohook/build.gradle.kts new file mode 100644 index 0000000..d7e0d22 --- /dev/null +++ b/myinfohook/build.gradle.kts @@ -0,0 +1,48 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "com.xyzshell.myinfohook" + compileSdk = 35 + + defaultConfig { + applicationId = "com.xyzshell.myinfohook" + minSdk = 31 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.xposed.api) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + +} \ No newline at end of file diff --git a/myinfohook/proguard-rules.pro b/myinfohook/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/myinfohook/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/myinfohook/src/androidTest/java/com/xyzshell/myinfohook/ExampleInstrumentedTest.kt b/myinfohook/src/androidTest/java/com/xyzshell/myinfohook/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..7699ba4 --- /dev/null +++ b/myinfohook/src/androidTest/java/com/xyzshell/myinfohook/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.xyzshell.myinfohook + +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.xyzshell.myinfohook", appContext.packageName) + } +} \ No newline at end of file diff --git a/myinfohook/src/main/AndroidManifest.xml b/myinfohook/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a4a1ef4 --- /dev/null +++ b/myinfohook/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/myinfohook/src/main/assets/xposed_init b/myinfohook/src/main/assets/xposed_init new file mode 100644 index 0000000..f4d210d --- /dev/null +++ b/myinfohook/src/main/assets/xposed_init @@ -0,0 +1 @@ +com.xyzshell.myinfohook.VungleHook \ No newline at end of file diff --git a/myinfohook/src/main/java/com/xyzshell/myinfohook/VungleHook.kt b/myinfohook/src/main/java/com/xyzshell/myinfohook/VungleHook.kt new file mode 100644 index 0000000..b567f54 --- /dev/null +++ b/myinfohook/src/main/java/com/xyzshell/myinfohook/VungleHook.kt @@ -0,0 +1,46 @@ +package com.xyzshell.myinfohook + +import de.robv.android.xposed.IXposedHookLoadPackage +import de.robv.android.xposed.XC_MethodHook +import de.robv.android.xposed.XposedBridge +import de.robv.android.xposed.XposedHelpers +import de.robv.android.xposed.callbacks.XC_LoadPackage + +class VungleHook: IXposedHookLoadPackage{ + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + val cls = "com.vungle.ads.internal.network.VungleApiImpl" + XposedBridge.log("VungleHook ads:$cls") + try { + val vungleApiImplCls = XposedHelpers.findClassIfExists(cls, lpparam.classLoader) + if (vungleApiImplCls == null) { + return + } + val commonRequestBody = lpparam.classLoader.loadClass("com.vungle.ads.internal.model.CommonRequestBody") + XposedHelpers.findAndHookMethod( + vungleApiImplCls, + "ads", + String::class.java, + String::class.java, + commonRequestBody, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + super.beforeHookedMethod(param) + try { + val pa1 = param.args[0] as String + val pa2 = param.args[1] as String + val body = param.args[2] + XposedBridge.log("vungle ads:$pa1") + XposedBridge.log("vungle ads:$pa2") + XposedBridge.log("vungle ads:$body") + } catch (e:Throwable) { + e.printStackTrace() + } + + } + } + ) + } catch (e:Throwable) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/myinfohook/src/main/res/drawable/ic_launcher_background.xml b/myinfohook/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/myinfohook/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/myinfohook/src/main/res/drawable/ic_launcher_foreground.xml b/myinfohook/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/myinfohook/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/myinfohook/src/main/res/mipmap-anydpi/ic_launcher.xml b/myinfohook/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/myinfohook/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/myinfohook/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/myinfohook/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/myinfohook/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/myinfohook/src/main/res/mipmap-hdpi/ic_launcher.webp b/myinfohook/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/myinfohook/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/myinfohook/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/myinfohook/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/myinfohook/src/main/res/mipmap-mdpi/ic_launcher.webp b/myinfohook/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/myinfohook/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/myinfohook/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/myinfohook/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher.webp b/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/myinfohook/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/myinfohook/src/main/res/values-night/themes.xml b/myinfohook/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..e6d1d57 --- /dev/null +++ b/myinfohook/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/myinfohook/src/main/res/values/arrays.xml b/myinfohook/src/main/res/values/arrays.xml new file mode 100644 index 0000000..c71d75a --- /dev/null +++ b/myinfohook/src/main/res/values/arrays.xml @@ -0,0 +1,7 @@ + + + + + com.apps.chillscreen + + \ No newline at end of file diff --git a/myinfohook/src/main/res/values/colors.xml b/myinfohook/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/myinfohook/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/myinfohook/src/main/res/values/strings.xml b/myinfohook/src/main/res/values/strings.xml new file mode 100644 index 0000000..799a7b1 --- /dev/null +++ b/myinfohook/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MyInfoHook + \ No newline at end of file diff --git a/myinfohook/src/main/res/values/themes.xml b/myinfohook/src/main/res/values/themes.xml new file mode 100644 index 0000000..f76a2e9 --- /dev/null +++ b/myinfohook/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/myinfohook/src/test/java/com/xyzshell/myinfohook/ExampleUnitTest.kt b/myinfohook/src/test/java/com/xyzshell/myinfohook/ExampleUnitTest.kt new file mode 100644 index 0000000..5a51942 --- /dev/null +++ b/myinfohook/src/test/java/com/xyzshell/myinfohook/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.xyzshell.myinfohook + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/myphoneinfo/.gitignore b/myphoneinfo/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/myphoneinfo/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/myphoneinfo/andinfo/.gitignore b/myphoneinfo/andinfo/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/myphoneinfo/andinfo/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/myphoneinfo/andinfo/build.gradle.kts b/myphoneinfo/andinfo/build.gradle.kts new file mode 100644 index 0000000..5a81721 --- /dev/null +++ b/myphoneinfo/andinfo/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "com.xyzshell.andinfo" + compileSdk = 35 + + defaultConfig { + minSdk = 31 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.koin.core) + implementation(libs.koin.android) + implementation(libs.androidx.datastore.preferences) + // implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7") + implementation(libs.androidx.datastore) + // implementation("androidx.datastore:datastore-rxjava3:1.1.7") + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/consumer-rules.pro b/myphoneinfo/andinfo/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/myphoneinfo/andinfo/proguard-rules.pro b/myphoneinfo/andinfo/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/myphoneinfo/andinfo/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/androidTest/java/com/xyzshell/andinfo/ExampleInstrumentedTest.kt b/myphoneinfo/andinfo/src/androidTest/java/com/xyzshell/andinfo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..5cf527c --- /dev/null +++ b/myphoneinfo/andinfo/src/androidTest/java/com/xyzshell/andinfo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.xyzshell.andinfo + +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.xyzshell.andinfo.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/AndroidManifest.xml b/myphoneinfo/andinfo/src/main/AndroidManifest.xml new file mode 100644 index 0000000..09f32ab --- /dev/null +++ b/myphoneinfo/andinfo/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt new file mode 100644 index 0000000..ecb11b1 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt @@ -0,0 +1,24 @@ +package com.xyzshell.andinfo + +import com.xyzshell.andinfo.libs.CpuInfo + +class AndInfo private constructor() { + + companion object { + val instance = SingletonHolder.holder + } + + private object SingletonHolder { + val holder= AndInfo() + } + + private val _cpu: CpuInfo + init { + _cpu = CpuInfo() + + } + + val cpu get() = _cpu + + +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfoApp.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfoApp.kt new file mode 100644 index 0000000..5988190 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfoApp.kt @@ -0,0 +1,19 @@ +package com.xyzshell.andinfo + +import android.app.Application +import com.xyzshell.andinfo.di.androidModule + +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin + +class AndInfoApp : Application() { + override fun onCreate() { + super.onCreate() + startKoin { + androidContext(this@AndInfoApp) + modules( + androidModule, + ) + } + } +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/di/AndroidModule.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/di/AndroidModule.kt new file mode 100644 index 0000000..2c559d2 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/di/AndroidModule.kt @@ -0,0 +1,48 @@ +package com.xyzshell.andinfo.di + +import android.annotation.SuppressLint +import android.app.ActivityManager +import android.app.admin.DevicePolicyManager +import android.content.Context +import android.hardware.SensorManager +import android.hardware.camera2.CameraManager +import android.net.wifi.WifiManager +import android.os.storage.StorageManager +import android.view.WindowManager +import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.emptyPreferences +import androidx.datastore.preferences.preferencesDataStoreFile + +import org.koin.android.ext.koin.androidContext +// import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + + +const val USER_PREFERENCES_NAME = "user_preferences" + +@SuppressLint("WifiManagerLeak") +val androidModule = module { + single { androidContext().resources } + single { androidContext().packageManager } + single { androidContext().contentResolver } + single { androidContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager } + single { + androidContext().getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager + } + single { androidContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager } + single { androidContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager } + single { androidContext().getSystemService(Context.WIFI_SERVICE) as WifiManager } + single { androidContext().getSystemService(Context.STORAGE_SERVICE) as StorageManager } + single { androidContext().getSystemService(Context.CAMERA_SERVICE) as CameraManager } + single { + PreferenceDataStoreFactory.create( + corruptionHandler = ReplaceFileCorruptionHandler( + produceNewData = { emptyPreferences() }, + ), + produceFile = { + androidContext().preferencesDataStoreFile(USER_PREFERENCES_NAME) + }, + ) + } +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt new file mode 100644 index 0000000..efd2d95 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt @@ -0,0 +1,33 @@ +package com.xyzshell.andinfo.libs + +import android.os.Build +import android.util.Log + +class CpuInfo { + private val cores: Int = 0 + + init { + + } + fun text() : String { + val sb = StringBuilder() + ReadFile().also { + it.read( + "/proc/cpuinfo", + { line:String, idx:Int -> + sb.appendLine(line) + false + } + ) + } + val res = sb.toString() + Log.i("[AND INFO]", res) + return res + } + fun cores() : Int { + return Runtime.getRuntime().availableProcessors() + } + fun hardware() : String { + return Build.HARDWARE + } +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt new file mode 100644 index 0000000..8b0e8fe --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt @@ -0,0 +1,4 @@ +package com.xyzshell.andinfo.libs + +class MemInfo { +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/ReadFile.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/ReadFile.kt new file mode 100644 index 0000000..0e164f8 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/ReadFile.kt @@ -0,0 +1,30 @@ +package com.xyzshell.andinfo.libs + +import java.io.RandomAccessFile + +typealias ReadFileCallback = (line:String, index: Int) -> Boolean + +class ReadFile { + fun read(path: String, callback: ReadFileCallback) { + try { + val randomAccessFile = RandomAccessFile(path,"r") + var i = 0 + + randomAccessFile.use { + while (true) { + val line = randomAccessFile.readLine() + if(line == null) { + break + } + if(callback(line, i)){ + break + } + i++ + } + } + + } catch (e:Throwable) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/myphoneinfo/andinfo/src/test/java/com/xyzshell/andinfo/ExampleUnitTest.kt b/myphoneinfo/andinfo/src/test/java/com/xyzshell/andinfo/ExampleUnitTest.kt new file mode 100644 index 0000000..482ef1e --- /dev/null +++ b/myphoneinfo/andinfo/src/test/java/com/xyzshell/andinfo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.xyzshell.andinfo + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/myphoneinfo/build.gradle.kts b/myphoneinfo/build.gradle.kts new file mode 100644 index 0000000..bf15744 --- /dev/null +++ b/myphoneinfo/build.gradle.kts @@ -0,0 +1,73 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.compose.compiler) +} + +android { + namespace = "com.xyzshell.myphoneinfo" + compileSdk = 35 + + defaultConfig { + applicationId = "com.xyzshell.myphoneinfo" + minSdk = 31 + //noinspection OldTargetApi + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + 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 { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.5.1" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(project("andinfo")) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/myphoneinfo/proguard-rules.pro b/myphoneinfo/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/myphoneinfo/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/myphoneinfo/src/androidTest/java/com/xyzshell/myphoneinfo/ExampleInstrumentedTest.kt b/myphoneinfo/src/androidTest/java/com/xyzshell/myphoneinfo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..796e85b --- /dev/null +++ b/myphoneinfo/src/androidTest/java/com/xyzshell/myphoneinfo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.xyzshell.myphoneinfo + +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.xyzshell.myphoneinfo", appContext.packageName) + } +} \ No newline at end of file diff --git a/myphoneinfo/src/main/AndroidManifest.xml b/myphoneinfo/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1145c8b --- /dev/null +++ b/myphoneinfo/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt new file mode 100644 index 0000000..9fc283d --- /dev/null +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt @@ -0,0 +1,96 @@ +package com.xyzshell.myphoneinfo + +import android.app.AlertDialog +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.xyzshell.myphoneinfo.ui.theme.MyAndriodInfoTheme +import com.xyzshell.andinfo.AndInfo + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + MyAndriodInfoTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + MainView( + name = "DevCheck Clone", + modifier = Modifier.padding(innerPadding) + ) + } + } + } + + } + +} + +@Composable +fun MainView(name: String, modifier: Modifier = Modifier) { + val showDialog = remember { mutableStateOf(false) } + Column (modifier){ + Box(modifier = Modifier.fillMaxWidth()){ + Text(text = name, Modifier.align(Alignment.Center)) + } + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + Text("硬件:${AndInfo.instance.cpu.hardware()}") + Text("核心数:${AndInfo.instance.cpu.cores()}") + Button(onClick = {showDialog.value = true}) { Text("cpu") } + } + } + if (showDialog.value) { + AlertDialog( + onDismissRequest = { showDialog.value = false }, + title = { Text(text = "标题") }, + text = { Text(text = AndInfo.instance.cpu.text()) }, + confirmButton = { + TextButton(onClick = { showDialog.value = false }) { + Text("确认") + } + }, + dismissButton = { + TextButton(onClick = { showDialog.value = false }) { + Text("取消") + } + } + ) + } +} + + + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + MyAndriodInfoTheme { + MainView("Android") + } +} \ No newline at end of file diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Color.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Color.kt new file mode 100644 index 0000000..2ea8c10 --- /dev/null +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.xyzshell.myphoneinfo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Theme.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Theme.kt new file mode 100644 index 0000000..ce522f6 --- /dev/null +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.xyzshell.myphoneinfo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun MyAndriodInfoTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Type.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Type.kt new file mode 100644 index 0000000..087b4ec --- /dev/null +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.xyzshell.myphoneinfo.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/myphoneinfo/src/main/res/drawable/ic_launcher_background.xml b/myphoneinfo/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/myphoneinfo/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/myphoneinfo/src/main/res/drawable/ic_launcher_foreground.xml b/myphoneinfo/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/myphoneinfo/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher.xml b/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/myphoneinfo/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher.webp b/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher.webp b/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher.webp b/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/myphoneinfo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/myphoneinfo/src/main/res/values/colors.xml b/myphoneinfo/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/myphoneinfo/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/myphoneinfo/src/main/res/values/strings.xml b/myphoneinfo/src/main/res/values/strings.xml new file mode 100644 index 0000000..c2f4eb1 --- /dev/null +++ b/myphoneinfo/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MyPhoneInfo + \ No newline at end of file diff --git a/myphoneinfo/src/main/res/values/themes.xml b/myphoneinfo/src/main/res/values/themes.xml new file mode 100644 index 0000000..62e72b9 --- /dev/null +++ b/myphoneinfo/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +