From a69f7732b025c79a335abb5d77708533e62eea3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=94=E5=BE=B7=E8=85=BE?= Date: Fri, 16 Aug 2019 11:33:31 +0800 Subject: [PATCH] Initial commit --- .idea/vcs.xml | 6 + DKit.iml | 19 + DebugKit.iml | 19 + app/.gitignore | 1 + app/app.iml | 162 ++++++ app/build.gradle | 36 ++ app/proguard-rules.pro | 21 + .../Demo/ExampleInstrumentedTest.java | 27 + app/src/main/AndroidManifest.xml | 22 + .../devkit/DebugKit/Demo/MainActivity.java | 39 ++ .../java/vip/devkit/DebugKit/Demo/PDF.java | 43 ++ .../drawable-v24/ic_launcher_foreground.xml | 34 ++ .../res/drawable/ic_launcher_background.xml | 170 ++++++ app/src/main/res/drawable/shape_debug.xml | 7 + app/src/main/res/layout/activity_main.xml | 33 ++ app/src/main/res/layout/activity_pdf.xml | 29 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 11 + .../devkit/DebugKit/Demo/ExampleUnitTest.java | 17 + build.gradle | 28 + dklib/.gitignore | 1 + dklib/build.gradle | 34 ++ dklib/dklib.iml | 147 +++++ dklib/proguard-rules.pro | 21 + .../debugkit/ExampleInstrumentedTest.java | 27 + dklib/src/main/AndroidManifest.xml | 48 ++ .../content/pm/IPackageStatsObserver.aidl | 14 + .../aidl/android/content/pm/PackageStats.aidl | 3 + .../content/pm/IPackageStatsObserver.aidl | 14 + .../java/android/content/pm/PackageStats.aidl | 3 + .../java/vip/devkit/debugkit/DataSource.java | 199 +++++++ .../devkit/debugkit/DebugKitFileProvider.java | 17 + .../java/vip/devkit/debugkit/KitAdapter.java | 49 ++ .../devkit/debugkit/KitManagerAdapter.java | 41 ++ .../adapter/BaseUrlManagerAdapter.java | 67 +++ .../debugkit/adapter/CrashListAdapter.java | 62 +++ .../debugkit/adapter/FileFolderAdapter.java | 34 ++ .../debugkit/adapter/FileInfoAdapter.java | 56 ++ .../adapter/PermissionManagerAdapter.java | 39 ++ .../vip/devkit/debugkit/bean/AppInfoBean.java | 281 ++++++++++ .../devkit/debugkit/bean/CrashInfoBean.java | 26 + .../devkit/debugkit/bean/FileInfoBean.java | 22 + .../devkit/debugkit/bean/PermissionInfo.java | 15 + .../vip/devkit/debugkit/kit/Category.java | 25 + .../vip/devkit/debugkit/kit/GroupKitItem.java | 30 + .../java/vip/devkit/debugkit/kit/IKit.java | 31 ++ .../java/vip/devkit/debugkit/kit/KitItem.java | 23 + .../debugkit/kit/crash/CacheConfig.java | 27 + .../devkit/debugkit/kit/crash/CacheUtils.java | 115 ++++ .../kit/crash/CrashCaptureManager.java | 126 +++++ .../devkit/debugkit/kit/debug/AppInfo.java | 49 ++ .../debugkit/kit/debug/BaseUrlManger.java | 50 ++ .../debugkit/kit/debug/CachesManager.java | 50 ++ .../debugkit/kit/debug/CrashManger.java | 53 ++ .../devkit/debugkit/kit/debug/DataExport.java | 46 ++ .../debugkit/kit/debug/FileExplorer.java | 50 ++ .../devkit/debugkit/kit/debug/LogManager.java | 47 ++ .../debugkit/kit/debug/PermissionManager.java | 47 ++ .../devkit/debugkit/kit/debug/Simulation.java | 47 ++ .../devkit/debugkit/kit/debug/WebBrowse.java | 47 ++ .../debugkit/kit/developer/Language.java | 15 + .../debugkit/kit/developer/RuningService.java | 15 + .../debugkit/kit/developer/SystemSetting.java | 15 + .../devkit/debugkit/kit/developer/USBKit.java | 47 ++ .../vip/devkit/debugkit/kit/log/IPrinter.java | 73 +++ .../vip/devkit/debugkit/kit/log/LogCat.java | 113 ++++ .../devkit/debugkit/kit/log/LogConfig.java | 45 ++ .../vip/devkit/debugkit/kit/log/LogLevel.java | 39 ++ .../devkit/debugkit/kit/log/LogPrinter.java | 327 +++++++++++ .../vip/devkit/debugkit/kit/log/Util.java | 104 ++++ .../debugkit/kit/performance/Battery.java | 46 ++ .../devkit/debugkit/kit/performance/CPU.java | 46 ++ .../devkit/debugkit/kit/performance/FTPS.java | 46 ++ .../devkit/debugkit/kit/performance/RAM.java | 46 ++ .../devkit/debugkit/kit/performance/Time.java | 46 ++ .../debugkit/kit/performance/Traffic.java | 46 ++ .../devkit/debugkit/kit/system/CpuKit.java | 46 ++ .../debugkit/kit/system/HardwareKit.java | 47 ++ .../debugkit/kit/system/NetworkKit.java | 50 ++ .../devkit/debugkit/kit/system/ScreenKit.java | 50 ++ .../devkit/debugkit/kit/system/SysInfo.java | 53 ++ .../devkit/debugkit/kit/ue/ColorPicker.java | 46 ++ .../java/vip/devkit/debugkit/kit/ue/UE.java | 46 ++ .../debugkit/ui/AppDataCleanActivity.java | 36 ++ .../ui/FileExplorer/FileExplorerActivity.java | 250 +++++++++ .../debugkit/ui/KitManagerActivity.java | 95 ++++ .../devkit/debugkit/ui/base/BaseActivity.java | 222 ++++++++ .../devkit/debugkit/ui/base/BaseFragment.java | 143 +++++ .../ui/base/GCBaseExpandableListAdapter.java | 121 ++++ .../devkit/debugkit/ui/base/ViewHolder.java | 142 +++++ .../debugkit/ui/base_url/BaseUrlManager.java | 115 ++++ .../ui/base_url/BaseUrlManagerActivity.java | 131 +++++ .../debugkit/ui/base_url/BaseUrlUtil.java | 221 ++++++++ .../debugkit/ui/base_url/IBaseUrlManager.java | 79 +++ .../devkit/debugkit/ui/base_url/UrlInfo.java | 138 +++++ .../ui/crash/CrashManagerActivity.java | 103 ++++ .../devkit/debugkit/ui/debug/AppInfoM.java | 127 +++++ .../ui/permission/PermissionData.java | 171 ++++++ .../permission/PermissionManagerActivity.java | 150 +++++ .../debugkit/ui/sysinfo/SysInfoActivity.java | 15 + .../debugkit/ui/sysinfo/SysInfoKit.java | 197 +++++++ .../vip/devkit/debugkit/util/AppUtil.java | 58 ++ .../java/vip/devkit/debugkit/util/Comm.java | 35 ++ .../devkit/debugkit/util/DataCleanUtil.java | 105 ++++ .../vip/devkit/debugkit/util/DeviceUtils.java | 457 +++++++++++++++ .../vip/devkit/debugkit/util/FileUtil.java | 248 +++++++++ .../vip/devkit/debugkit/util/NetUtils.java | 283 ++++++++++ .../vip/devkit/debugkit/util/ResUtil.java | 24 + .../java/vip/devkit/debugkit/widget/a.java | 15 + .../recyclerview/BaseRecyclerAdapter.java | 128 +++++ .../widget/recyclerview/BaseViewHolder.java | 519 ++++++++++++++++++ .../recyclerview/DividerItemDecoration.java | 138 +++++ .../debugkit/widget/recyclerview/S.java | 33 ++ .../drawable/shape_group_kit_background.xml | 6 + dklib/src/main/res/layout/act_kit_manager.xml | 16 + .../main/res/layout/dk_activity_base_url.xml | 46 ++ .../src/main/res/layout/dk_activity_crash.xml | 34 ++ .../res/layout/dk_activity_file_explorer.xml | 36 ++ dklib/src/main/res/layout/dk_activity_rv.xml | 20 + .../src/main/res/layout/dk_item_base_url.xml | 28 + dklib/src/main/res/layout/dk_item_crash.xml | 59 ++ dklib/src/main/res/layout/dk_item_file.xml | 48 ++ .../main/res/layout/dk_item_file_folder.xml | 14 + .../src/main/res/layout/dk_item_group_kit.xml | 27 + dklib/src/main/res/layout/dk_item_kit.xml | 23 + .../main/res/layout/dk_item_permission.xml | 40 ++ .../res/layout/dk_view_common_divider.xml | 10 + .../main/res/layout/dk_view_common_title.xml | 62 +++ .../main/res/mipmap-xxhdpi/dk_app_info.png | Bin 0 -> 2084 bytes .../main/res/mipmap-xxhdpi/dk_base_url.png | Bin 0 -> 1480 bytes .../main/res/mipmap-xxhdpi/dk_crash_catch.png | Bin 0 -> 5318 bytes .../res/mipmap-xxhdpi/dk_crash_permission.png | Bin 0 -> 1524 bytes .../main/res/mipmap-xxhdpi/dk_data_clean.png | Bin 0 -> 3302 bytes .../main/res/mipmap-xxhdpi/dk_data_export.png | Bin 0 -> 1371 bytes .../src/main/res/mipmap-xxhdpi/dk_file_db.png | Bin 0 -> 1717 bytes .../res/mipmap-xxhdpi/dk_file_explorer.png | Bin 0 -> 2825 bytes .../main/res/mipmap-xxhdpi/dk_file_folder.png | Bin 0 -> 540 bytes .../main/res/mipmap-xxhdpi/dk_file_img.png | Bin 0 -> 756 bytes .../main/res/mipmap-xxhdpi/dk_file_ohter.png | Bin 0 -> 970 bytes .../main/res/mipmap-xxhdpi/dk_file_txt.png | Bin 0 -> 945 bytes .../main/res/mipmap-xxhdpi/dk_log_info.png | Bin 0 -> 1819 bytes .../main/res/mipmap-xxhdpi/dk_more_down.png | Bin 0 -> 589 bytes .../src/main/res/mipmap-xxhdpi/dk_more_up.png | Bin 0 -> 535 bytes .../main/res/mipmap-xxhdpi/dk_right_more.png | Bin 0 -> 486 bytes dklib/src/main/res/mipmap/dk_icon_back.png | Bin 0 -> 438 bytes dklib/src/main/res/values/color.xml | 18 + dklib/src/main/res/values/dimens.xml | 24 + dklib/src/main/res/values/strings.xml | 71 +++ .../vip/devkit/debugkit/ExampleUnitTest.java | 17 + gradle.properties | 20 + gradlew | 172 ++++++ gradlew.bat | 84 +++ settings.gradle | 1 + 166 files changed, 9608 insertions(+) create mode 100644 .idea/vcs.xml create mode 100644 DKit.iml create mode 100644 DebugKit.iml create mode 100644 app/.gitignore create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/vip/devkit/DebugKit/Demo/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/vip/devkit/DebugKit/Demo/MainActivity.java create mode 100644 app/src/main/java/vip/devkit/DebugKit/Demo/PDF.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/shape_debug.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_pdf.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/vip/devkit/DebugKit/Demo/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 dklib/.gitignore create mode 100644 dklib/build.gradle create mode 100644 dklib/dklib.iml create mode 100644 dklib/proguard-rules.pro create mode 100644 dklib/src/androidTest/java/vip/devkit/debugkit/ExampleInstrumentedTest.java create mode 100644 dklib/src/main/AndroidManifest.xml create mode 100644 dklib/src/main/aidl/android/content/pm/IPackageStatsObserver.aidl create mode 100644 dklib/src/main/aidl/android/content/pm/PackageStats.aidl create mode 100644 dklib/src/main/java/android/content/pm/IPackageStatsObserver.aidl create mode 100644 dklib/src/main/java/android/content/pm/PackageStats.aidl create mode 100644 dklib/src/main/java/vip/devkit/debugkit/DataSource.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/DebugKitFileProvider.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/KitAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/KitManagerAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/adapter/BaseUrlManagerAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/adapter/CrashListAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/adapter/FileFolderAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/adapter/FileInfoAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/adapter/PermissionManagerAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/bean/AppInfoBean.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/bean/CrashInfoBean.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/bean/FileInfoBean.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/bean/PermissionInfo.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/Category.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/GroupKitItem.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/IKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/KitItem.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheConfig.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheUtils.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/crash/CrashCaptureManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/AppInfo.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/BaseUrlManger.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/CachesManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/CrashManger.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/DataExport.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/FileExplorer.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/LogManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/PermissionManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/Simulation.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/debug/WebBrowse.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/developer/Language.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/developer/RuningService.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/developer/SystemSetting.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/developer/USBKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/IPrinter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/LogCat.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/LogConfig.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/LogLevel.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/LogPrinter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/log/Util.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/Battery.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/CPU.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/FTPS.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/RAM.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/Time.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/performance/Traffic.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/system/CpuKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/system/HardwareKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/system/NetworkKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/system/ScreenKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/system/SysInfo.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/ue/ColorPicker.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/kit/ue/UE.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/AppDataCleanActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/FileExplorer/FileExplorerActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/KitManagerActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseFragment.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base/GCBaseExpandableListAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base/ViewHolder.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManagerActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlUtil.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base_url/IBaseUrlManager.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/base_url/UrlInfo.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/crash/CrashManagerActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/debug/AppInfoM.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionData.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionManagerActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoActivity.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoKit.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/AppUtil.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/Comm.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/DataCleanUtil.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/DeviceUtils.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/FileUtil.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/NetUtils.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/util/ResUtil.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/widget/a.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseRecyclerAdapter.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseViewHolder.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/DividerItemDecoration.java create mode 100644 dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/S.java create mode 100644 dklib/src/main/res/drawable/shape_group_kit_background.xml create mode 100644 dklib/src/main/res/layout/act_kit_manager.xml create mode 100644 dklib/src/main/res/layout/dk_activity_base_url.xml create mode 100644 dklib/src/main/res/layout/dk_activity_crash.xml create mode 100644 dklib/src/main/res/layout/dk_activity_file_explorer.xml create mode 100644 dklib/src/main/res/layout/dk_activity_rv.xml create mode 100644 dklib/src/main/res/layout/dk_item_base_url.xml create mode 100644 dklib/src/main/res/layout/dk_item_crash.xml create mode 100644 dklib/src/main/res/layout/dk_item_file.xml create mode 100644 dklib/src/main/res/layout/dk_item_file_folder.xml create mode 100644 dklib/src/main/res/layout/dk_item_group_kit.xml create mode 100644 dklib/src/main/res/layout/dk_item_kit.xml create mode 100644 dklib/src/main/res/layout/dk_item_permission.xml create mode 100644 dklib/src/main/res/layout/dk_view_common_divider.xml create mode 100644 dklib/src/main/res/layout/dk_view_common_title.xml create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_app_info.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_base_url.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_crash_catch.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_crash_permission.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_data_clean.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_data_export.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_db.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_explorer.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_folder.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_img.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_ohter.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_file_txt.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_log_info.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_more_down.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_more_up.png create mode 100644 dklib/src/main/res/mipmap-xxhdpi/dk_right_more.png create mode 100644 dklib/src/main/res/mipmap/dk_icon_back.png create mode 100644 dklib/src/main/res/values/color.xml create mode 100644 dklib/src/main/res/values/dimens.xml create mode 100644 dklib/src/main/res/values/strings.xml create mode 100644 dklib/src/test/java/vip/devkit/debugkit/ExampleUnitTest.java create mode 100644 gradle.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DKit.iml b/DKit.iml new file mode 100644 index 0000000..1cbfb92 --- /dev/null +++ b/DKit.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DebugKit.iml b/DebugKit.iml new file mode 100644 index 0000000..d51aceb --- /dev/null +++ b/DebugKit.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..0038a61 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..ab6a8f8 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.0" + defaultConfig { + applicationId "vip.devkit.DebugKit.Demo" + minSdkVersion 19 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation project(':dklib') + + api 'com.joanzapata.pdfview:android-pdfview:1.0.4@aar' + + + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /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 diff --git a/app/src/androidTest/java/vip/devkit/DebugKit/Demo/ExampleInstrumentedTest.java b/app/src/androidTest/java/vip/devkit/DebugKit/Demo/ExampleInstrumentedTest.java new file mode 100644 index 0000000..3aaf7fd --- /dev/null +++ b/app/src/androidTest/java/vip/devkit/DebugKit/Demo/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package vip.devkit.DebugKit.Demo; + +import android.content.Context; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("vip.devkit.DebugKit.Demo", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e1e74e6 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/vip/devkit/DebugKit/Demo/MainActivity.java b/app/src/main/java/vip/devkit/DebugKit/Demo/MainActivity.java new file mode 100644 index 0000000..6c0a83b --- /dev/null +++ b/app/src/main/java/vip/devkit/DebugKit/Demo/MainActivity.java @@ -0,0 +1,39 @@ +package vip.devkit.DebugKit.Demo; + +import android.Manifest; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import vip.devkit.debugkit.ui.KitManagerActivity; + +public class MainActivity extends AppCompatActivity { + + /** + * Debug + */ + private TextView mTvDebug; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + initView(); + + } + + private void initView() { + mTvDebug = (TextView) findViewById(R.id.tv_debug); + mTvDebug.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(MainActivity.this, KitManagerActivity.class); + startActivity(intent); + String[] permissions=new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; + } + }); + } +} diff --git a/app/src/main/java/vip/devkit/DebugKit/Demo/PDF.java b/app/src/main/java/vip/devkit/DebugKit/Demo/PDF.java new file mode 100644 index 0000000..e763d27 --- /dev/null +++ b/app/src/main/java/vip/devkit/DebugKit/Demo/PDF.java @@ -0,0 +1,43 @@ +package vip.devkit.DebugKit.Demo; + +import android.os.Bundle; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.joanzapata.pdfview.PDFView; + +/** + * Package Name: vip.devkit.DebugKit.Demo + * File Name: PDF.java + * Create Date: 2019/7/5 16:51 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PDF extends AppCompatActivity { + + + private PDFView mPdfView; + /** + * Debug + */ + private TextView mTvDebug; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pdf); + initView(); + } + + private void initView() { + mPdfView = (PDFView) findViewById(R.id.pdf_view); + mTvDebug = (TextView) findViewById(R.id.tv_debug); + + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + 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..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/shape_debug.xml b/app/src/main/res/drawable/shape_debug.xml new file mode 100644 index 0000000..024d9bc --- /dev/null +++ b/app/src/main/res/drawable/shape_debug.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file 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..dc38795 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,33 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_pdf.xml b/app/src/main/res/layout/activity_pdf.xml new file mode 100644 index 0000000..07aa4e3 --- /dev/null +++ b/app/src/main/res/layout/activity_pdf.xml @@ -0,0 +1,29 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..898f3ed59ac9f3248734a00e5902736c9367d455 GIT binary patch literal 2963 zcmV;E3vBd>P)a+K}1d8+^p? z!e{m!F(8(%L-Or7x3OYORF&;mRAm8a^;km%J=s!AdNyc=+ezQqUM;oHYO18U%`T}O zHf$ra^L^sklEoIeAKmbOvX~v2@Y|vHs<^3JwwH?D$4l*XnPNs zMOqozmbkT?^lZ?$DjQ9%E0x+GsV=1PwZ&39Y}iI-$Fb3d%nsk+qrN@cV=OmQMEdF% z)iHMl(4Yu=cIkixWXtwMIV=>BvDSrHg8?)+vLJKozy*}$iE>&gGGonlG0cJhG&DRv ztzkg-AO(q)B7~G^EwE#tK@nqmJ}!(Bqtf z=eN{I?X#P!Xx=uL)D9cAk=b!~&@H~6S)=a?R4fDdP{-5E5X_!5&FwFJ^7&W2WS z;CnxBCOsSU^v-%(vad;MPukr;&+ciI+F`>sGCPiqHe`1A1|N0p^<|#<+iECwOG@y7 zBF$;;0YAhxtqK7O0SW;M0SW;ckbsQ#9QTYyC*g`2j%bA%1Zh^g9=9l*Cy!I^{_p2$PP2>j_D2AybM$NwY}iJ(ZH9O3 zlM8g4+dw;}V{dlY2EM^Z-Q(AmcmO|Ub1&3EFTS>iuHC#rcNo$wkB3@5c#lSunxsQ) zaA7tLFV3Oxk}X2`9qVL6?4fcq?f>Yk0E0IEcm0~^P5ovLLV$&D9ibbZTOt4ivg_<= zu^#q8tYJktl(egXwj4c3u6N&}S3mj_9pv5y{gQvL;&nM}TeNE{4K3O%_QAdpCAswa z`Ev>!oQREY9uPqL)g(QPVc1U`Q3An`+x_7g8edZ^0zdcpXNv7^!ZsgV{ugB){w+5&3-Wlp}yI7?tN)6*ST)-XSL4g8_rtDVlw+a zE+K|#(tV!KfQE22d-}7B(mLkHukIp4?na@q?%@4Kb%u!@F-ww?o?tn_Ohb zPi3Do`yL?Y$rDPYtEV;|250yzpS^rZT*TflAZ&YqC;by2Ul7NTZHKmC)9NA6Vv+>C%^1XhNlp5*!7zxTTKfHTPhe?@XbH=VzWEuCcmX z@L_&qCB;=(Xi;-D&DvT)kGOiMQ0&YQTezdH&j4D;U@#9&WiZClJThS7w)OHH^fIT| z+jn{&5bhMbynmM$P<0U*%ksp0WUy)=J!n9~WJ&YNn$e3{jMFOW6n~uqMHg+M3FY|#>(q)ZF;RS(xqTh>S1Ez_jfFig z#ivbPnZ26mv{5wdB5SFYrUNM5D?g-OsiZZK?hPof9gqf&7m!5-C=d>yOsw<)(t*G@h5zIY2saaEx|99pU%^#gvdI(Qqf>)zFjf zN}5zm9~oT`PmH~EF012{9eT8?4piYolF(86uiGy`^r#V4yu7SA-c zjm})#d$(Kx2|Yn~i19Fr<)Gs+1XaUIJs~G>kg>3 zkQ$CqUj*cb1ORzHKmZ`Ab2^0!}Qkq&-DC(S~W*1GV zw9}L-zX}y4ZLblxEO1qhqE9Q-IY{NmR+w+RDpB;$@R(PRjCP|D$yJ+BvI$!mIbb<+GQ3MGKxUdIY{N`DOv%} zWA){tEw8M2f!r&ugC6C5AMVXM=w7ej#c_{G;Obab=fD={ut@71RLCd*b?Y1+R_HMR zqYNuWxFqU^Yq9YB)SmxVgNKR;UMH207l5qNItP~xUO*YTsayf1g`)yAJoRV6f2$Fh z|A1cNgyW)@1ZJ!8eBC7gN$MOgAgg|zqX4pYgkw{E4wcr09u#3tt$JW@xgr2dT0piE zfSguooznr3CR>T88cu6RII0io!Z)mN2S3C%toVr+P`0PTJ>8yo4OoHX161h;q+jRY zs$2o2lgirxY2o-j$>c;3w)BT<1fb;PVV(V`cL*zHj5+On;kX@;0)6rF-I?1)gyZtM6}?#ji{u+_Jz`IW9a=87nIA3aK2~3iFMS zzYP&fCXLEibCzR_6R~#sKN@)HB>);Za`ud*QCaKG8jEwqgoknK7rwW`Cq?RYYE5r+ zh-YUqJ082>*;EG`_lhV^vHEM7d+5Y#e$d^rC*jx{U%h3B^nU%7N|*y`o4g{@w;KP-89>&W#h zTBB2vTk*S|My+4jYTPKdk6yR3b?nAfcd`FeC@gttYuGBEl9wuf8`rOD9VP6`bhNxR znvXql-3ssVUSXfvcf^2L5R-^4E-s=g|M$Wm!?BMl!51d{AS*7Ggjwh^YsbK?6jgCA5T=(9$oK{{z$fCe9x5IJ^J=002ov JPDHLkV1g@XpTGbB literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..dffca3601eba7bf5f409bdd520820e2eb5122c75 GIT binary patch literal 4905 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 lV%Z2*hu);6rydA(}wUDXPCF_W1vnaRBK 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..14ed0af35023e4f1901cf03487b6c524257b8483 GIT binary patch literal 6895 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b0907cac3bfd8fbfdc46e1108247f0a1055387ec GIT binary patch literal 6387 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ae03154975f397f8ed1b84f2d4bf9783ecfa26 GIT binary patch literal 10413 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 XdJ+W}DiIkV00000NkvXXu0mjfKBlg6 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..2c18de9e66108411737e910f5c1972476f03ddbf GIT binary patch literal 9128 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 I20H400LcNok^lez literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..beed3cdd2c32af5114a7dc70b9ef5b698eb8797e GIT binary patch literal 15132 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..69b2233 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..0240004 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + DebugKit + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/test/java/vip/devkit/DebugKit/Demo/ExampleUnitTest.java b/app/src/test/java/vip/devkit/DebugKit/Demo/ExampleUnitTest.java new file mode 100644 index 0000000..14605e6 --- /dev/null +++ b/app/src/test/java/vip/devkit/DebugKit/Demo/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package vip.devkit.DebugKit.Demo; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..485ea3d --- /dev/null +++ b/build.gradle @@ -0,0 +1,28 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + maven { url 'https://jitpack.io' } + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/dklib/.gitignore b/dklib/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/dklib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/dklib/build.gradle b/dklib/build.gradle new file mode 100644 index 0000000..7bb2a1f --- /dev/null +++ b/dklib/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation('com.android.support:recyclerview-v7:29.0.0') { + exclude group: 'com.android.support' + } + implementation 'com.android.support:design:29.0.0' + +} + +//https://github.com/nisrulz/easydeviceinfo/wiki/Usage#easyappmod diff --git a/dklib/dklib.iml b/dklib/dklib.iml new file mode 100644 index 0000000..6662db8 --- /dev/null +++ b/dklib/dklib.iml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dklib/proguard-rules.pro b/dklib/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/dklib/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 diff --git a/dklib/src/androidTest/java/vip/devkit/debugkit/ExampleInstrumentedTest.java b/dklib/src/androidTest/java/vip/devkit/debugkit/ExampleInstrumentedTest.java new file mode 100644 index 0000000..e97630c --- /dev/null +++ b/dklib/src/androidTest/java/vip/devkit/debugkit/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package vip.devkit.debugkit; + +import android.content.Context; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("vip.devkit.debugkit.test", appContext.getPackageName()); + } +} diff --git a/dklib/src/main/AndroidManifest.xml b/dklib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..484381b --- /dev/null +++ b/dklib/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dklib/src/main/aidl/android/content/pm/IPackageStatsObserver.aidl b/dklib/src/main/aidl/android/content/pm/IPackageStatsObserver.aidl new file mode 100644 index 0000000..4ce6f7a --- /dev/null +++ b/dklib/src/main/aidl/android/content/pm/IPackageStatsObserver.aidl @@ -0,0 +1,14 @@ +// PackageStats.aidl +package android.content.pm; + +import android.content.pm.PackageStats; +/** + * API for package data change related callbacks from the Package Manager. + * Some usage scenarios include deletion of cache directory, generate + * statistics related to code, data, cache usage(TODO) + * {@hide} + */ +oneway interface IPackageStatsObserver { + + void onGetStatsCompleted(in PackageStats pStats, boolean succeeded); +} \ No newline at end of file diff --git a/dklib/src/main/aidl/android/content/pm/PackageStats.aidl b/dklib/src/main/aidl/android/content/pm/PackageStats.aidl new file mode 100644 index 0000000..97e19ff --- /dev/null +++ b/dklib/src/main/aidl/android/content/pm/PackageStats.aidl @@ -0,0 +1,3 @@ +package android.content.pm; + +parcelable PackageStats; \ No newline at end of file diff --git a/dklib/src/main/java/android/content/pm/IPackageStatsObserver.aidl b/dklib/src/main/java/android/content/pm/IPackageStatsObserver.aidl new file mode 100644 index 0000000..4ce6f7a --- /dev/null +++ b/dklib/src/main/java/android/content/pm/IPackageStatsObserver.aidl @@ -0,0 +1,14 @@ +// PackageStats.aidl +package android.content.pm; + +import android.content.pm.PackageStats; +/** + * API for package data change related callbacks from the Package Manager. + * Some usage scenarios include deletion of cache directory, generate + * statistics related to code, data, cache usage(TODO) + * {@hide} + */ +oneway interface IPackageStatsObserver { + + void onGetStatsCompleted(in PackageStats pStats, boolean succeeded); +} \ No newline at end of file diff --git a/dklib/src/main/java/android/content/pm/PackageStats.aidl b/dklib/src/main/java/android/content/pm/PackageStats.aidl new file mode 100644 index 0000000..97e19ff --- /dev/null +++ b/dklib/src/main/java/android/content/pm/PackageStats.aidl @@ -0,0 +1,3 @@ +package android.content.pm; + +parcelable PackageStats; \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/DataSource.java b/dklib/src/main/java/vip/devkit/debugkit/DataSource.java new file mode 100644 index 0000000..d2f655a --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/DataSource.java @@ -0,0 +1,199 @@ +package vip.devkit.debugkit; + +import android.content.Context; + +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.kit.GroupKitItem; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.kit.KitItem; +import vip.devkit.debugkit.kit.debug.AppInfo; +import vip.devkit.debugkit.kit.debug.BaseUrlManger; +import vip.devkit.debugkit.kit.debug.CachesManager; +import vip.devkit.debugkit.kit.debug.CrashManger; +import vip.devkit.debugkit.kit.debug.DataExport; +import vip.devkit.debugkit.kit.debug.FileExplorer; +import vip.devkit.debugkit.kit.debug.WebBrowse; +import vip.devkit.debugkit.kit.debug.LogManager; +import vip.devkit.debugkit.kit.debug.PermissionManager; +import vip.devkit.debugkit.kit.debug.Simulation; +import vip.devkit.debugkit.kit.performance.Battery; +import vip.devkit.debugkit.kit.performance.CPU; +import vip.devkit.debugkit.kit.performance.FTPS; +import vip.devkit.debugkit.kit.performance.RAM; +import vip.devkit.debugkit.kit.performance.Time; +import vip.devkit.debugkit.kit.performance.Traffic; +import vip.devkit.debugkit.kit.system.CpuKit; +import vip.devkit.debugkit.kit.system.HardwareKit; +import vip.devkit.debugkit.kit.system.NetworkKit; +import vip.devkit.debugkit.kit.system.ScreenKit; +import vip.devkit.debugkit.kit.system.SysInfo; +import vip.devkit.debugkit.kit.ue.ColorPicker; +import vip.devkit.debugkit.kit.ue.UE; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit + * File Name: DataSource.java + * Create Date: 2019/7/1 17:24 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class DataSource { + + private List mItemList = new ArrayList<>(); + private List mDiyKitItems = new ArrayList<>(); + private Context mContext; + + public List getKitList() { + return mItemList; + } + + public DataSource(Context context) { + mContext = context; + initKit(); + } + + private void initKit() { + sysKit(); + debugKit(); + developerKit(); + performanceKit(); + ueKit(); + diyKit(); + } + + + public void sysKit() { + GroupKitItem sys = new GroupKitItem(); + sys.mGroupName = ResUtil.getString(mContext, R.string.dk_sys_system); + + List d = new ArrayList<>(); + d.add(new SysInfo()); + d.add(new ScreenKit()); + d.add(new NetworkKit()); + d.add(new HardwareKit()); + d.add(new CpuKit()); + + List kitItems = new ArrayList<>(); + for (IKit kit : d) { + kitItems.add(new KitItem(kit)); + } + sys.mKitList = kitItems; + mItemList.add(sys); + + } + + + public void debugKit() { + GroupKitItem mGroupBean = new GroupKitItem(); + mGroupBean.mGroupName = ResUtil.getString(mContext, R.string.dk_debug); + + + List d = new ArrayList<>(); + d.add(new AppInfo()); + d.add(new FileExplorer()); + d.add(new LogManager()); + d.add(new PermissionManager()); + d.add(new BaseUrlManger()); + d.add(new CachesManager()); + d.add(new CrashManger()); + d.add(new Simulation()); + d.add(new DataExport()); + d.add(new WebBrowse()); + + + List kitItems = new ArrayList<>(); + for (IKit kit : d) { + kitItems.add(new KitItem(kit)); + } + mGroupBean.mKitList = kitItems; + mItemList.add(mGroupBean); + + + + } + + public void developerKit() { + GroupKitItem mGroupBean = new GroupKitItem(); + mGroupBean.mGroupName = ResUtil.getString(mContext, R.string.dk_developer); + + List d = new ArrayList<>(); + d.add(new SysInfo()); + d.add(new ScreenKit()); + d.add(new NetworkKit()); + d.add(new HardwareKit()); + d.add(new CpuKit()); + + List kitItems = new ArrayList<>(); + for (IKit kit : d) { + kitItems.add(new KitItem(kit)); + } + mGroupBean.mKitList = kitItems; + mItemList.add(mGroupBean); + + } + + public void performanceKit() { + GroupKitItem mGroupBean = new GroupKitItem(); + mGroupBean.mGroupName = ResUtil.getString(mContext, R.string.dk_performance); + + List d = new ArrayList<>(); + d.add(new FTPS()); + d.add(new CPU()); + d.add(new RAM()); + d.add(new Traffic()); + d.add(new Battery()); + d.add(new Time()); + + List kitItems = new ArrayList<>(); + for (IKit kit : d) { + kitItems.add(new KitItem(kit)); + } + mGroupBean.mKitList = kitItems; + mItemList.add(mGroupBean); + + } + + public void ueKit() { + GroupKitItem mGroupBean = new GroupKitItem(); + mGroupBean.mGroupName = ResUtil.getString(mContext, R.string.dk_ue); + + List d = new ArrayList<>(); + d.add(new ColorPicker()); + d.add(new UE()); + + List kitItems = new ArrayList<>(); + for (IKit kit : d) { + kitItems.add(new KitItem(kit)); + } + mGroupBean.mKitList = kitItems; + mItemList.add(mGroupBean); + + } + + + public void diyKit() { + if (mDiyKitItems.size() > 0) { + GroupKitItem mGroupBean = new GroupKitItem(); + mGroupBean.mGroupName = ResUtil.getString(mContext, R.string.dk_diy); + mGroupBean.mKitList = mDiyKitItems; + } + } + + + public void add(IKit mIKit) { + mDiyKitItems.add(new KitItem(mIKit)); + } + + public void add(List list) { + for (IKit kit : list) { + mDiyKitItems.add(new KitItem(kit)); + } + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/DebugKitFileProvider.java b/dklib/src/main/java/vip/devkit/debugkit/DebugKitFileProvider.java new file mode 100644 index 0000000..505cfc7 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/DebugKitFileProvider.java @@ -0,0 +1,17 @@ +package vip.devkit.debugkit; + +import androidx.core.content.FileProvider; + +/** + * Package Name: vip.devkit.debugkit + * File Name: DebugKitFileProvider.java + * Create Date: 2019/6/28 11:06 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class DebugKitFileProvider extends FileProvider { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/KitAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/KitAdapter.java new file mode 100644 index 0000000..5366b58 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/KitAdapter.java @@ -0,0 +1,49 @@ +package vip.devkit.debugkit; + +import android.view.View; + +import androidx.annotation.Nullable; + +import java.util.List; + +import vip.devkit.debugkit.kit.KitItem; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit + * File Name: KitAdapter.java + * Create Date: 2019/7/1 14:59 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class KitAdapter extends BaseRecyclerAdapter { + + + public KitAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper,final KitItem mItem) { + helper.setText(R.id.tv_name, mItem.kit.getName()) + .setImageResource(R.id.iv_icon, mItem.kit.getIcon()); + helper.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mItem.kit.onClick(mContext); + } + }); + } + + + @Override + public void setOnItemClick(View v, int position) { + super.setOnItemClick(v, position); + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/KitManagerAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/KitManagerAdapter.java new file mode 100644 index 0000000..d35d71f --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/KitManagerAdapter.java @@ -0,0 +1,41 @@ +package vip.devkit.debugkit; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import vip.devkit.debugkit.kit.GroupKitItem; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit + * File Name: KitManagerAdapter.java + * Create Date: 2019/7/1 11:16 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class KitManagerAdapter extends BaseRecyclerAdapter { + + public KitManagerAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, GroupKitItem mItem) { + + helper.setText(R.id.tv_group_name, mItem.mGroupName); + RecyclerView mKitList = (RecyclerView) helper.getView(R.id.rv_group_kit); + mKitList.setLayoutManager(new GridLayoutManager(mContext, 4)); + KitAdapter mKitAdapter = new KitAdapter(R.layout.dk_item_kit, mItem.mKitList); + mKitList.setAdapter(mKitAdapter); + + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/adapter/BaseUrlManagerAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/adapter/BaseUrlManagerAdapter.java new file mode 100644 index 0000000..1532e41 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/adapter/BaseUrlManagerAdapter.java @@ -0,0 +1,67 @@ +package vip.devkit.debugkit.adapter; + +import android.widget.CheckBox; +import android.widget.CompoundButton; + +import androidx.annotation.Nullable; + +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.ui.base_url.UrlInfo; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit.adapter + * File Name: BaseUrlManagerAdapter.java + * Create Date: 2019/7/3 10:34 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class BaseUrlManagerAdapter extends BaseRecyclerAdapter { + + public interface OnUrlCheckedListener { + void onChecked(UrlInfo urlInfo); + } + + private OnUrlCheckedListener mOnUrlCheckedListener; + private int checkPosition=-1; + + public void setOnUrlCheckedListener(OnUrlCheckedListener onUrlCheckedListener) { + mOnUrlCheckedListener = onUrlCheckedListener; + } + + public BaseUrlManagerAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(final BaseViewHolder helper, final UrlInfo mItem) { + helper.setText(R.id.tv_url, mItem.getBaseUrl()); + CheckBox checkBox = (CheckBox) helper.getView(R.id.cb_check); + LogCat.i("----------"+helper.getAdapterPosition()); + if (helper.getAdapterPosition()==checkPosition){ + checkBox.setChecked(true); + }else { + checkBox.setChecked(false); + } + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + LogCat.i("----------"+helper.getAdapterPosition()+"/"+isChecked); + if (isChecked && mOnUrlCheckedListener != null) { + checkPosition=helper.getAdapterPosition(); + mOnUrlCheckedListener.onChecked(mItem); + } else { + checkPosition=-1; + } + } + }); + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/adapter/CrashListAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/adapter/CrashListAdapter.java new file mode 100644 index 0000000..32690ba --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/adapter/CrashListAdapter.java @@ -0,0 +1,62 @@ +package vip.devkit.debugkit.adapter; + +import android.util.Log; + +import androidx.annotation.Nullable; + +import java.lang.reflect.UndeclaredThrowableException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.bean.CrashInfoBean; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit.adapter + * File Name: CrashListAdapter.java + * Create Date: 2019/7/9 10:00 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CrashListAdapter extends BaseRecyclerAdapter { + public CrashListAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, CrashInfoBean mItem) { + LogCat.i(" 1" + mItem.tr.toString()); + + Throwable throwable = mItem.tr; + String type = throwable.toString(); +// LogCat.i("throwable 99999 "+type.substring(0,type.indexOf(":"))); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + helper.setText(R.id.tv_time,""+dateFormat.format(new Date(mItem.time))) + .setText(R.id.tv_crash_name,type.substring(0,type.indexOf(":"))); + if (helper.getAdapterPosition()==0){ + LogCat.i(Log.getStackTraceString(throwable)); + } + +// StackTraceElement[] elements= throwable .getStackTrace(); +// for (int i = 0; i { + public FileFolderAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, FileInfoBean mItem) { + helper.setText(R.id.tv_folder,mItem.file.getName()+" >"); + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/adapter/FileInfoAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/adapter/FileInfoAdapter.java new file mode 100644 index 0000000..e7c8090 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/adapter/FileInfoAdapter.java @@ -0,0 +1,56 @@ +package vip.devkit.debugkit.adapter; + +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.bean.FileInfoBean; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.util.FileUtil; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit.adapter + * File Name: FileInfoAdapter.java + * Create Date: 2019/7/9 14:27 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FileInfoAdapter extends BaseRecyclerAdapter { + public FileInfoAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, FileInfoBean fileInfo) { + helper.setText(R.id.tv_name, fileInfo.file.getName()) + .setVisible(R.id.iv_more, !fileInfo.file.isFile()); + + ImageView mIcon = (ImageView) helper.getView(R.id.iv_icon); + if (fileInfo.file.isFile()) { + String suffix = FileUtil.getSuffix(fileInfo.file); + LogCat.i("---------------"+suffix); + if (suffix.equals("gif") || suffix.equals("jpg") || suffix.equals("jpeg") || suffix.equals("png") || suffix.equals("bmp")) { + mIcon.setImageResource(R.mipmap.dk_file_img); + } else if (suffix.equals(FileUtil.TXT)||suffix.equals("json")||suffix.equals("xml")) { + mIcon.setImageResource(R.mipmap.dk_file_txt); + } else if (suffix.equals(FileUtil.SHARED_PREFS)) { + } else if (suffix.equals(FileUtil.DB)) { + mIcon.setImageResource(R.mipmap.dk_file_db); + } else { + mIcon.setImageResource(R.mipmap.dk_file_ohter); + } + } else { + mIcon.setImageResource(R.mipmap.dk_file_folder); + } + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/adapter/PermissionManagerAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/adapter/PermissionManagerAdapter.java new file mode 100644 index 0000000..a311aa7 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/adapter/PermissionManagerAdapter.java @@ -0,0 +1,39 @@ +package vip.devkit.debugkit.adapter; + +import android.content.pm.PermissionInfo; + +import androidx.annotation.Nullable; + + +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.ui.permission.PermissionData; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; +import vip.devkit.debugkit.widget.recyclerview.BaseViewHolder; + +/** + * Package Name: vip.devkit.debugkit.adapter + * File Name: PermissionManagerAdapter.java + * Create Date: 2019/7/3 11:58 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PermissionManagerAdapter extends BaseRecyclerAdapter { + + + public PermissionManagerAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, String name) { + helper.setText(R.id.tv_permission, name) + .setText(R.id.tv_desc,""+PermissionData.getPermissionName(name)) + .setChecked(R.id.cb_check, PermissionData.hasSelfPermission(mContext, name)); + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/bean/AppInfoBean.java b/dklib/src/main/java/vip/devkit/debugkit/bean/AppInfoBean.java new file mode 100644 index 0000000..c12743c --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/bean/AppInfoBean.java @@ -0,0 +1,281 @@ +package vip.devkit.debugkit.bean; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import androidx.annotation.Keep; + +import vip.devkit.debugkit.util.AppUtil; +import vip.devkit.debugkit.util.DeviceUtils; +import vip.devkit.debugkit.util.FileUtil; + +/** + * Package Name: vip.devkit.debugkit.bean + * File Name: AppInfoBean.java + * Create Date: 2019/7/8 13:56 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class AppInfoBean { + + @Keep // App 包名 + private String appPackName; + @Keep // App 应用名 + private String appName; + @Keep // App 图标 + private transient Drawable appIcon; + @Keep // App 类型 + private AppType appType; + @Keep // App 版本号 + private int versionCode; + @Keep // App 版本名 + private String versionName; + @Keep // App 首次安装时间 + private long firstInstallTime; + @Keep // App 最后一次更新时间 + private long lastUpdateTime; + @Keep // App 地址 + private String sourceDir; + @Keep // APK 大小 + private long apkSize; + @Keep //Sign MD5 + private String apkSign; + @Keep //最小支持 + private int minSdkVersion = -1; + @Keep //兼容 + private int targetSdkVersion = -1; + + @Keep //activity 数量 + private int activityCount; + @Keep //service 数量 + private int serviceCount; + @Keep //receiver 数量 + private int receiverCount; + @Keep //provider 数量 + private int providerCount; + @Keep //permission 数量 + private int permissionCount; + + + private Context context; + + + /** + * 初始化 AppInfoBean + */ + protected AppInfoBean() { + + init(); + } + + public AppInfoBean(Context context) { + this.context = context; + init(); + } + + private void init() { + //GET_CONFIGURATIONS + PackageInfo packageInfo = DeviceUtils.getPackageInfo(context); + + PackageManager packageManager = context.getPackageManager(); + // App 包名 + appPackName = packageInfo.applicationInfo.packageName; + // App 应用名 + appName = packageManager.getApplicationLabel(packageInfo.applicationInfo).toString(); + // App 图标 + appIcon = packageManager.getApplicationIcon(packageInfo.applicationInfo); + // App 类型 + appType = AppInfoBean.getAppType(packageInfo); + // App 版本号 + versionCode = packageInfo.versionCode; + // App 版本名 + versionName = packageInfo.versionName; + // App 首次安装时间 + firstInstallTime = packageInfo.firstInstallTime; + // App 最后一次更新时间 + lastUpdateTime = packageInfo.lastUpdateTime; + // App 地址 + sourceDir = packageInfo.applicationInfo.sourceDir; + // APK 大小 +// apkSize = FileUtil.getFileSize(context,sourceDir); + // APK sign + apkSign = AppUtil.getSign(context, packageInfo.packageName); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + minSdkVersion = context.getApplicationInfo().minSdkVersion; + } + targetSdkVersion = context.getApplicationInfo().targetSdkVersion; + PackageInfo pia = DeviceUtils.getPackageInfo(context, PackageManager.GET_ACTIVITIES); + if (pia.activities != null) { + activityCount = pia.activities.length; + } + + PackageInfo pis = DeviceUtils.getPackageInfo(context, PackageManager.GET_SERVICES); + if (pis.services != null) { + serviceCount = pis.services.length; + } + + PackageInfo pir = DeviceUtils.getPackageInfo(context, PackageManager.GET_RECEIVERS); + if (pir.receivers != null) { + receiverCount = pir.receivers.length; + } + PackageInfo pip = DeviceUtils.getPackageInfo(context, PackageManager.GET_PROVIDERS); + if (pip.providers != null) { + providerCount = pip.providers.length; + } + + PackageInfo permissions = DeviceUtils.getPackageInfo(context, PackageManager.GET_PERMISSIONS); + if (permissions.requestedPermissions != null) { + permissionCount = permissions.requestedPermissions.length; + } + } + + + /** + * detail: 应用类型 + */ + public enum AppType { + + USER, // 用户 App + + SYSTEM, // 系统 App + + ALL // 全部 App + } + + public String getAppPackName() { + return appPackName; + } + + public String getAppName() { + return appName; + } + + public Drawable getAppIcon() { + return appIcon; + } + + public AppType getAppType() { + return appType; + } + + public int getVersionCode() { + return versionCode; + } + + public String getVersionName() { + return versionName; + } + + public long getFirstInstallTime() { + return firstInstallTime; + } + + public long getLastUpdateTime() { + return lastUpdateTime; + } + + public String getSourceDir() { + return sourceDir; + } + + public long getApkSize() { + return apkSize; + } + + public String getApkSign() { + return apkSign; + } + + public int getMinSdkVersion() { + return minSdkVersion; + } + + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + public int getActivityCount() { + return activityCount; + } + + public int getServiceCount() { + return serviceCount; + } + + public int getReceiverCount() { + return receiverCount; + } + + public int getProviderCount() { + return providerCount; + } + + public int getPermissionCount() { + return permissionCount; + } + + /** + * 获取 App 类型 + * + * @param packageInfo {@link PackageInfo} + * @return {@link AppType} 应用类型 + */ + public static AppType getAppType(final PackageInfo packageInfo) { + if (!isSystemApp(packageInfo) && !isSystemUpdateApp(packageInfo)) { + return AppType.USER; + } + return AppType.SYSTEM; + } + + /** + * 是否系统程序 + * + * @param packageInfo {@link PackageInfo} + * @return {@code true} yes, {@code false} no + */ + public static boolean isSystemApp(final PackageInfo packageInfo) { + return ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + } + + /** + * 是否系统程序被手动更新后, 也成为第三方应用程序 + * + * @param packageInfo {@link PackageInfo} + * @return {@code true} yes, {@code false} no + */ + public static boolean isSystemUpdateApp(final PackageInfo packageInfo) { + return ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); + } + + @Override + public String toString() { + return "AppInfoBean{" + + "appPackName='" + appPackName + '\'' + + ", appName='" + appName + '\'' + + ", appIcon=" + appIcon + + ", appType=" + appType + + ", versionCode=" + versionCode + + ", versionName='" + versionName + '\'' + + ", firstInstallTime=" + firstInstallTime + + ", lastUpdateTime=" + lastUpdateTime + + ", sourceDir='" + sourceDir + '\'' + + ", apkSize=" + apkSize + + ", apkSign='" + apkSign + '\'' + + ", minSdkVersion='" + targetSdkVersion + '\'' + + ", activityCount=" + activityCount + + ", serviceCount=" + serviceCount + + ", receiverCount=" + receiverCount + + ", providerCount=" + providerCount + + ", permissionCount=" + permissionCount + + '}'; + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/bean/CrashInfoBean.java b/dklib/src/main/java/vip/devkit/debugkit/bean/CrashInfoBean.java new file mode 100644 index 0000000..fca5878 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/bean/CrashInfoBean.java @@ -0,0 +1,26 @@ +package vip.devkit.debugkit.bean; + +import java.io.Serializable; + +/** + * Package Name: vip.devkit.debugkit.bean + * File Name: CrashInfoBean.java + * Create Date: 2019/7/9 9:24 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CrashInfoBean implements Serializable { + public final Throwable tr; + + public final long time; + + public CrashInfoBean(Throwable tr, long l) { + this.tr = tr; + this.time = l; + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/bean/FileInfoBean.java b/dklib/src/main/java/vip/devkit/debugkit/bean/FileInfoBean.java new file mode 100644 index 0000000..f96befe --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/bean/FileInfoBean.java @@ -0,0 +1,22 @@ +package vip.devkit.debugkit.bean; + +import java.io.File; + +/** + * Package Name: vip.devkit.debugkit.bean + * File Name: FileInfoBean.java + * Create Date: 2019/7/9 14:23 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FileInfoBean { + public final File file; + + public FileInfoBean(File file) { + this.file = file; + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/bean/PermissionInfo.java b/dklib/src/main/java/vip/devkit/debugkit/bean/PermissionInfo.java new file mode 100644 index 0000000..acdb2db --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/bean/PermissionInfo.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.bean; + +/** + * Package Name: vip.devkit.debugkit.bean + * File Name: PermissionData.java + * Create Date: 2019/7/3 11:59 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PermissionInfo { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/Category.java b/dklib/src/main/java/vip/devkit/debugkit/kit/Category.java new file mode 100644 index 0000000..df4baac --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/Category.java @@ -0,0 +1,25 @@ +package vip.devkit.debugkit.kit; + +/** + * Package Name: vip.devkit.debugkit.kit + * File Name: Category.java + * Create Date: 2019/6/28 10:57 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public interface Category { + int BIZ = 0; + + int TOOLS = 1; + + int PERFORMANCE = 2; + + int UI = 3; + + int CLOSE = 5; +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/GroupKitItem.java b/dklib/src/main/java/vip/devkit/debugkit/kit/GroupKitItem.java new file mode 100644 index 0000000..9124fad --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/GroupKitItem.java @@ -0,0 +1,30 @@ +package vip.devkit.debugkit.kit; + +import java.security.acl.Group; +import java.util.List; + +/** + * Package Name: vip.devkit.debugkit.kit + * File Name: GroupKitItem.java + * Create Date: 2019/7/1 14:53 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class GroupKitItem { + + + public String mGroupName; + public List mKitList; + + public GroupKitItem() { + } + + public GroupKitItem(String groupName, List kitList) { + mGroupName = groupName; + mKitList = kitList; + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/IKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/IKit.java new file mode 100644 index 0000000..bf28e61 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/IKit.java @@ -0,0 +1,31 @@ +package vip.devkit.debugkit.kit; + +import android.content.Context; + +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; + +/** + * Package Name: vip.devkit.debugkit.kit + * File Name: IKit.java + * Create Date: 2019/6/28 10:57 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public interface IKit { + int getCategory(); + + @StringRes + int getName(); + + @DrawableRes + int getIcon(); + + void onClick(Context context); + + void onAppInit(Context context); +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/KitItem.java b/dklib/src/main/java/vip/devkit/debugkit/kit/KitItem.java new file mode 100644 index 0000000..1c0b253 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/KitItem.java @@ -0,0 +1,23 @@ +package vip.devkit.debugkit.kit; + +/** + * Package Name: vip.devkit.debugkit.kit + * File Name: KitItem.java + * Create Date: 2019/7/1 15:00 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class KitItem { + public IKit kit; + + public KitItem(){ + + } + public KitItem(IKit kit) { + this.kit = kit; + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheConfig.java b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheConfig.java new file mode 100644 index 0000000..92fff47 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheConfig.java @@ -0,0 +1,27 @@ +package vip.devkit.debugkit.kit.crash; + +/** + * Package Name: vip.devkit.debugkit.kit.crash + * File Name: CacheConfig.java + * Create Date: 2019/7/9 9:33 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CacheConfig { + + static String CRASH_HISTORY_DIR = "crash"; + + static int CRASH_FILE_SZIE = 5; + + static boolean isCrashCapture = false; + + + + + + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheUtils.java b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheUtils.java new file mode 100644 index 0000000..3df701f --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CacheUtils.java @@ -0,0 +1,115 @@ +package vip.devkit.debugkit.kit.crash; + +import android.content.Context; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import vip.devkit.debugkit.kit.log.LogCat; + +/** + * Package Name: vip.devkit.debugkit.kit.crash + * File Name: CacheUtils.java + * Create Date: 2019/7/9 9:30 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CacheUtils { + + private CacheUtils() { + } + + public static boolean saveObject(Context context, String key, Serializable ser) { + File file = new File(context.getCacheDir() + "/" + key); + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + LogCat.e(e.toString()); + } + } + return saveObject(ser, file); + } + + public static Serializable readObject(Context context, String key) { + File file = new File(context.getCacheDir() + "/" + key); + return readObject(file); + } + + public static boolean saveObject(Serializable ser, File file) { + FileOutputStream fos = null; + ObjectOutputStream oos = null; + try { + fos = new FileOutputStream(file); + oos = new ObjectOutputStream(fos); + oos.writeObject(ser); + oos.flush(); + return true; + } catch (IOException e) { + LogCat.e(e.toString()); + return false; + } finally { + if (oos != null) { + try { + oos.close(); + } catch (IOException e) { + LogCat.e(e.toString()); + } + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + LogCat.e(e.toString()); + } + } + } + } + + public static Serializable readObject(File file) { + if (file == null || !file.exists() || file.isDirectory()) { + return null; + } + FileInputStream fis = null; + ObjectInputStream ois = null; + try { + fis = new FileInputStream(file); + ois = new ObjectInputStream(fis); + return (Serializable) ois.readObject(); + } catch (IOException e) { + if (e instanceof InvalidClassException) { + file.delete(); + } + LogCat.e(e.toString()); + return null; + } catch (ClassNotFoundException e) { + LogCat.e(e.toString()); + return null; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + LogCat.e(e.toString()); + } + } + if (ois != null) { + try { + ois.close(); + } catch (IOException e) { + LogCat.e(e.toString()); + } + } + } + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CrashCaptureManager.java b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CrashCaptureManager.java new file mode 100644 index 0000000..f06de2e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/crash/CrashCaptureManager.java @@ -0,0 +1,126 @@ +package vip.devkit.debugkit.kit.crash; + +import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; +import android.widget.Toast; + + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.bean.CrashInfoBean; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.util.FileUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.crash + * File Name: CrashCaptureManager.java + * Create Date: 2019/7/9 9:26 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CrashCaptureManager implements Thread.UncaughtExceptionHandler { + private static final String TAG = "CrashCaptureManager"; + private final Thread.UncaughtExceptionHandler mDefaultHandler; + private final Handler mHandler; + private Context mContext; + private CrashCaptureManager() { + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + HandlerThread handlerThread = new HandlerThread(TAG); + handlerThread.start(); + mHandler = new Handler(handlerThread.getLooper()); + } + + private static class Holder { + private static final CrashCaptureManager INSTANCE = new CrashCaptureManager(); + } + + public static CrashCaptureManager getInstance() { + return Holder.INSTANCE; + } + + public void init(Context context) { + mContext = context.getApplicationContext(); + } + + public void start() { + Thread.setDefaultUncaughtExceptionHandler(this); + } + + public void stop() { + Thread.setDefaultUncaughtExceptionHandler(mDefaultHandler); + } + + @Override + public void uncaughtException(final Thread t, final Throwable e) { + LogCat.d(t.toString()); + LogCat.d(Log.getStackTraceString(e)); + CacheUtils.saveObject(e, getCrashCacheFile()); + post(new Runnable() { + @Override + public void run() { + Toast.makeText(mContext, mContext.getString(R.string.dk_crash_capture_tips), Toast.LENGTH_SHORT).show(); + } + }); + postDelay(new Runnable() { + @Override + public void run() { + if (mDefaultHandler != null) { + mDefaultHandler.uncaughtException(t, e); + } + } + }, 2000); + } + + private void post(Runnable r) { + mHandler.post(r); + } + + private void postDelay(Runnable r, long delayMillis) { + mHandler.postDelayed(r, delayMillis); + } + + public File getCrashCacheDir() { + File dir = new File(mContext.getCacheDir() + File.separator + "crash"); + if (!dir.exists()) { + dir.mkdir(); + } + return dir; + } + + private File getCrashCacheFile() { + String fileName = new Date().toString(); + return new File(getCrashCacheDir() + File.separator + fileName); + } + + public void clearCacheHistory() { + FileUtil.deleteDirectory(getCrashCacheDir()); + } + + public List getCrashCaches() { + File[] caches = getCrashCacheDir().listFiles(); + List result = new ArrayList<>(); + if (caches == null) { + return result; + } + for (File cache : caches) { + Serializable serializable = CacheUtils.readObject(cache); + if (serializable instanceof Throwable) { + CrashInfoBean info = new CrashInfoBean((Throwable) serializable, cache.lastModified()); + result.add(info); + } + } + return result; + } + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/AppInfo.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/AppInfo.java new file mode 100644 index 0000000..6ee3a95 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/AppInfo.java @@ -0,0 +1,49 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.bean.AppInfoBean; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.kit.log.LogCat; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class AppInfo implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_info; + } + + @Override + public int getIcon() { + return R.mipmap.dk_app_info; + } + + @Override + public void onClick(Context context) { + AppInfoBean appInfoBean = new AppInfoBean(context); +// LogCat.i("build netInfo:"+appInfoBean.toString()); + LogCat.i("dk_log:"+123); + LogCat.i("dk_log----------------","build netInfo:"+appInfoBean.toString()); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/BaseUrlManger.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/BaseUrlManger.java new file mode 100644 index 0000000..60db114 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/BaseUrlManger.java @@ -0,0 +1,50 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.base_url.BaseUrlManagerActivity; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class BaseUrlManger implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_base_url; + } + + @Override + public int getIcon() { + return R.mipmap.dk_base_url; + } + + @Override + public void onClick(Context context) { + Intent intent = new Intent(context, BaseUrlManagerActivity.class); + context.startActivity(intent); + + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CachesManager.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CachesManager.java new file mode 100644 index 0000000..5f1e2e1 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CachesManager.java @@ -0,0 +1,50 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.AppDataCleanActivity; +import vip.devkit.debugkit.ui.crash.CrashManagerActivity; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CachesManager implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_clean; + } + + @Override + public int getIcon() { + return R.mipmap.dk_data_clean; + } + + @Override + public void onClick(Context context) { + Intent intent = new Intent(context, AppDataCleanActivity.class); + context.startActivity(intent); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CrashManger.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CrashManger.java new file mode 100644 index 0000000..c8298b0 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/CrashManger.java @@ -0,0 +1,53 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.kit.crash.CrashCaptureManager; +import vip.devkit.debugkit.ui.crash.CrashManagerActivity; +import vip.devkit.debugkit.ui.permission.PermissionManagerActivity; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CrashManger implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_crash; + } + + @Override + public int getIcon() { + return R.mipmap.dk_crash_catch; + } + + @Override + public void onClick(Context context) { + CrashCaptureManager.getInstance().init(context); + CrashCaptureManager.getInstance().start(); + Intent intent = new Intent(context, CrashManagerActivity.class); + context.startActivity(intent); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/DataExport.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/DataExport.java new file mode 100644 index 0000000..056ea6e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/DataExport.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class DataExport implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_data_export; + } + + @Override + public int getIcon() { + return R.mipmap.dk_data_export; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/FileExplorer.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/FileExplorer.java new file mode 100644 index 0000000..48e1760 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/FileExplorer.java @@ -0,0 +1,50 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.FileExplorer.FileExplorerActivity; +import vip.devkit.debugkit.ui.crash.CrashManagerActivity; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FileExplorer implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_file; + } + + @Override + public int getIcon() { + return R.mipmap.dk_file_explorer; + } + + @Override + public void onClick(Context context) { + Intent intent = new Intent(context, FileExplorerActivity.class); + context.startActivity(intent); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/LogManager.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/LogManager.java new file mode 100644 index 0000000..efecf8d --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/LogManager.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: PermissionManager.java + * Create Date: 2019/7/1 17:48 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class LogManager implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_log; + } + + @Override + public int getIcon() { + return R.mipmap.dk_log_info; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/PermissionManager.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/PermissionManager.java new file mode 100644 index 0000000..ef78e9f --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/PermissionManager.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.content.Intent; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.permission.PermissionManagerActivity; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: PermissionManager.java + * Create Date: 2019/7/1 17:48 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PermissionManager implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_permission; + } + + @Override + public int getIcon() { + return R.mipmap.dk_crash_permission; + } + + @Override + public void onClick(Context context) { + Intent intent = new Intent(context, PermissionManagerActivity.class); + context.startActivity(intent); + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/Simulation.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/Simulation.java new file mode 100644 index 0000000..054fb88 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/Simulation.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: Simulation.java + * Create Date: 2019/7/1 17:52 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Simulation implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_simulation; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/debug/WebBrowse.java b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/WebBrowse.java new file mode 100644 index 0000000..21d878e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/debug/WebBrowse.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.debug; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class WebBrowse implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_web; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/developer/Language.java b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/Language.java new file mode 100644 index 0000000..e0d8f79 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/Language.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.kit.developer; + +/** + * Package Name: vip.devkit.debugkit.kit.developer + * File Name: Language.java + * Create Date: 2019/7/1 18:04 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Language { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/developer/RuningService.java b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/RuningService.java new file mode 100644 index 0000000..3f7c756 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/RuningService.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.kit.developer; + +/** + * Package Name: vip.devkit.debugkit.kit.developer + * File Name: SystemSetting.java + * Create Date: 2019/7/1 18:00 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class RuningService { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/developer/SystemSetting.java b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/SystemSetting.java new file mode 100644 index 0000000..0f5694f --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/SystemSetting.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.kit.developer; + +/** + * Package Name: vip.devkit.debugkit.kit.developer + * File Name: SystemSetting.java + * Create Date: 2019/7/1 18:00 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class SystemSetting { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/developer/USBKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/USBKit.java new file mode 100644 index 0000000..87ec20e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/developer/USBKit.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.developer; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/1 17:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class USBKit implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_debug_info; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/IPrinter.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/IPrinter.java new file mode 100644 index 0000000..6a6ec90 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/IPrinter.java @@ -0,0 +1,73 @@ +package vip.devkit.debugkit.kit.log; + +/** + * Package Name: vip.devkit.debugkit.kit.log + * File Name: IPrinter.java + * Create Date: 2019/7/8 15:16 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public interface IPrinter { + + /** + * 获取日志配置信息 + * + * @return {@link LogConfig} 日志配置 + */ + LogConfig getLogConfig(); + + /** + * 初始化日志配置信息 ( 使用默认配置 ) + * + * @return {@link LogConfig} 日志配置 + */ + LogConfig init(); + + + /** + * 自定义日志配置信息 + * + * @param logConfig 日志配置 + */ + void init(LogConfig logConfig); + + + void d(String log); + + void i(Object... log); + + void w(String log); + + void e(String log); + + void e(Throwable throwable); + + void a(String log); + + void json(String log); + + void xml(String log); + + + + void d(String tag, String log); + + void i(String tag, Object... log); + + void w(String tag, String log); + + void e(String tag, String log); + + void e(String tag, Throwable throwable); + + void a(String tag, String log); + + void json(String tag, String log); + + void xml(String tag, String log); + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogCat.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogCat.java new file mode 100644 index 0000000..98052ab --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogCat.java @@ -0,0 +1,113 @@ +package vip.devkit.debugkit.kit.log; + +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Map; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: LogCat.java + * Create Date: 2019/7/1 11:51 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class LogCat { + + private static final IPrinter sPrinter = new LogPrinter(); + + + private LogCat() { + } + + /** + * @return {@link LogConfig} config + */ + public static LogConfig getLogConfig() { + return sPrinter.getLogConfig(); + } + + /** + * default + * @return {@link LogConfig} log config + */ + public static LogConfig init() { + return sPrinter.init(); + } + + /** + * @param logConfig config + */ + public static void init(final LogConfig logConfig) { + sPrinter.init(logConfig); + } + + + + public static void d(String msg) { + sPrinter.d(msg); + } + + public static void i(Object... msg) { + sPrinter.i(msg); + } + + public static void w(String msg) { + sPrinter.w(msg); + } + + + public static void e(String msg) { + sPrinter.e(msg); + } + + public static void e(Throwable msg) { + sPrinter.e(msg); + } + + public static void a(String msg) { + sPrinter.a(msg); + } + + + public static void d(String tag, String msg) { + sPrinter.d(tag,msg); + } + public static void i(String tag, String msg) { + sPrinter.i(tag,msg); + } + public static void w(String tag, String msg) { + sPrinter.w(tag,msg); + } + public static void e(String tag, String msg) { + sPrinter.e(tag,msg); + } + public static void e(String tag,Throwable msg) { + sPrinter.e(tag,msg); + } + public static void a(String tag, String msg) { + sPrinter.a(tag,msg); + } + + + + + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogConfig.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogConfig.java new file mode 100644 index 0000000..bca7619 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogConfig.java @@ -0,0 +1,45 @@ +package vip.devkit.debugkit.kit.log; + +/** + * Package Name: vip.devkit.debugkit.kit.log + * File Name: LogConfig.java + * Create Date: 2019/7/8 15:00 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class LogConfig { + + public static final int VERBOSE = 2; + public static final int DEBUG = 3; + public static final int INFO = 4; + public static final int WARN = 5; + public static final int ERROR = 6; + public static final int ASSERT = 7; + public static final int JSON = 8; + public static final int XML = 9; + + public static final int JSON_INDENT = 4; + + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + + public static String LOG_TAG = "dk_log"; + + public static LogLevel DEFAULT_LOG_LEVEL = LogLevel.DEBUG; + + + public static LogLevel logLevel=DEFAULT_LOG_LEVEL; + + public static void setLogTag(String logTag) { + LOG_TAG = logTag; + } + + public void setLogLevel(LogLevel logLevel) { + this.logLevel = logLevel; + } +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogLevel.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogLevel.java new file mode 100644 index 0000000..0f0cc9c --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogLevel.java @@ -0,0 +1,39 @@ +package vip.devkit.debugkit.kit.log; + +/** + * Package Name: vip.devkit.debugkit.kit.log + * File Name: LogLevel.java + * Create Date: 2019/7/8 14:59 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public enum LogLevel { + /** + * 全部不打印 + */ + NONE, + + /** + * 调试级别 v, d - 全部打印 + */ + DEBUG, + + /** + * 正常级别 i + */ + INFO, + + /** + * 警告级别 w + */ + WARN, + + /** + * 异常级别 e, wtf + */ + ERROR +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogPrinter.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogPrinter.java new file mode 100644 index 0000000..b5e325e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/LogPrinter.java @@ -0,0 +1,327 @@ +package vip.devkit.debugkit.kit.log; + +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import static vip.devkit.debugkit.kit.log.LogConfig.ASSERT; +import static vip.devkit.debugkit.kit.log.LogConfig.DEBUG; +import static vip.devkit.debugkit.kit.log.LogConfig.ERROR; +import static vip.devkit.debugkit.kit.log.LogConfig.INFO; +import static vip.devkit.debugkit.kit.log.LogConfig.JSON_INDENT; +import static vip.devkit.debugkit.kit.log.LogConfig.LINE_SEPARATOR; +import static vip.devkit.debugkit.kit.log.LogConfig.VERBOSE; +import static vip.devkit.debugkit.kit.log.LogConfig.WARN; +import static vip.devkit.debugkit.kit.log.LogConfig.JSON; +import static vip.devkit.debugkit.kit.log.LogConfig.XML; +import static vip.devkit.debugkit.kit.log.Util.getObjectsString; +import static vip.devkit.debugkit.kit.log.Util.printLine; + + +/** + * Package Name: vip.devkit.debugkit.kit.log + * File Name: LogLevel.java + * Create Date: 2019/7/8 14:59 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class LogPrinter implements IPrinter { + + LogConfig mLogConfig; + + @Override + public LogConfig getLogConfig() { + return mLogConfig; + } + + @Override + public LogConfig init() { + if (mLogConfig == null) { + mLogConfig = new LogConfig(); + } + return mLogConfig; + } + + @Override + public void init(LogConfig logConfig) { + mLogConfig = logConfig; + } + + + @Override + public void d(String log) { + d(mLogConfig.LOG_TAG, log); + } + + @Override + public void i(Object... log) { + StringBuilder sb = new StringBuilder(); + for (Object obj : log) { + sb.append(obj + ","); + } + log(INFO,mLogConfig.LOG_TAG,String.valueOf(sb)); + } + + + @Override + public void w(String log) { + log(WARN,mLogConfig.LOG_TAG,log); + } + + @Override + public void e(String log) { + log(INFO,mLogConfig.LOG_TAG,log); + } + + @Override + public void e(Throwable throwable) { + log(ERROR,mLogConfig.LOG_TAG,throwable.toString()); + } + + @Override + public void a(String log) { + log(ASSERT,mLogConfig.LOG_TAG,log); + } + + @Override + public void json(String log) { + log(JSON,mLogConfig.LOG_TAG,log); + } + + @Override + public void xml(String log) { + log(XML,mLogConfig.LOG_TAG,log); + } + + + @Override + public void d(String tag, String log) { + log(DEBUG,tag,log); + } + + + @Override + public void i(String tag, Object... log) { + StringBuilder sb = new StringBuilder(); + for (Object obj : log) { + sb.append(obj + ","); + } + log(INFO,tag,String.valueOf(sb)); + } + + @Override + public void w(String tag, String log) { + log(WARN,tag,log); + } + + @Override + public void e(String tag, String log) { + log(ERROR,tag,log); + } + + @Override + public void e(String tag, Throwable throwable) { + log(ERROR,tag,throwable.toString()); + } + + @Override + public void a(String tag, String log) { + log(ASSERT,tag,log); + } + + @Override + public void json(String tag, String log) { + log(JSON,tag,log); + } + + @Override + public void xml(String tag, String log) { + log(XML,tag,log); + } + + + private void log(int logType, String tagStr, Object objects) { + String[] contents = wrapperContent(tagStr, objects); + String tag = contents[0]; + String msg = contents[1]; + String headString = contents[2]; + if (mLogConfig.logLevel != LogLevel.NONE) { + switch (logType) { + case VERBOSE: + case DEBUG: + case INFO: + case WARN: + case ERROR: + case ASSERT: + printDefault(logType, tag, headString + msg); + break; + case JSON: + printJson(tag, msg, headString); + break; + case XML: + printXml(tag, msg, headString); + break; + default: + break; + } + } + } + public String[] wrapperContent(String tag, Object... objects) { + if (TextUtils.isEmpty(tag)) { + tag = LogConfig.LOG_TAG; + } + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + StackTraceElement targetElement = stackTrace[6]; + if (TextUtils.isEmpty(tag)) { + targetElement = stackTrace[6]; + } + String className = targetElement.getClassName(); + String[] classNameInfo = className.split("\\."); + if (classNameInfo.length > 0) { + className = classNameInfo[classNameInfo.length-1] + ".java"; + } + String methodName = targetElement.getMethodName(); + int lineNumber = targetElement.getLineNumber(); + if (lineNumber < 0) { + lineNumber = 0; + } + String methodNameShort = methodName.substring(0, 1).toUpperCase() + methodName.substring(1); + String msg = (objects == null) ? "Log with null object" : getObjectsString(objects); + String headString = "[(" + className + ":" + lineNumber + ")#" + methodNameShort + " ] "; + return new String[]{tag, msg, headString}; + } + + private void printDefault(int type, String tag, String msg) { + if (!Util.isPrintLog(mLogConfig, type)) { + return; + } + if (TextUtils.isEmpty(tag)) { + tag = mLogConfig.LOG_TAG; + } + int index = 0; + int maxLength = 4000; + int countOfSub = msg.length() / maxLength; + + if (countOfSub > 0) { // The log is so long + for (int i = 0; i < countOfSub; i++) { + String sub = msg.substring(index, index + maxLength); + printSub(type, tag, sub); + index += maxLength; + } + //printSub(type, msg.substring(index, msg.length())); + } else { + printSub(type, tag, msg); + } + + } + + private void printSub(int type, String tag, String sub) { + if (tag == null) { + tag = mLogConfig.LOG_TAG; + } + switch (type) { + case VERBOSE: + Log.v(tag, sub); + break; + case DEBUG: + Log.d(tag, sub); + break; + case INFO: + Log.i(tag, sub); + break; + case WARN: + Log.w(tag, sub); + break; + case ERROR: + Log.e(tag, sub); + break; + case ASSERT: + Log.wtf(tag, sub); + break; + } + } + + + private void printJson(String tag, String json, String headString) { + if (TextUtils.isEmpty(json)) { + d("Empty/Null json content"); + return; + } + if (TextUtils.isEmpty(tag)) { + tag = mLogConfig.LOG_TAG; + } + String message; + + try { + if (json.startsWith("{")) { + JSONObject jsonObject = new JSONObject(json); + message = jsonObject.toString(JSON_INDENT); + } else if (json.startsWith("[")) { + JSONArray jsonArray = new JSONArray(json); + message = jsonArray.toString(JSON_INDENT); + } else { + message = json; + } + } catch (JSONException e) { + message = json; + } + + printLine(tag, true); + message = headString + LINE_SEPARATOR + message; + String[] lines = message.split(LINE_SEPARATOR); + for (String line : lines) { + Log.d(tag, "|" + line); + } + printLine(tag, false); + } + + private void printXml(String tag, String xml, String headString) { + if (TextUtils.isEmpty(tag)) { + tag = mLogConfig.LOG_TAG; + } + if (xml != null) { + try { + Source xmlInput = new StreamSource(new StringReader(xml)); + StreamResult xmlOutput = new StreamResult(new StringWriter()); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + transformer.transform(xmlInput, xmlOutput); + xml = xmlOutput.getWriter().toString().replaceFirst(">", ">\n"); + } catch (Exception e) { + e.printStackTrace(); + } + xml = headString + "\n" + xml; + } else { + xml = headString + "Log with null object"; + } + + printLine(tag, true); + String[] lines = xml.split(LINE_SEPARATOR); + for (String line : lines) { + if (!TextUtils.isEmpty(line)) { + Log.d(tag, "|" + line); + } + } + printLine(tag, false); + } + + +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/log/Util.java b/dklib/src/main/java/vip/devkit/debugkit/kit/log/Util.java new file mode 100644 index 0000000..c0d79e7 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/log/Util.java @@ -0,0 +1,104 @@ +package vip.devkit.debugkit.kit.log; + +import android.text.TextUtils; +import android.util.Log; + + +/** + * Package Name: vip.devkit.debugkit.kit.log + * File Name: Util.java + * Create Date: 2019/7/8 15:38 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Util { + + + + public static String getObjectsString(Object... objects) { + + if (objects.length > 1) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("\n"); + for (int i = 0; i < objects.length; i++) { + Object object = objects[i]; + if (object == null) { + stringBuilder.append("param").append("[").append(i).append("]").append(" = ").append("null").append("\n"); + } else { + stringBuilder.append("param").append("[").append(i).append("]").append(" = ").append(object.toString()).append("\n"); + } + } + return stringBuilder.toString(); + } else { + Object object = objects[0]; + return object == null ? "null" : object.toString(); + } + } + + public static void printLine(String tag, boolean isTop) { + if (isTop) { + Log.d(tag, "╔═══════════════════════════════════════════════════════════════════════════════════════"); + } else { + Log.d(tag, "╚═══════════════════════════════════════════════════════════════════════════════════════"); + } + } + + /** + * 是否打印日志 + * @param logConfig 日志配置 + * @param logType 日志类型 + * @return {@code true} yes, {@code false} no + */ + public static boolean isPrintLog(final LogConfig logConfig, final int logType) { + boolean isPrint = false; + LogLevel logLevel = logConfig.logLevel; + switch (logLevel) { + case NONE: // + break; + case DEBUG: // v, d - all + isPrint = true; + break; + case INFO: // i + case WARN: // w + case ERROR: // e, wtf + isPrint = checkLogLevel(logLevel, logType); + break; + default: + break; + } + return isPrint; + } + /** + * 判断日志级别是否允许输出 + * @param logLevel 日志级别 + * @param logType 日志类型 + * @return {@code true} yes, {@code false} no + */ + private static boolean checkLogLevel(final LogLevel logLevel, final int logType) { + switch (logLevel) { + case INFO: // i + if (logType != Log.VERBOSE && logType != Log.DEBUG) { + return true; + } + break; + case WARN: // w + if (logType != Log.VERBOSE && logType != Log.DEBUG && logType != Log.INFO) { + return true; + } + break; + case ERROR: // e, wtf + if (logType == Log.ERROR || logType == Log.ASSERT) { + return true; + } + break; + default: + break; + } + return false; + } + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Battery.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Battery.java new file mode 100644 index 0000000..218e2a7 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Battery.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: Battery.java + * Create Date: 2019/7/1 18:05 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Battery implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_battery; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/CPU.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/CPU.java new file mode 100644 index 0000000..f26c492 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/CPU.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: FTPS.java + * Create Date: 2019/7/1 18:04 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CPU implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_cpu; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/FTPS.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/FTPS.java new file mode 100644 index 0000000..cb809de --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/FTPS.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: FTPS.java + * Create Date: 2019/7/1 18:04 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FTPS implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_fps; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/RAM.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/RAM.java new file mode 100644 index 0000000..467fa34 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/RAM.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: RAM.java + * Create Date: 2019/7/2 9:14 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class RAM implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_ram; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Time.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Time.java new file mode 100644 index 0000000..603354b --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Time.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: Time.java + * Create Date: 2019/7/2 9:15 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Time implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_open_time; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Traffic.java b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Traffic.java new file mode 100644 index 0000000..c245194 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/performance/Traffic.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.performance; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.performance + * File Name: Traffic.java + * Create Date: 2019/7/2 9:14 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Traffic implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_performance_traffic; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/system/CpuKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/system/CpuKit.java new file mode 100644 index 0000000..43c7fef --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/system/CpuKit.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.system; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.system + * File Name: HardwareKit.java + * Create Date: 2019/7/1 15:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CpuKit implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_sys_cpu; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/system/HardwareKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/system/HardwareKit.java new file mode 100644 index 0000000..c990cdc --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/system/HardwareKit.java @@ -0,0 +1,47 @@ +package vip.devkit.debugkit.kit.system; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.system + * File Name: HardwareKit.java + * Create Date: 2019/7/1 15:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class HardwareKit implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_sys_hardware; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/system/NetworkKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/system/NetworkKit.java new file mode 100644 index 0000000..3d454af --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/system/NetworkKit.java @@ -0,0 +1,50 @@ +package vip.devkit.debugkit.kit.system; + +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.sysinfo.SysInfoKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.system + * File Name: HardwareKit.java + * Create Date: 2019/7/1 15:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class NetworkKit implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_sys_network; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + SysInfoKit sysInfoKit =new SysInfoKit(); + Log.i("build netInfo:",0+sysInfoKit.getNetInfo(context).toString()); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/system/ScreenKit.java b/dklib/src/main/java/vip/devkit/debugkit/kit/system/ScreenKit.java new file mode 100644 index 0000000..708799b --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/system/ScreenKit.java @@ -0,0 +1,50 @@ +package vip.devkit.debugkit.kit.system; + +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.sysinfo.SysInfoKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.system + * File Name: HardwareKit.java + * Create Date: 2019/7/1 15:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class ScreenKit implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_sys_screen; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + SysInfoKit sysInfoKit =new SysInfoKit(); + Log.i("build getScreen:",0+sysInfoKit.getScreen(context).toString()); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/system/SysInfo.java b/dklib/src/main/java/vip/devkit/debugkit/kit/system/SysInfo.java new file mode 100644 index 0000000..e4282cd --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/system/SysInfo.java @@ -0,0 +1,53 @@ +package vip.devkit.debugkit.kit.system; + +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.ui.sysinfo.SysInfoKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit + * File Name: SysInfo.java + * Create Date: 2019/7/1 15:30 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class SysInfo implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_sys_system; + } + + + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + + SysInfoKit sysInfoKit =new SysInfoKit(); + Log.i("build SysInfo:",0+sysInfoKit.getInfo().toString()); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/ue/ColorPicker.java b/dklib/src/main/java/vip/devkit/debugkit/kit/ue/ColorPicker.java new file mode 100644 index 0000000..b73a2f5 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/ue/ColorPicker.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.ue; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.ue + * File Name: ColorPicker.java + * Create Date: 2019/7/2 9:09 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class ColorPicker implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_ue_color_picker; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/kit/ue/UE.java b/dklib/src/main/java/vip/devkit/debugkit/kit/ue/UE.java new file mode 100644 index 0000000..551a7fd --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/kit/ue/UE.java @@ -0,0 +1,46 @@ +package vip.devkit.debugkit.kit.ue; + +import android.content.Context; +import android.widget.Toast; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.IKit; +import vip.devkit.debugkit.util.ResUtil; + +/** + * Package Name: vip.devkit.debugkit.kit.ue + * File Name: ColorPicker.java + * Create Date: 2019/7/2 9:09 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class UE implements IKit { + @Override + public int getCategory() { + return 0; + } + + @Override + public int getName() { + return R.string.dk_ue_ue; + } + + @Override + public int getIcon() { + return android.R.mipmap.sym_def_app_icon; + } + + @Override + public void onClick(Context context) { + Toast.makeText(context, ResUtil.getString(context,getName()), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onAppInit(Context context) { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/AppDataCleanActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/AppDataCleanActivity.java new file mode 100644 index 0000000..165b26c --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/AppDataCleanActivity.java @@ -0,0 +1,36 @@ +package vip.devkit.debugkit.ui; + +import vip.devkit.debugkit.ui.base.BaseActivity; + +/** + * Package Name: vip.devkit.debugkit.ui + * File Name: AppDataCleanActivity.java + * Create Date: 2019/7/9 11:41 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class AppDataCleanActivity extends BaseActivity { + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return 0; + } + + @Override + protected void initView() { + + } + + @Override + protected void setListener() { + + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/FileExplorer/FileExplorerActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/FileExplorer/FileExplorerActivity.java new file mode 100644 index 0000000..16e5136 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/FileExplorer/FileExplorerActivity.java @@ -0,0 +1,250 @@ +package vip.devkit.debugkit.ui.FileExplorer; + +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.MediaStore; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.adapter.FileFolderAdapter; +import vip.devkit.debugkit.adapter.FileInfoAdapter; +import vip.devkit.debugkit.bean.FileInfoBean; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.ui.base.BaseActivity; +import vip.devkit.debugkit.widget.recyclerview.BaseRecyclerAdapter; + +/** + * Package Name: vip.devkit.debugkit.ui.FileExplorer + * File Name: FileExplorerActivity.java + * Create Date: 2019/7/9 14:17 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FileExplorerActivity extends BaseActivity implements View.OnClickListener, FileInfoAdapter.OnItemClickListener { + private LinearLayout mLlTitleBack; + private TextView mTvTitle; + private TextView mTvTitleRight; + private LinearLayout mLlTitleRight; + private LinearLayout mLlCommonLayout; + private RecyclerView mRlList; + private RecyclerView mRlFileFolder; + private LinearLayout mLlFolder; + + private File mCurDir; + private FileInfoAdapter mAdapter; + private List mBeanList = new ArrayList<>(); + private FileFolderAdapter mFolderAdapter; + private List mFolderList = new ArrayList<>(); + + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return R.layout.dk_activity_file_explorer; + } + + @Override + protected void initView() { + + mLlTitleBack = (LinearLayout) findViewById(R.id.ll_title_back); + mLlTitleBack.setOnClickListener(this); + mTvTitle = (TextView) findViewById(R.id.tv_title); + mTvTitleRight = (TextView) findViewById(R.id.tv_title_right); + mLlTitleRight = (LinearLayout) findViewById(R.id.ll_title_right); + mLlCommonLayout = (LinearLayout) findViewById(R.id.ll_common_layout); + mRlList = (RecyclerView) findViewById(R.id.rl_list); + mRlFileFolder = (RecyclerView) findViewById(R.id.rl_file_folder); + mLlFolder = (LinearLayout) findViewById(R.id.ll_folder); + mTvTitle.setOnClickListener(this); + mTvTitleRight.setOnClickListener(this); + mLlFolder.setOnClickListener(this); + + mFolderAdapter = new FileFolderAdapter(R.layout.dk_item_file_folder, mFolderList); + LinearLayoutManager layoutManager = new LinearLayoutManager(this); + layoutManager.setOrientation(RecyclerView.HORIZONTAL); + mRlFileFolder.setLayoutManager(layoutManager); + mRlFileFolder.setAdapter(mFolderAdapter); + + + mBeanList.addAll(initRootFileInfos(this)); + mAdapter = new FileInfoAdapter(R.layout.dk_item_file, mBeanList); + mAdapter.setOnItemClickListener(this); + mRlList.setLayoutManager(new LinearLayoutManager(this)); + mRlList.setAdapter(mAdapter); + + + } + + @Override + protected void setListener() { + + mFolderAdapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() { + @Override + public void onItemClick(BaseRecyclerAdapter adapter, View view, int position) { + FileInfoBean fileInfoBean = mFolderAdapter.getItem(position); + if (fileInfoBean.file == mCurDir) { + LogCat.i("当前文件夹"); + return; + } + setAdapterData(getFileInfos(fileInfoBean.file)); + for (int i = 0; i < mFolderList.size(); i++) { + LogCat.i("当前文件夹" + i); + if (i > position) { + mFolderList.remove(i); + } + } + mFolderAdapter.notifyDataSetChanged(); + } + }); + } + + + @Override + public void onItemClick(BaseRecyclerAdapter adapter, View view, int position) { + FileInfoBean fileInfoBean = mAdapter.getItem(position); + if (fileInfoBean.file.isFile()) { + openFile(this,fileInfoBean.file); + } else { + mCurDir = fileInfoBean.file; + setAdapterData(getFileInfos(fileInfoBean.file)); + mFolderList.add(fileInfoBean); + mFolderAdapter.notifyDataSetChanged(); + } + } + + private void setAdapterData(List fileInfos) { + mBeanList.clear(); + if (!fileInfos.isEmpty()) { + mBeanList.addAll(fileInfos); + } + mAdapter.notifyDataSetChanged(); + + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.ll_title_back) { + finish(); + } else if (v.getId() == R.id.ll_folder) { + mFolderList.clear(); + mFolderAdapter.notifyDataSetChanged(); + mBeanList.clear(); + mBeanList.addAll(initRootFileInfos(this)); + mAdapter.notifyDataSetChanged(); + } + } + + + /** + * 调用系统应用打开图片 + * + * @param context context + * @param file file + */ + public static void openFile(Context context, File file) { + Intent intent = new Intent(); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setAction(Intent.ACTION_VIEW); + Uri uri = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // 方式一 + uri = getImageContentUri(context, file); + // 方式二 + // uri = FileProvider.getUriForFile(context, ".fileProvider", file); + // intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + uri = Uri.fromFile(file); + } + + String type = null; + intent.setDataAndType(uri, type); + try { + context.startActivity(intent); + } catch (Exception e) { + LogCat.e("FileUtil"+ e.getMessage()); + Toast.makeText(context, "找不到打开此文件的应用!", Toast.LENGTH_SHORT).show(); + } + } + /** + * 转换 content:// uri + * + * @param imageFile imageFile + * @return + */ + public static Uri getImageContentUri(Context context, File imageFile) { + String filePath = imageFile.getAbsolutePath(); + Cursor cursor = context.getContentResolver().query( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + new String[] { MediaStore.Images.Media._ID }, + MediaStore.Images.Media.DATA + "=? ", + new String[] { filePath }, null); + + if (cursor != null && cursor.moveToFirst()) { + int id = cursor.getInt(cursor + .getColumnIndex(MediaStore.MediaColumns._ID)); + Uri baseUri = Uri.parse("content://media/external/images/media"); + return Uri.withAppendedPath(baseUri, "" + id); + } else { + if (imageFile.exists()) { + ContentValues values = new ContentValues(); + values.put(MediaStore.Images.Media.DATA, filePath); + return context.getContentResolver().insert( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + } else { + return null; + } + } + } + + private List getFileInfos(File dir) { + List fileInfos = new ArrayList<>(); + if (dir.listFiles() == null) { + return fileInfos; + } + for (File file : dir.listFiles()) { + FileInfoBean fileInfo = new FileInfoBean(file); + fileInfos.add(fileInfo); + } + return fileInfos; + } + + private List initRootFileInfos(Context context) { + List fileInfos = new ArrayList<>(); + fileInfos.add(new FileInfoBean(context.getFilesDir().getParentFile())); + fileInfos.add(new FileInfoBean(context.getExternalCacheDir())); + fileInfos.add(new FileInfoBean(context.getExternalFilesDir(null))); + return fileInfos; + } + + private boolean isRootFile(Context context, File file) { + if (file == null) { + return false; + } + return file.equals(context.getExternalCacheDir()) + || file.equals(context.getExternalFilesDir(null)) + || file.equals(context.getFilesDir().getParentFile()); + } +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/KitManagerActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/KitManagerActivity.java new file mode 100644 index 0000000..c356d4e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/KitManagerActivity.java @@ -0,0 +1,95 @@ +package vip.devkit.debugkit.ui; + +import android.content.pm.IPackageStatsObserver; +import android.content.pm.PackageStats; +import android.os.RemoteException; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.DataSource; +import vip.devkit.debugkit.KitManagerAdapter; +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.kit.GroupKitItem; +import vip.devkit.debugkit.kit.KitItem; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.ui.base.BaseActivity; +import vip.devkit.debugkit.ui.base_url.BaseUrlManager; + +/** + * Package Name: vip.devkit.debugkit.ui + * File Name: KitManagerActivity.java + * Create Date: 2019/7/1 10:43 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class KitManagerActivity extends BaseActivity { + + + private RecyclerView mRvList; + private KitManagerAdapter mManagerAdapter; + + List mItemList = new ArrayList<>(); + List mKitItems = new ArrayList<>(); + + private BaseUrlManager mBaseUrlManager; + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return R.layout.act_kit_manager; + } + + @Override + protected void initView() { + mRvList = (RecyclerView) findViewById(R.id.rv_list); + mRvList.setLayoutManager(new LinearLayoutManager(this)); + mManagerAdapter = new KitManagerAdapter(R.layout.dk_item_group_kit, mItemList); + mRvList.setAdapter(mManagerAdapter); + + DataSource dataSource = new DataSource(this); + + mItemList.addAll(dataSource.getKitList()); + mManagerAdapter.notifyDataSetChanged(); + + mBaseUrlManager = new BaseUrlManager(this); + + LogCat.i("mBaseUrlManager:"+mBaseUrlManager.getBaseUrl()); + + } + + @Override + protected void onResume() { + super.onResume(); + mBaseUrlManager.refreshData(); + LogCat.i("mBaseUrlManager:"+mBaseUrlManager.getBaseUrl()); + + } + + @Override + protected void setListener() { + + } + //aidl文件形成的Bindler机制服务类 + public class PkgSizeObserver extends IPackageStatsObserver.Stub{ + /*** 回调函数, + * @param pStats ,返回数据封装在PackageStats对象中 + * @param succeeded 代表回调成功 + */ + @Override + public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) + throws RemoteException { + // TODO Auto-generated method stub + } + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseActivity.java new file mode 100644 index 0000000..2e944a3 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseActivity.java @@ -0,0 +1,222 @@ +package vip.devkit.debugkit.ui.base; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + + +/** + * Package Name: vip.devkit.debugkit.ui.base + * File Name: BaseActivity.java + * Create Date: 2019/7/1 10:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public abstract class BaseActivity extends AppCompatActivity { + + private long lastBackKeyDownTick = 0; + public static final long MAX_DOUBLE_BACK_DURATION = 1500; + protected Context mContext; + + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + supportRequestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏应用的标题栏 + setContentView(setLayoutId()); + mContext = this; + initBase(); + initData(); + initView(); + setListener(); + } + + protected boolean isOrientation() { + return true; + } + + private void initBase() { + } + + + protected abstract void initData(); + + protected abstract int setLayoutId(); + + protected abstract void initView(); + + protected abstract void setListener(); + + + + + /** + * @return RootView FrameLayout + */ + protected FrameLayout getRootView() { + View re = this.findViewById(android.R.id.content); + if (re != null && re instanceof FrameLayout) { + return (FrameLayout) re; + } + ViewGroup viewGroup = (ViewGroup) this.getWindow().getDecorView(); + re = viewGroup.getChildAt(viewGroup.getChildCount() - 1); + if (re != null && re instanceof FrameLayout) { + return (FrameLayout) re; + } else { + re = new FrameLayout(this); + this.getActionBar().getHeight(); + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT + , ViewGroup.LayoutParams.MATCH_PARENT); + viewGroup.addView(re, lp); + return (FrameLayout) re; + } + } + + protected T getView(int id) { + return (T) super.findViewById(id); + } + + /** + * startActivity + * + * @param clazz + */ + protected void startActivity(Class clazz) { + Intent intent = new Intent(this, clazz); + startActivity(intent); + } + + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param extras + */ + protected void startActivity(Class clazz, Bundle extras) { + Intent intent = new Intent(this, clazz); + intent.putExtras(extras); + startActivity(intent); + } + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param requestCode + * @param extras + */ + protected void startActivity(Class clazz, int requestCode, Bundle extras) { + Intent intent = new Intent(this, clazz); + intent.putExtras(extras); + startActivityForResult(intent, requestCode); + } + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param code + */ + protected void startActivity(Class clazz, int code) { + Intent intent = new Intent(this, clazz); + startActivityForResult(intent, code); + } + + + /** + * 重启当前Activity + */ + private void reStartActivity() { + Intent intent = getIntent(); + finish(); + startActivity(intent); + } + + /** + * 初始化是否全屏 + */ + protected void initFlagFullscreen() { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置全屏 + } + + + + /** + * @return 设置android app 的字体大小不受系统字体大小改变的影响 + */ + @Override + public Resources getResources() { + Resources res = super.getResources(); + Configuration config = new Configuration(); + config.setToDefaults(); + res.updateConfiguration(config, res.getDisplayMetrics()); + return res; + } + + + @Override + public void onBackPressed() { + super.onBackPressed(); + long currentTick = System.currentTimeMillis(); + if (currentTick - lastBackKeyDownTick > MAX_DOUBLE_BACK_DURATION) { + lastBackKeyDownTick = currentTick; + } else { + finish(); + System.exit(0); + } + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + public void finish() { + hideSoftInput(); + super.finish(); + } + + private void hideSoftInput() { + View view = getCurrentFocus(); + if (view == null) view = new View(this); + InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseFragment.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseFragment.java new file mode 100644 index 0000000..b766be1 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base/BaseFragment.java @@ -0,0 +1,143 @@ +package vip.devkit.debugkit.ui.base; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; + + +/** + * Package Name: vip.devkit.debugkit.ui.base + * File Name: BaseFragment.java + * Create Date: 2019/7/1 10:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public abstract class BaseFragment extends Fragment { + + protected AppCompatActivity mActivity; + protected View mRootView; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof BaseActivity) { + mActivity = (BaseActivity) context; + } else { + mActivity = (AppCompatActivity) context; + } + } + + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + mRootView = inflater.inflate(setLayoutId(), container, false); + return mRootView; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + initView(view); + initData(); + setListener(); + } + + + + protected abstract void initData(); + + protected abstract int setLayoutId(); + + protected abstract void initView(View view); + + protected abstract void setListener(); + + + + + + protected T getView(int id) { + return (T) mRootView.findViewById(id); + } + + /** + * startActivity + * + * @param clazz + */ + protected void startActivity(Class clazz) { + Intent intent = new Intent(mActivity, clazz); + startActivity(intent); + } + + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param extras + */ + protected void startActivity(Class clazz, Bundle extras) { + Intent intent = new Intent(mActivity, clazz); + intent.putExtras(extras); + startActivity(intent); + } + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param requestCode + * @param extras + */ + protected void startActivity(Class clazz, int requestCode, Bundle extras) { + Intent intent = new Intent(mActivity, clazz); + intent.putExtras(extras); + startActivityForResult(intent, requestCode); + } + + /** + * startActivity putExtras(Bundle) + * + * @param clazz + * @param code + */ + protected void startActivity(Class clazz, int code) { + Intent intent = new Intent(mActivity, clazz); + startActivityForResult(intent, code); + } + + + /** + * 重启当前Activity + */ + private void reStartActivity() { + Intent intent = mActivity.getIntent(); + mActivity.finish(); + startActivity(intent); + } + + + + + +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base/GCBaseExpandableListAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base/GCBaseExpandableListAdapter.java new file mode 100644 index 0000000..88af7b4 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base/GCBaseExpandableListAdapter.java @@ -0,0 +1,121 @@ +package vip.devkit.debugkit.ui.base; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseExpandableListAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * Package Name: vip.devkit.debugkit.ui.base + * File Name: GCBaseExpandableListAdapter + * Create Date: 2019/7/1 10:48 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public abstract class GCBaseExpandableListAdapter extends BaseExpandableListAdapter { + + protected Map> mDatas = new HashMap<>(); + protected List mGroup = new ArrayList<>(); + protected LayoutInflater mInflater; + protected Context mContext; + protected int groupLayoutId; + protected int childLayoutId; + + public GCBaseExpandableListAdapter(Context context, int groupLayoutId, int childLayoutId, List mGroup, Map> datas) { + this.mContext = context; + this.mGroup = mGroup; + this.mDatas = datas; + this.groupLayoutId = groupLayoutId; + this.childLayoutId = childLayoutId; + mInflater = LayoutInflater.from(context); + } + + + @Override + public int getGroupCount() { + return mGroup.size(); + } + + @Override + public Group getGroup(int i) { + return mGroup.get(i); + } + + @Override + public int getChildrenCount(int i) { + return isEmpty(mDatas.get(getGroup(i))) ? 0 : mDatas.get(getGroup(i)).size(); + } + + @Override + public Child getChild(int i, int i1) { + List mGroup = mDatas.get(getGroup(i)); + return mGroup.get(i1); + } + + @Override + public long getGroupId(int i) { + return i; + } + + @Override + public long getChildId(int i, int i1) { + return i1; + } + + + @Override + public View getGroupView(int position, boolean b, View view, ViewGroup viewGroup) { + ViewHolder mGroupHolder = ViewHolder.get(mContext, view, viewGroup, groupLayoutId, position); + convertGroup(mGroupHolder, getGroup(position), position); + return mGroupHolder.getConvertView(); + } + + + @Override + public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) { + ViewHolder childHolder = ViewHolder.get(mContext, view, viewGroup, childLayoutId, childPosition); + convertChild(childHolder, getGroup(groupPosition), getChild(groupPosition, childPosition), groupPosition, childPosition); + return childHolder.getConvertView(); + } + + public abstract void convertGroup(ViewHolder holder, Group t, int groupPosition); + + public abstract void convertChild(ViewHolder holder, Group group, Child child, int groupPosition, int childPosition); + + @Override + public boolean hasStableIds() { + return true; + } + + /** + * 子类点击事件 + * + * @param i groupPosition + * @param i1 childPosition + * @return + */ + @Override + public boolean isChildSelectable(int i, int i1) { + return true; + } + + public static boolean isEmpty(List sourceList) { + return (sourceList == null || sourceList.size() == 0); + } + + @Override + public void onGroupExpanded(int groupPosition) { + super.onGroupExpanded(groupPosition); + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base/ViewHolder.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base/ViewHolder.java new file mode 100644 index 0000000..a854af0 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base/ViewHolder.java @@ -0,0 +1,142 @@ +package vip.devkit.debugkit.ui.base; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Adapter; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.annotation.IdRes; + +/** + * Package Name: vip.devkit.debugkit.ui.base + * File Name: ViewHolder + * Create Date: 2019/7/1 10:44 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class ViewHolder { + private SparseArray mViews; + private int mPosition; + private View mConvertView; + private Context mContext; + + public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) { + this.mPosition = position; + this.mViews = new SparseArray(); + this.mContext = context; + mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false); + mConvertView.setTag(this); + } + + public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) { + if (convertView == null) { + return new ViewHolder(context, parent, layoutId, position); + } else { + ViewHolder holder = (ViewHolder) convertView.getTag(); + holder.mPosition = position; + return holder; + } + } + + /** + * 通过viewId获取控件,此方法返回的是View的一个子类 + */ + public T getView(int viewId) { + View view = mViews.get(viewId); + if (view == null) { + view = mConvertView.findViewById(viewId); + mViews.put(viewId, view); + } + return (T) view; + } + + public View getConvertView() { + return mConvertView; + } + + public ViewHolder setText(int viewId, String text) { + TextView tv = getView(viewId); + tv.setText(text); + return this; + } + + /** + * @param viewId + * @param text + * @param flag Paint.STRIKE_THRU_TEXT_FLAG + * @return + */ + public ViewHolder setText(int viewId, String text, int flag) { + TextView tv = getView(viewId); + tv.getPaint().setFlags(flag); + tv.setText(text); + return this; + } + + /** + * + */ + public ViewHolder setImageResource(int viewId, int resId) { + ImageView imageView = getView(viewId); + imageView.setImageResource(resId); + return this; + } + + + public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) { + ImageView imageView = getView(viewId); + imageView.setImageBitmap(bitmap); + return this; + } + + + public ViewHolder setCheckBox(int viewId, boolean c, boolean isShow) { + CheckBox mCheckBox = getView(viewId); + if (isShow == true) { + mCheckBox.setVisibility(View.VISIBLE); + } else { + mCheckBox.setVisibility(View.GONE); + } + mCheckBox.setChecked(c); + return this; + } + + public ViewHolder setAdapter(int viewId, Adapter adapter) { + ListView listView = getView(viewId); + if (listView != null) { + listView.setAdapter((ListAdapter) adapter); + } + return this; + } + + public ViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) { + View view = getView(viewId); + view.setOnClickListener(listener); + return this; + } + + public ViewHolder setVisibility(@IdRes int viewId, boolean isVisibility) { + View view = getView(viewId); + if (isVisibility) { + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + return this; + } + + +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManager.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManager.java new file mode 100644 index 0000000..f207476 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManager.java @@ -0,0 +1,115 @@ +package vip.devkit.debugkit.ui.base_url; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import java.util.Collection; +import java.util.List; + +/** + * File Name: BaseUrlManager + * Create Date: 2019/6/14 11:53 + * Describe : + * Author : By k + * E-mail : vip@devkit.vip + * VersionName: 1 + * VersionCode: V 1.0 + * Code Update:(author - time) + * Update Describe: + */ +public class BaseUrlManager implements IBaseUrlManager { + private Context context; + + private List urlInfos; + + private UrlInfo urlInfo; + + private String baseUrl; + + + public BaseUrlManager(@NonNull Context context){ + this.context = context; + refreshData(); + } + + + @Override + public String getBaseUrl() { + return baseUrl; + } + + @Override + public UrlInfo getUrlInfo() { + return urlInfo; + } + + @Override + public void setUrlInfo(@NonNull UrlInfo urlInfo) { + this.urlInfo = urlInfo; + this.baseUrl = urlInfo.getBaseUrl(); + if(urlInfos!=null){ + if(urlInfos.contains(urlInfo)){ + urlInfos.remove(urlInfo); + } + urlInfos.add(urlInfo); + BaseUrlUtil.put(context,urlInfo,true); + } + } + + @Override + public void addUrlInfo(@NonNull UrlInfo urlInfo) { + if(urlInfos!=null){ + if(urlInfos.contains(urlInfo)){ + urlInfos.remove(urlInfo); + } + urlInfos.add(urlInfo); + BaseUrlUtil.put(context,urlInfo); + + } + } + + @Override + public void addUrlInfo(@NonNull Collection list) { + if(urlInfos!=null){ + urlInfos.addAll(list); + BaseUrlUtil.put(context,list); + } + } + + @Override + public void remove(@NonNull UrlInfo urlInfo) { + if(urlInfos!=null){ + urlInfos.remove(urlInfo); + BaseUrlUtil.remove(context,urlInfo.getBaseUrl()); + } + } + + @Override + public void clear() { + if(urlInfos!=null){ + urlInfos.clear(); + } + urlInfo = null; + baseUrl = null; + BaseUrlUtil.clear(context); + } + + @Override + public List getUrlInfos() { + return urlInfos; + } + + + @Override + public int getCount() { + return urlInfos != null ? urlInfos.size() : 0; + } + + @Override + public void refreshData() { + baseUrl = BaseUrlUtil.getBaseUrl(context); + urlInfo = BaseUrlUtil.getUrlInfo(context,baseUrl); + urlInfos = BaseUrlUtil.getUrlInfos(context); + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManagerActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManagerActivity.java new file mode 100644 index 0000000..85f0569 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlManagerActivity.java @@ -0,0 +1,131 @@ +package vip.devkit.debugkit.ui.base_url; + +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.adapter.BaseUrlManagerAdapter; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.ui.base.BaseActivity; + +/** + * Package Name: vip.devkit.debugkit.ui.base_url + * File Name: BaseUrlManagerActivity.java + * Create Date: 2019/7/3 9:47 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class BaseUrlManagerActivity extends BaseActivity implements View.OnClickListener,BaseUrlManagerAdapter.OnUrlCheckedListener { + private LinearLayout mLlTitleBack; + private TextView mTvTitle; + private TextView mTvTitleRight; + private LinearLayout mLlTitleRight; + private LinearLayout mLlCommonLayout; + private RecyclerView mRlList; + private EditText mEtContent; + private Button mBtnSubmit; + + private BaseUrlManager mBaseUrlManager; + private UrlInfo mCheckUrlInfo; + private List mUrlList = new ArrayList<>(); + private BaseUrlManagerAdapter mAdapter; + + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return R.layout.dk_activity_base_url; + } + + @Override + protected void initView() { + mBaseUrlManager = new BaseUrlManager(this); + mLlTitleBack = (LinearLayout) findViewById(R.id.ll_title_back); + mTvTitle = (TextView) findViewById(R.id.tv_title); + mTvTitleRight = (TextView) findViewById(R.id.tv_title_right); + mLlTitleRight = (LinearLayout) findViewById(R.id.ll_title_right); + mLlCommonLayout = (LinearLayout) findViewById(R.id.ll_common_layout); + mRlList = (RecyclerView) findViewById(R.id.rl_list); + mEtContent = (EditText) findViewById(R.id.et_content); + mBtnSubmit = (Button) findViewById(R.id.btn_submit); + mLlTitleBack.setOnClickListener(this); + mBtnSubmit.setOnClickListener(this); + mLlTitleRight.setOnClickListener(this); + + mTvTitle.setText("Base URL 管理"); + + mTvTitleRight.setText("保存"); + + mUrlList.clear(); + mUrlList.addAll(mBaseUrlManager.getUrlInfos()); + + + mAdapter = new BaseUrlManagerAdapter(R.layout.dk_item_base_url, mUrlList); + mAdapter.setOnUrlCheckedListener(this); + mRlList.setLayoutManager(new LinearLayoutManager(this)); + mRlList.setAdapter(mAdapter); + + + } + + @Override + protected void setListener() { + + } + + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.ll_title_back) { + finish(); + } else if (id == R.id.btn_submit) { + String addUrl = mEtContent.getText().toString(); + if (TextUtils.isEmpty(addUrl)) { + Toast.makeText(this, "请输入网络地址", Toast.LENGTH_SHORT).show(); + return; + } + if (!addUrl.startsWith("http")) { + Toast.makeText(this, "请输入正确的网络地址", Toast.LENGTH_SHORT).show(); + return; + } + mBaseUrlManager.addUrlInfo(new UrlInfo(addUrl)); + mEtContent.setText(""); + mEtContent.clearFocus(); + mUrlList.clear(); + mUrlList.addAll(mBaseUrlManager.getUrlInfos()); + LogCat.i("mBaseUrlManager:"+mBaseUrlManager.getUrlInfos().size()+"/"+mUrlList); + mAdapter.notifyDataSetChanged(); + }else if (id==R.id.ll_title_right){ + if (mCheckUrlInfo!=null){ + LogCat.i("mBaseUrlManager setUrlInfo :"+mCheckUrlInfo.getBaseUrl()); + mBaseUrlManager.setUrlInfo(mCheckUrlInfo); + } + finish(); + } + } + + @Override + public void onChecked(UrlInfo urlInfo) { + mCheckUrlInfo= urlInfo; + mAdapter.notifyDataSetChanged(); + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlUtil.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlUtil.java new file mode 100644 index 0000000..46744dc --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/BaseUrlUtil.java @@ -0,0 +1,221 @@ +package vip.devkit.debugkit.ui.base_url; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * File Name: BaseUrlUtil + * Create Date: 2019/6/14 11:48 + * Describe : + * Author : By k + * E-mail : vip@devkit.vip + * VersionName: 1 + * VersionCode: V 1.0 + * Code Update:(author - time) + * Update Describe: + */ +public class BaseUrlUtil { + private static final String DEFAULT_PREF_NAME = "base_url_manager"; + private static final String CURRENT_URL_PREF_NAME = "cur_base_url"; + private static final String KEY_BASE_URL = "key_base_url"; + + private BaseUrlUtil(){ + throw new AssertionError(); + } + + /** + * 缓存String + * @param context + * @param key + * @param value + */ + public static void put(@NonNull Context context, @NonNull String key, Long value){ + getSharedPreferences(context).edit() + .putLong(key,value) + .commit(); + } + + /** + * 缓存Map + * @param context + * @param map + */ + public static void put(@NonNull Context context, Map map){ + if(map!=null){ + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + + for(Map.Entry entry: map.entrySet()){ + if(!TextUtils.isEmpty(entry.getKey())) + editor.putLong(entry.getKey(), entry.getValue()); + } + + editor.commit(); + + } + } + + /** + * 缓存UrlInfo + * @param context + * @param urlInfo + */ + public static void put(@NonNull Context context,@NonNull UrlInfo urlInfo){ + put(context,urlInfo,false); + } + + + /** + * 缓存一个UrlInfo + * @param context + * @param urlInfo + * @param isCurBaseUrl 是否设置为当前baseUrl + */ + public static void put(@NonNull Context context,@NonNull UrlInfo urlInfo,boolean isCurBaseUrl){ + put(context,urlInfo.getBaseUrl(),urlInfo.getTime()); + if(isCurBaseUrl){ + getSharedPreferences(context,CURRENT_URL_PREF_NAME) + .edit() + .putString(KEY_BASE_URL,urlInfo.getBaseUrl()) + .commit(); + } + } + + /** + * 缓存UrlInfo结合 + * @param context + * @param urlInfos + */ + public static void put(@NonNull Context context, Collection urlInfos){ + if(urlInfos!=null && !urlInfos.isEmpty()){ + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + + for(UrlInfo urlInfo : urlInfos){ + editor.putLong(urlInfo.getBaseUrl(),urlInfo.getTime()); + } + + editor.commit(); + + } + } + + /** + * 移除指定的key + * @param context + * @param key + */ + public static void remove(@NonNull Context context,String key){ + getSharedPreferences(context).edit() + .remove(key) + .commit(); + } + + /** + * 清除缓存 + * @param context + */ + public static void clear(@NonNull Context context){ + getSharedPreferences(context).edit().clear().commit(); + getSharedPreferences(context,CURRENT_URL_PREF_NAME).edit().clear().commit(); + } + + /** + * 获取Long + * @param context + * @param key + * @return + */ + public static long getLong(Context context,@NonNull String key){ + SharedPreferences sp = getSharedPreferences(context); + return sp.getLong(key,0); + } + + /** + * 获取UrlInfo + * @param context + * @param url + * @return + */ + public static UrlInfo getUrlInfo(Context context,@NonNull String url){ + long time = getLong(context,url); + if(time>0){ + return new UrlInfo(url,time); + } + return new UrlInfo(url); + } + + /** + * 获取BaseUrl + * @param context + * @return + */ + public static String getBaseUrl(Context context){ + return getSharedPreferences(context,CURRENT_URL_PREF_NAME).getString(KEY_BASE_URL,""); + } + + + /** + * 获取当前的UrlInfo + * @param context + * @return + */ + public static UrlInfo getBseUrlInfo(Context context){ + String baseUrl = getBaseUrl(context); + + UrlInfo urlInfo = null; + if(!TextUtils.isEmpty(baseUrl)){ + urlInfo = getUrlInfo(context,baseUrl); + } + return urlInfo; + } + + /** + * 获取UrlInfo集合 + * @param context + * @return + */ + public static List getUrlInfos(@NonNull Context context){ + SharedPreferences sp = getSharedPreferences(context); + List list = new ArrayList<>(); + try{ + Map map = (Map)sp.getAll(); + if(map!=null){ + for(Map.Entry entry : map.entrySet()){ + list.add(new UrlInfo(entry.getKey(),entry.getValue())); + } + } + Collections.sort(list); + }catch (Exception e){ + e.printStackTrace(); + } + + return list; + } + + /** + * 获取数据存储 + * @param context + * @return + */ + private static SharedPreferences getSharedPreferences(@NonNull Context context){ + return context.getSharedPreferences(DEFAULT_PREF_NAME, Context.MODE_PRIVATE); + } + + /** + * 获取数据存储 + * @param context + * @param prefName + * @return + */ + private static SharedPreferences getSharedPreferences(@NonNull Context context,String prefName){ + return context.getSharedPreferences(prefName, Context.MODE_PRIVATE); + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/IBaseUrlManager.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/IBaseUrlManager.java new file mode 100644 index 0000000..25ae09a --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/IBaseUrlManager.java @@ -0,0 +1,79 @@ +package vip.devkit.debugkit.ui.base_url; + + +import androidx.annotation.NonNull; + +import java.util.Collection; +import java.util.List; + +/** + * File Name: IBaseUrlManager + * Create Date: 2019/6/14 11:41 + * Describe : + * Author : By k + * E-mail : vip@devkit.vip + * VersionName: 1 + * VersionCode: V 1.0 + * Code Update:(author - time) + * Update Describe: + */ +public interface IBaseUrlManager { + /** + * 获取BaseUrl + * @return {@link String} + */ + String getBaseUrl(); + + /** + * 获取UrlInfo + * @return {@link UrlInfo} + */ + UrlInfo getUrlInfo(); + + /** + * 设置UrlInfo + * @param urlInfo + */ + void setUrlInfo(@NonNull UrlInfo urlInfo); + + /** + * 添加UrlInfo + * @param urlInfo + */ + void addUrlInfo(@NonNull UrlInfo urlInfo); + + /** + * 添加UrlInfo集合 + * @param list + */ + void addUrlInfo(@NonNull Collection list); + + + /** + * 移除UrlInfo + * @param urlInfo + */ + void remove(@NonNull UrlInfo urlInfo); + + /** + * 清除 + */ + void clear(); + + /** + * 获取UrlInfo集合 + * @return {@link List} + */ + List getUrlInfos(); + + /** + * 获取url数 + * @return {@link int} + */ + int getCount(); + + /** + * 刷新数据 + */ + void refreshData(); +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/UrlInfo.java b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/UrlInfo.java new file mode 100644 index 0000000..039261e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/base_url/UrlInfo.java @@ -0,0 +1,138 @@ +package vip.devkit.debugkit.ui.base_url; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +/** + * File Name: UrlInfo + * Create Date: 2019/6/14 11:48 + * Describe : + * Author : By k + * E-mail : vip@devkit.vip + * VersionName: 1 + * VersionCode: V 1.0 + * Code Update:(author - time) + * Update Describe: + */ +public class UrlInfo implements Parcelable,Comparable { + + private String baseUrl; + + private long time; + + private String baseName; + + public UrlInfo(@NonNull String baseUrl) { + this(baseUrl,System.currentTimeMillis()); + } + + public UrlInfo(@NonNull String baseUrl,long time) { + this.baseUrl = baseUrl; + this.time = time; + } + + + public UrlInfo(@NonNull String baseUrl,String baseName) { + this.baseUrl = baseUrl; + this.baseName = baseName; + } + + public String getBaseUrl() { + if(TextUtils.isEmpty(baseUrl)){ + return ""; + } + return baseUrl; + } + + public void setBaseUrl(@NonNull String baseUrl) { + this.baseUrl = baseUrl; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public String getBaseName() { + return baseName; + } + + public void setBaseName(String baseName) { + this.baseName = baseName; + } + + public static Creator getCREATOR() { + return CREATOR; + } + + @Override + public String toString() { + return "UrlInfo{" + + "baseUrl='" + baseUrl + '\'' + + ", time=" + time + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + UrlInfo urlInfo = (UrlInfo) o; + + return baseUrl.equals(urlInfo.baseUrl); + } + + @Override + public int hashCode() { + return baseUrl.hashCode(); + } + + + @Override + public int compareTo(@NonNull UrlInfo o) { + if(time > o.time){ + return 1; + } + if(time < o.time){ + return -1; + } + return 0; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.baseUrl); + dest.writeString(this.baseName); + dest.writeLong(this.time); + } + + protected UrlInfo(Parcel in) { + this.baseUrl = in.readString(); + this.time = in.readLong(); + this.baseName = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public UrlInfo createFromParcel(Parcel source) { + return new UrlInfo(source); + } + + @Override + public UrlInfo[] newArray(int size) { + return new UrlInfo[size]; + } + }; +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/crash/CrashManagerActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/crash/CrashManagerActivity.java new file mode 100644 index 0000000..de2e61a --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/crash/CrashManagerActivity.java @@ -0,0 +1,103 @@ +package vip.devkit.debugkit.ui.crash; + +import android.app.ApplicationErrorReport; +import android.os.Bundle; +import android.text.format.Formatter; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.adapter.CrashListAdapter; +import vip.devkit.debugkit.bean.CrashInfoBean; +import vip.devkit.debugkit.kit.crash.CrashCaptureManager; +import vip.devkit.debugkit.ui.base.BaseActivity; +import vip.devkit.debugkit.util.FileUtil; + +/** + * Package Name: vip.devkit.debugkit.ui.crash + * File Name: CrashManagerActivity.java + * Create Date: 2019/7/9 9:54 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class CrashManagerActivity extends BaseActivity implements View.OnClickListener { + private LinearLayout mLlTitleBack; + private TextView mTvTitle; + private TextView mTvTitleRight; + private LinearLayout mLlTitleRight; + private LinearLayout mLlCommonLayout; + private Button mBtnAddCrash; + private RecyclerView mRlList; + + private TextView mTvCrashSize; + + private CrashListAdapter mAdapter; + private List mBeanList = new ArrayList<>(); + + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return R.layout.dk_activity_crash; + } + + @Override + protected void initView() { + + mLlTitleBack = (LinearLayout) findViewById(R.id.ll_title_back); + mTvTitle = (TextView) findViewById(R.id.tv_title); + mTvTitleRight = (TextView) findViewById(R.id.tv_title_right); + mLlTitleRight = (LinearLayout) findViewById(R.id.ll_title_right); + mLlCommonLayout = (LinearLayout) findViewById(R.id.ll_common_layout); + mBtnAddCrash = (Button) findViewById(R.id.btn_add_crash); + mRlList = (RecyclerView) findViewById(R.id.rl_list); + mTvCrashSize = findViewById(R.id.tv_crash_size); + String s = Formatter.formatFileSize(this, FileUtil.getDirectorySize(CrashCaptureManager.getInstance().getCrashCacheDir())); + mTvCrashSize.setText(s); + mBtnAddCrash.setOnClickListener(this); + mLlTitleBack.setOnClickListener(this); + + + List caches = CrashCaptureManager.getInstance().getCrashCaches(); + mBeanList.addAll(caches); + mAdapter = new CrashListAdapter(R.layout.dk_item_crash, mBeanList); + mRlList.setLayoutManager(new LinearLayoutManager(this)); + mRlList.setAdapter(mAdapter); + + + } + + @Override + protected void setListener() { + + } + + @Override + public void onClick(View v) { + int i = v.getId(); + if (i == R.id.ll_title_back) { + finish(); + } else if (i == R.id.btn_add_crash) { + testCrash().length(); + } + } + + public String testCrash() { + return null; + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/debug/AppInfoM.java b/dklib/src/main/java/vip/devkit/debugkit/ui/debug/AppInfoM.java new file mode 100644 index 0000000..2b2eba5 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/debug/AppInfoM.java @@ -0,0 +1,127 @@ +package vip.devkit.debugkit.ui.debug; + +import android.content.Context; +import android.content.pm.IPackageStatsObserver; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageStats; +import android.content.pm.Signature; +import android.os.Build; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.Keep; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.TreeMap; + +import vip.devkit.debugkit.BuildConfig; +import vip.devkit.debugkit.util.AppUtil; +import vip.devkit.debugkit.util.DeviceUtils; + +/** + * Package Name: vip.devkit.debugkit.ui.debug + * File Name: AppInfoM.java + * Create Date: 2019/7/2 15:14 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class AppInfoM { + + @Keep // App 地址 + private String sourceDir; + @Keep // APK 大小 + private long apkSize; + public Map getAppInfo(Context context) { + Map map = new TreeMap(); + PackageInfo pi = DeviceUtils.getPackageInfo(context); + map.put("包名", "" + pi.packageName); + map.put("包类型", "" + BuildConfig.BUILD_TYPE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + map.put("版本号", "" + pi.getLongVersionCode()); + } else { + map.put("版本号", "" + pi.versionCode); + } + map.put("sharedUserId", "" + pi.sharedUserId); + map.put("版本名uid", "" + pi.applicationInfo.uid); + PackageInfo pia = DeviceUtils.getPackageInfo(context, PackageManager.GET_ACTIVITIES); + if (pia.activities != null) { + map.put("activities", "" + pia.activities.length); + for (int i = 0; i < pia.activities.length; i++) { + map.put("activities" + i, "" + pia.activities[i].name); + } + } + PackageInfo pip = DeviceUtils.getPackageInfo(context, PackageManager.GET_PERMISSIONS); + if (pip.permissions != null) { + map.put("permissions", "" + pip.permissions.length); + } + + PackageInfo pirp = DeviceUtils.getPackageInfo(context, PackageManager.GET_PERMISSIONS); + if (pirp.requestedPermissions != null) { + map.put("requestedPermissions", "" + pirp.requestedPermissions.length); + } + if (Build.VERSION.SDK_INT >= 28) { + PackageInfo pis = DeviceUtils.getPackageInfo(context, PackageManager.GET_GIDS); + if (pis.signingInfo != null) { + } + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + map.put("baseRevisionCode", "" + pi.baseRevisionCode); + map.put("installLocation", "" + pi.installLocation); + } + map.put("SDK 目标版本号", "" + String.valueOf(context.getApplicationInfo().targetSdkVersion)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + map.put("最小支持SDK版本", "" + String.valueOf(context.getApplicationInfo().minSdkVersion)); + } + map.put("安装包大小", ""); + map.put("安装包 SIGN MD5", "" + AppUtil.getSign(context, pi.packageName)); + map.put("安装包文件MD5", ""); + map.put("首次安装时间", "" + pi.firstInstallTime); + map.put("更新安装时间", "" + pi.lastUpdateTime); + map.put("缓存大小", ""); + + return map; + } + + public void queryPacakgeSize(Context context, String pkgName) { + if (pkgName != null) { + //使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo + PackageManager pm = context.getPackageManager(); //得到pm对象 + try { + //通过反射机制获得该隐藏函数 + Method getPackageSizeInfo = pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class); + //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数 + getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver()); + } catch (Exception ex) { + Log.i("build", "NoSuchMethodException"+ex); + ex.printStackTrace(); + } + } + } + + + //aidl文件形成的Bindler机制服务类 + public class PkgSizeObserver extends IPackageStatsObserver.Stub { + /*** 回调函数, + * @param pStats ,返回数据封装在PackageStats对象中 + * @param succeeded 代表回调成功 + */ + PackageStats mPackageStats; + + @Override + public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) + throws RemoteException { + // TODO Auto-generated method stub + Log.i("build", "PackageStats"+pStats.codeSize); + Log.i("build", "PackageStats"+pStats.dataSize); + Log.i("build", "PackageStats"+pStats.cacheSize); + this.mPackageStats = pStats; + } + } + +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionData.java b/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionData.java new file mode 100644 index 0000000..216dc0b --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionData.java @@ -0,0 +1,171 @@ +package vip.devkit.debugkit.ui.permission; + +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; +import android.os.Build; +import android.text.TextUtils; + +import androidx.core.app.ActivityCompat; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import vip.devkit.debugkit.util.DeviceUtils; + +/** + * Package Name: vip.devkit.debugkit.ui.permission + * File Name: PermissionData.java + * Create Date: 2019/7/3 13:52 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PermissionData { + + + /** + * @param context + * @return 自定义权限组 + */ + public List getPermissions(Context context) { + List list = new ArrayList(); + PackageInfo pip = DeviceUtils.getPackageInfo(context, PackageManager.GET_PERMISSIONS); + if (pip.permissions != null) { + list.addAll(Arrays.asList(pip.permissions)); + } + return list; + } + + + public List getRequestedPermissions(Context context) { + List list = new ArrayList(); + PackageInfo pip = DeviceUtils.getPackageInfo(context, PackageManager.GET_PERMISSIONS); + if (pip.requestedPermissions != null) { + list.addAll(Arrays.asList(pip.requestedPermissions)); + } + return list; + } + + + public static String getPermissionName(String permission) { + Map map = new TreeMap(); + + //威胁需要申请的权限 + map.put("android.permission.BIND_ACCESSIBILITY_SERVICE", "辅助"); + map.put("android.permission.PACKAGE_USAGE_STATS", "应用使用情况"); + map.put("android.permission.BIND_NOTIFICATION_LISTENER_SERVICE", "监听通知栏"); + map.put("android.permission.WRITE_SETTINGS", "修改系统设置"); + map.put("android.permission.SYSTEM_ALERT_WINDOW", "显示在其他应用上面"); + map.put("android.permission.BIND_DEVICE_ADMIN", "设备管理器"); + map.put("android.permission.WRITE_EXTERNAL_STORAGE", "读取/修改/删除SD卡内容"); + map.put("android.permission.READ_EXTERNAL_STORAGE", "读取SD卡中的内容"); + map.put("android.permission.READ_CELL_BROADCASTS", "读取小区广播消息"); + map.put("android.permission.RECEIVE_MMS", "接收文字讯息 (彩信)"); + map.put("android.permission.RECEIVE_WAP_PUSH", "接收文字讯息 (WAP)"); + map.put("android.permission.READ_SMS", "读取您的文字讯息 (短信或彩信)"); + map.put("android.permission.RECEIVE_SMS", "接收文字讯息 (短信)"); + map.put("android.permission.SEND_SMS", "发送短信"); + map.put("android.permission.BODY_SENSORS", "人体传感器 (如心跳速率检测器)"); + map.put("android.permission.ANSWER_PHONE_CALLS", "接听来电"); + map.put("android.permission.READ_PHONE_NUMBERS", "读取电话号码"); + map.put("android.permission.PROCESS_OUTGOING_CALLS", "重新设置呼出的路径"); + map.put("android.permission.USE_SIP", "拨打/接听互联网通话"); + map.put("com.android.voicemail.permission.ADD_VOICEMAIL", "添加语音邮件"); + map.put("android.permission.CALL_PHONE", "直接拨打电话号码"); + map.put("android.permission.WRITE_CALL_LOG", "写入通话记录"); + map.put("android.permission.READ_CALL_LOG", "读取通话记录"); + map.put("android.permission.READ_PHONE_STATE", "设备信息:读取手机状态和身份"); + map.put("android.permission.RECORD_AUDIO", "录音"); + map.put("android.permission.ACCESS_COARSE_LOCATION", "(基于网络的) 大概位置"); + map.put("android.permission.ACCESS_FINE_LOCATION", "精准的 (GPS) 位置"); + map.put("android.permission.GET_ACCOUNTS", "查找设备上的帐户"); + map.put("android.permission.WRITE_CONTACTS", "修改通讯录"); + map.put("android.permission.READ_CONTACTS", "读取您的通讯录"); + map.put("android.permission.CAMERA", "拍摄照片和视频"); + map.put("android.permission.WRITE_CALENDAR", "写日历"); + map.put("android.permission.READ_CALENDAR", "读日历"); + + + map.put("android.permission.REQUEST_INSTALL_PACKAGES", "8.0+安装权限"); + map.put("android.permission.SYSTEM_ALERT_WINDOW", "6.0+安装权限"); + + map.put("android.permission.ANSWER_PHONE_CALLS", "允许您的应用通过编程方式接听呼入电话"); + map.put("android.permission.READ_PHONE_NUMBERS", "权限允许您的应用读取设备中存储的电话号码"); + + map.put("android.permission.SYSTEM_ALERT_WINDOW", "安装权限"); + map.put("ACCESS_CHECKIN_PROPERTIES", ""); + return map.get(permission); + } + + + /** + * 检查某些权限是否全部授予了 + * + * @param context 上下文对象 + * @param permissions 需要请求的权限组 + */ + public static boolean isHasPermission(Context context, String... permissions) { + ArrayList failPermissions = getFailPermissions(context, Arrays.asList(permissions)); + return failPermissions == null || failPermissions.isEmpty(); + } + + /** + * 获取没有授予的权限 + * + * @param context 上下文对象 + * @param permissions 需要请求的权限组 + */ + static ArrayList getFailPermissions(Context context, List permissions) { + ArrayList failPermissions = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (String permission : permissions) { + // 把没有授予过的权限加入到集合中 + if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) { + if (failPermissions == null) failPermissions = new ArrayList<>(); + failPermissions.add(permission); + } + } + } else { + failPermissions = new ArrayList<>(); + } + return failPermissions; + } + + public static boolean hasSelfPermission(Context context, List permissions) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true; + ArrayList failPermissions = null; + for (String permission : permissions) { + if (!hasSelfPermission(context, permission)) { + if (failPermissions == null) failPermissions = new ArrayList<>(); + failPermissions.add(permission); + } + } + return failPermissions == null || failPermissions.isEmpty(); + } + + public static boolean hasSelfPermission(Context context, String permission) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true; + AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + String op = AppOpsManager.permissionToOp(permission); + if (!TextUtils.isEmpty(op)) { + int checkOp = appOpsManager.checkOp(op, android.os.Process.myUid(), context.getPackageName()); + return checkOp == AppOpsManager.MODE_ALLOWED && ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; + } + return true; + } + + public static void ss(){ + + + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionManagerActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionManagerActivity.java new file mode 100644 index 0000000..9441e11 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/permission/PermissionManagerActivity.java @@ -0,0 +1,150 @@ +package vip.devkit.debugkit.ui.permission; + +import android.Manifest; +import android.content.ComponentName; +import android.os.Build; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + + +import com.google.android.material.snackbar.Snackbar; + +import java.util.ArrayList; +import java.util.List; + +import vip.devkit.debugkit.R; +import vip.devkit.debugkit.adapter.PermissionManagerAdapter; +import vip.devkit.debugkit.kit.log.LogCat; +import vip.devkit.debugkit.ui.base.BaseActivity; + +/** + * Package Name: vip.devkit.debugkit.ui.permission + * File Name: PermissionManagerActivity.java + * Create Date: 2019/7/3 11:52 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class PermissionManagerActivity extends BaseActivity implements View.OnClickListener { + + + private LinearLayout mLlTitleBack; + private TextView mTvTitle; + private TextView mTvTitleRight; + private LinearLayout mLlTitleRight; + private LinearLayout mLlCommonLayout; + private RecyclerView mRlList; + + private PermissionManagerAdapter mAdapter; + private List mList = new ArrayList<>(); + + private ComponentName mAdminName = null; + + + @Override + protected void initData() { + + } + + @Override + protected int setLayoutId() { + return R.layout.dk_activity_rv; + } + + @Override + protected void initView() { + mLlTitleBack = (LinearLayout) findViewById(R.id.ll_title_back); + mTvTitle = (TextView) findViewById(R.id.tv_title); + mTvTitleRight = (TextView) findViewById(R.id.tv_title_right); + mLlTitleRight = (LinearLayout) findViewById(R.id.ll_title_right); + mLlCommonLayout = (LinearLayout) findViewById(R.id.ll_common_layout); + mRlList = (RecyclerView) findViewById(R.id.rl_list); + mLlTitleBack.setOnClickListener(this); + mLlTitleRight.setOnClickListener(this); + mTvTitle.setText("权限管理"); + mTvTitleRight.setText("申请"); + + PermissionData data = new PermissionData(); + mList.addAll(data.getRequestedPermissions(this)); + for (int i = 0; i < data.getRequestedPermissions(this).size(); i++) { + String p = data.getRequestedPermissions(this).get(i); + LogCat.i("2:" + p); + LogCat.i("3:" + PermissionData.isHasPermission(this, p) + "/" + + PermissionData.hasSelfPermission(this, p) + "/" + + 0 + "/" + + 1); + } + mAdapter = new PermissionManagerAdapter(R.layout.dk_item_permission, mList); + mRlList.setLayoutManager(new LinearLayoutManager(this)); + mRlList.setAdapter(mAdapter); + } + + @Override + protected void setListener() { + + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.ll_title_back) { + finish(); + } else if (v.getId() == R.id.ll_title_right) { + + LogCat.i("权限申请"); + String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; + for (int i = 0; i = Build.VERSION_CODES.M) { +// requestPermissions(permissions, 9999); + + } + + if (shouldShowRequestPermissionRationale(permissions[0])){ + + ActivityCompat.requestPermissions(PermissionManagerActivity.this, + permissions, + 9999); + }else { + Snackbar.make(getRootView(), "请开启权限", Snackbar.LENGTH_SHORT).show(); + } + } + } + + @Override + public boolean shouldShowRequestPermissionRationale(String permission) { + return super.shouldShowRequestPermissionRationale(permission); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + LogCat.i("requestCode:" + requestCode + "/" + permissions + "/" + grantResults); + + + for (int i = 0; i < permissions.length; i++) { + LogCat.i("permissions:" + permissions[i]); + } + + for (int i = 0; i < grantResults.length; i++) { + LogCat.i("grantResults:" + grantResults[i]); + } + + } + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoActivity.java b/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoActivity.java new file mode 100644 index 0000000..1315bc8 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoActivity.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.ui.sysinfo; + +/** + * Package Name: vip.devkit.debugkit.ui + * File Name: SysInfoActivity.java + * Create Date: 2019/7/1 10:41 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class SysInfoActivity { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoKit.java b/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoKit.java new file mode 100644 index 0000000..4cda493 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/ui/sysinfo/SysInfoKit.java @@ -0,0 +1,197 @@ +package vip.devkit.debugkit.ui.sysinfo; + +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import vip.devkit.debugkit.util.Comm; +import vip.devkit.debugkit.util.NetUtils; + +/** + * Package Name: vip.ievkit.iebugkit.ui.sysinfo + * File Name: SysInfoKit.java + * Create Date: 2019/7/2 9:25 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class SysInfoKit { + + public SysInfoKit() { + + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public Map getInfo() { + Map map = new HashMap(); + + String[] s=Build.SUPPORTED_ABIS; + + String apis=""; + for (String ss:s) { + apis=""+ss+"/"; + } + apis=apis+Build.CPU_ABI+"/"+Build.CPU_ABI2; + map.put("品牌", Build.BRAND); + map.put("厂商", Build.MANUFACTURER); + map.put("型号", Build.DEVICE); + map.put("SDK版本", "" + Build.VERSION.SDK_INT); + map.put("CPU ABI", apis); + map.put("内核", Build.MANUFACTURER); + map.put("运行内存", Build.MANUFACTURER); + map.put("手机存储", Build.MANUFACTURER); + map.put("处理器", Build.HARDWARE); + map.put("无线电固件版本", Build.getRadioVersion()); + map.put("硬件识别码", "" + Build.FINGERPRINT); + map.put("硬件名称", "" + Build.HARDWARE); + map.put("HOST", "" + Build.HOST); + map.put("版本", "" + Build.MODEL); + map.put("硬件序列号", "" + Build.SERIAL); + map.put("手机制作商", "" + Build.MANUFACTURER); + map.put("描述Build的标签", "" + Build.TAGS); + map.put("builder类型", "" + Build.TYPE); + map.put("USERs", "" + Build.USER); + map.put("USER", "" + Build.USER + "/" + Build.VERSION.RELEASE + "/"); + map.put("USERs", "" + getNumberOfCPUCores()+"/"+Runtime.getRuntime().availableProcessors()); + + + return map; + } + + + public Map getScreen(Context context) { + + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + int height = dm.heightPixels; + int width = dm.widthPixels; + int sw = context.getResources().getConfiguration().smallestScreenWidthDp; + float density = dm.density; + int densityDPI = dm.densityDpi; // 屏幕密度(这里是系统密度)(每寸像素:120/160/240/320,480,640等) + float xdpi = dm.xdpi; + float ydpi = dm.ydpi; + + float scaledDensity = dm.scaledDensity; + Map map = new HashMap(); + + String dpi = "ldpi"; + if (density == 1.0) { + dpi = "mdpi"; + } else if (density == 1.5) { + dpi = "hdpi"; + } else if (density == 2.0) { + dpi = "xhdpi"; + } else if (density == 3.0) { + dpi = "xxhdpi"; + } + // 这样可以计算屏幕的物理尺寸 + float width2 = (width / xdpi) * (width / xdpi); + float height2 = (height / ydpi) * (width / xdpi); + + float xInch = width / xdpi; + float yInch = height / ydpi; + double screenInch = Math.sqrt(Math.pow(xInch, 2) + Math.pow(yInch, 2)); + map.put("密度", "" + densityDPI + "dpi/" + dpi + "/" + density); + map.put("精确密度", "" + xdpi + "*" + ydpi + "dp"); + map.put("屏幕分辨率", "" + width + "*" + height + "px"); + map.put("可用屏幕分辨率", "" + width + "*" + height + "px"); + map.put("屏幕尺寸", "" + formatDouble(screenInch, 1) + "英寸"); + return map; + } + + /** + * Double类型保留指定位数的小数,返回double类型(四舍五入) + * newScale 为指定的位数 + */ + private static double formatDouble(double d, int newScale) { + BigDecimal bd = new BigDecimal(d); + return bd.setScale(newScale, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + + public Map getNetInfo(Context context) { + Map map = new TreeMap<>(); + if (!NetUtils.isNetConnected(context)) { + map.put("网络类型:", "" + NetUtils.getNetworkStateName(context)); + } else { + map.put("网络类型:", "" + NetUtils.getNetworkStateName(context)); + int state = NetUtils.getNetworkState(context); + if (state == 0) { + } else if (state==1) { + int ipAddress=NetUtils.getWifiInfo(context).getIpAddress(); + String ipString = ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "." + (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff)); + map.put("WIFI SSID:", "" + NetUtils.getWifiInfo(context).getSSID()); + map.put("WIFI getBSSID:", "" + NetUtils.getWifiInfo(context).getBSSID()); + map.put("WIFI Ip:", "" + ipString); + map.put("WIFI getLinkSpeed:", "" + NetUtils.getWifiInfo(context).getLinkSpeed()); + map.put("WIFI getNetworkId:", "" + NetUtils.getWifiInfo(context).getNetworkId()); + map.put("WIFI 型号强度:", "" + NetUtils.getWifiInfo(context).getRssi()); + + } else if (state == 2 || state == 3 || state == 4 || state == 5) { + map.put("运行商:", "" + NetUtils.getOperatorName(context)); + } + map.put("local IP:", "" + NetUtils.getHostIp()); + map.put("IPv4:", ""); + map.put("IPv6:", ""); + } + map.put("MAC地址:", "" + NetUtils.getMacAddress()); + return map; + } + public Map getHardware(Context context) { + Map map = new TreeMap<>(); + + + return map; + } + + public static int getNumberOfCPUCores() { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { + // Gingerbread doesn't support giving PermissionManagerActivity single application access to both cores, but PermissionManagerActivity + // handful of devices (Atrix 4G and Droid X2 for example) were released with PermissionManagerActivity dual-core + // chipset and Gingerbread; that can let an app in the background run without impacting + // the foreground application. But for our purposes, it makes them single core. + return 1; //上面的意思就是2.3以前不支持多核,有些特殊的设备有双核...不考虑,就当单核!! + } + int cores; + try { + cores = new File("/sys/devices/system/cpu/").listFiles(CPU_FILTER).length; + } catch (SecurityException e) { + cores = 0; //这个常量得自己约定 + } catch (NullPointerException e) { + cores = 0; + } + return cores; + } + + private static final FileFilter CPU_FILTER = new FileFilter() { + @Override + public boolean accept(File pathname) { + String path = pathname.getName(); + //regex is slow, so checking char by char. + if (path.startsWith("cpu")) { + for (int i = 3; i < path.length(); i++) { + if (path.charAt(i) < '0' || path.charAt(i) > '9') { + return false; + } + } + return true; + } + return false; + } + }; +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/AppUtil.java b/dklib/src/main/java/vip/devkit/debugkit/util/AppUtil.java new file mode 100644 index 0000000..f1a74f3 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/AppUtil.java @@ -0,0 +1,58 @@ +package vip.devkit.debugkit.util; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +import java.security.MessageDigest; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: AppUtil.java + * Create Date: 2019/7/2 15:46 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class AppUtil { + /** + * 获取App Sign 签名 + * @param context + * @param pkgName + * @return + */ + public static String getSign(Context context, String pkgName) { + try { + PackageInfo pis = context.getPackageManager().getPackageInfo(pkgName, PackageManager.GET_SIGNATURES); + return hexdigest(pis.signatures[0].toByteArray()); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException("s application not found" + e); + } + } + + + public static String hexdigest(byte[] paramArrayOfByte) { + final char[] hexDigits = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, + 100, 101, 102}; + try { + MessageDigest localMessageDigest = MessageDigest.getInstance("MD5"); + localMessageDigest.update(paramArrayOfByte); + byte[] arrayOfByte = localMessageDigest.digest(); + char[] arrayOfChar = new char[32]; + for (int i = 0, j = 0; ; i++, j++) { + if (i >= 16) { + return new String(arrayOfChar); + } + int k = arrayOfByte[i]; + arrayOfChar[j] = hexDigits[(0xF & k >>> 4)]; + arrayOfChar[++j] = hexDigits[(k & 0xF)]; + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/Comm.java b/dklib/src/main/java/vip/devkit/debugkit/util/Comm.java new file mode 100644 index 0000000..a44e29c --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/Comm.java @@ -0,0 +1,35 @@ +package vip.devkit.debugkit.util; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: Comm.java + * Create Date: 2019/7/2 11:27 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class Comm { + /** + * 检查网络状态 + * + * @param context + * @return + */ + public static boolean isConnected(Context context) { + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = cm.getActiveNetworkInfo(); + if (info != null && info.isConnected()) { + if (info.getState() == NetworkInfo.State.CONNECTED) { + return true; + } + } + return false; + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/DataCleanUtil.java b/dklib/src/main/java/vip/devkit/debugkit/util/DataCleanUtil.java new file mode 100644 index 0000000..2a35b5e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/DataCleanUtil.java @@ -0,0 +1,105 @@ +package vip.devkit.debugkit.util; + +import android.content.Context; +import android.os.Environment; +import android.text.format.Formatter; + +import java.io.File; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: DataCleanUtil.java + * Create Date: 2019/6/28 11:04 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class DataCleanUtil { + private DataCleanUtil() { + } + + /** + * @param context + */ + public static void cleanInternalCache(Context context) { + FileUtil.deleteDirectory(context.getCacheDir()); + } + + /** + * @param context + */ + public static void cleanDatabases(Context context) { + FileUtil.deleteDirectory(new File(context.getFilesDir().getParent() + "/databases")); + } + + /** + * @param context + */ + public static void cleanSharedPreference(Context context) { + FileUtil.deleteDirectory(new File(context.getFilesDir().getParent() + "/shared_prefs")); + } + + /** + * @param context + */ + public static void cleanFiles(Context context) { + FileUtil.deleteDirectory(context.getFilesDir()); + } + + /** + * @param context + */ + public static void cleanExternalCache(Context context) { + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + FileUtil.deleteDirectory(context.getExternalCacheDir()); + } + } + + /** + * @param filePath + */ + public static void cleanCustomCache(String filePath) { + FileUtil.deleteDirectory(new File(filePath)); + } + + /** + * clean app data + * + * @param context + * @param filepath + */ + public static void cleanApplicationData(Context context, String... filepath) { + cleanInternalCache(context); + cleanExternalCache(context); + cleanDatabases(context); + cleanSharedPreference(context); + cleanFiles(context); + if (filepath == null) { + return; + } + for (String filePath : filepath) { + cleanCustomCache(filePath); + } + } + + public static long getApplicationDataSize(Context context) { + long size = 0; + // internal cache + size += FileUtil.getDirectorySize(context.getCacheDir()); + // databases + size += FileUtil.getDirectorySize(new File(context.getFilesDir().getParent() + "/databases")); + // shared preference + size += FileUtil.getDirectorySize(new File(context.getFilesDir().getParent() + "/shared_prefs")); + // files + size += FileUtil.getDirectorySize(context.getFilesDir()); + return size; + } + + public static String getApplicationDataSizeStr(Context context) { + return Formatter.formatFileSize(context, getApplicationDataSize(context)); + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/DeviceUtils.java b/dklib/src/main/java/vip/devkit/debugkit/util/DeviceUtils.java new file mode 100644 index 0000000..fc51ad5 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/DeviceUtils.java @@ -0,0 +1,457 @@ +package vip.devkit.debugkit.util; + + +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.hardware.Camera; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.os.Environment; +import android.os.StatFs; +import android.telephony.CellLocation; +import android.telephony.TelephonyManager; +import android.telephony.cdma.CdmaCellLocation; +import android.telephony.gsm.GsmCellLocation; +import android.text.TextUtils; +import android.text.format.Formatter; +import android.util.Log; + + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.regex.Pattern; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: DeviceUtils.java + * Create Date: 2019/6/28 11:01 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class DeviceUtils { + private static final String TAG = "DeviceUtils"; + private static final String PREF_DEVICE = "com.kuaidi.daijia.driver.device_pref"; + private static final String KEY_UUID = "key_uuid"; + private static final String BRAND_HUAWEI = "huawei"; + private static final String BRAND_HONOR = "honor"; + private static final String BRAND_SAMSUNG = "samsung"; + private static final String BRAND_XIAOMI = "xiaomi"; + private static final String BRAND_HONGMI = "hongmi"; + + private static String IMEI = ""; + private static String IMSI = ""; + private static String PHONE_NUMBER = null; + private static Boolean ROOTED = null; + + /** + * 获取CPU个数 + */ + public static int getCoreNum() { + class CpuFilter implements FileFilter { + @Override + public boolean accept(File pathname) { + // Check if filename is "cpu", followed by PermissionManagerActivity single digit number + if (Pattern.matches("cpu[0-9]", pathname.getName())) { + return true; + } + return false; + } + } + + try { + // Get directory containing CPU info + File dir = new File("/sys/devices/system/cpu/"); + // Filter to only list the devices we care about + File[] files = dir.listFiles(new CpuFilter()); + // Return the number of cores (virtual CPU devices) + return files.length; + } catch (Exception e) { + Log.e(TAG, "getCoreNum", e); + // Default to return 1 core + return 1; + } + } + + /** + * @param context + * @return 手机总内存(兆) + */ + public static long getTotalMemory(Context context) { + String str1 = "/proc/meminfo";// 系统内存信息文件 + String str2; + String[] arrayOfString; + long initial_memory = 0; + try { + FileReader localFileReader = new FileReader(str1); + BufferedReader localBufferedReader = new BufferedReader( + localFileReader, 8192); + str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小 + if (!TextUtils.isEmpty(str2)) { + arrayOfString = str2.split("\\s+"); + initial_memory = Integer.valueOf(arrayOfString[1]).intValue() / 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte + } + localBufferedReader.close(); + } catch (IOException e) { + } + return initial_memory;// Byte转换为KB或者MB,内存大小规格化 + } + + /** + * @param context + * @return 手机当前可用内存(兆) + */ + public static long getAvailMemory(Context context) {// 获取android当前可用内存大小 + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); + am.getMemoryInfo(mi); + return mi.availMem / 1024 / 1024; + } + + /** + * 版本名 + */ + public static String getVersionName(Context context) { + PackageInfo pi = getPackageInfo(context); + if (pi != null) { + return pi.versionName; + } else { + return ""; + } + } + + /** + * 版本号 + */ + public static int getVersionCode(Context context) { + PackageInfo pi = getPackageInfo(context); + if (pi != null) { + return pi.versionCode; + } else { + return 0; + } + } + + /** + * @desc GET_CONFIGURATIONS + * @param + * @return + * @author + * @time + */ + public static PackageInfo getPackageInfo(Context context) { + PackageInfo pi = null; + + try { + PackageManager pm = context.getPackageManager(); + pi = pm.getPackageInfo(context.getPackageName(), + PackageManager.GET_CONFIGURATIONS); + } catch (Exception e) { + e.printStackTrace(); + } + + return pi; + } + + public static PackageInfo getPackageInfo(Context context,int type) { + PackageInfo pi = null; + + try { + PackageManager pm = context.getPackageManager(); + pi = pm.getPackageInfo(context.getPackageName(), + type); + } catch (Exception e) { + e.printStackTrace(); + } + + return pi; + } + + public static PackageInfo getPackageInfoForPermission(Context context) { + PackageInfo pi = null; + + try { + PackageManager pm = context.getPackageManager(); + pi = pm.getPackageInfo(context.getPackageName(), + PackageManager.GET_PERMISSIONS); + } catch (Exception e) { + e.printStackTrace(); + } + + return pi; + } + + + + + + + + /** + * @return 手机链接wifi的路由器的名字 + */ + public static String getWifiSSID(Context context) { + WifiManager mWifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (mWifi.isWifiEnabled()) { + WifiInfo wifiInfo = mWifi.getConnectionInfo(); + return wifiInfo.getSSID(); + } + return ""; + } + + /** + * @return 手机链接wifi的路由器的mac地址 + */ + public static String getWifiBSSID(Context context) { + WifiManager mWifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (mWifi.isWifiEnabled()) { + WifiInfo wifiInfo = mWifi.getConnectionInfo(); + return wifiInfo.getBSSID(); + } + return ""; + } + + /** + * @param permission + * @param defalutValue 如果检测不到()检测发生异常的默认值 + * @return App是否拥有permission权限 + */ + public static boolean checkPermission(Context context, String permission, boolean defalutValue) { + boolean permit = false; + // 如果在判断的时候报错(有些机型),则默认不满足此权限 + try { + permit = PackageManager.PERMISSION_GRANTED == context + .checkCallingOrSelfPermission(permission); + } catch (Exception e) { + permit = defalutValue; + } + return permit; + } + + + /** + * 判断wifi是否开启 + * + * @param context + * @return + */ + public static boolean isWifiEnabled(Context context) { + WifiManager wm = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + return (wm != null) + && (wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED || wm.getWifiState() == WifiManager.WIFI_STATE_ENABLING); + } + + /** + * Is wifi connected + * + * @param context + * @return + */ + public static boolean isWifiConnected(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context. + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetInfo != null && activeNetInfo.isConnected() + && (activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI); + } + + public static boolean hasJellyBeanMr2() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; + } + + public static boolean hasJellyBeanMr1() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; + } + + /** + * 判断是否为某品牌生产的手机 + */ + public static boolean isProduceByBrand(String brand) { + boolean result = false; + // 判断厂家 + if (Build.MANUFACTURER != null) { + if (Build.MANUFACTURER.toLowerCase().contains(brand)) { + result = true; + } + } + // 判断品牌 + if (!result && Build.BRAND != null) { + if (Build.BRAND.toLowerCase().contains(brand)) { + result = true; + } + } + return result; + } + + public static boolean isProduceByXiaomi() { + return isProductInBrands(BRAND_XIAOMI, BRAND_HONGMI); + } + + public static boolean isProduceByHuaWei() { + return isProductInBrands(BRAND_HUAWEI, BRAND_HONOR); + } + + public static boolean isProduceBySamsung() { + return isProduceByBrand(BRAND_SAMSUNG); + } + + public static boolean isProductInBrands(String... brands) { + for (String brand : brands) { + if (isProduceByBrand(brand)) { + return true; + } + } + return false; + } + + + public static boolean isSimReady(Context context) { + try { + TelephonyManager mgr = (TelephonyManager) context + .getSystemService(Context.TELEPHONY_SERVICE); + Log.d(TAG, "[isSimReady]" + mgr.getSimState()); + return TelephonyManager.SIM_STATE_READY == mgr.getSimState() + || TelephonyManager.SIM_STATE_NETWORK_LOCKED == mgr.getSimState(); + } catch (Exception e) { + Log.e(TAG, "[isSimReady]" + e); + } + return false; + } + + /** + * 判断当前手机是否有ROOT权限 + * + * @return 是否ROOT + */ + public static boolean isRoot(Context context) { + if (ROOTED != null) { + return ROOTED; + } + try { +// RootBeer rootBeer = new RootBeer(context); +// rootBeer.setLogging(true); +// ROOTED = rootBeer.isRootedWithoutBusyBoxCheck(); +// if (ROOTED) { +// Log.w(TAG, "Device rooted."); +// } + } catch (Exception e) { + Log.e(TAG, "Check root failed.", e); + ROOTED = false; + } + return ROOTED; + } + + public static boolean hasFrontCamera() { + int cameraCount = Camera.getNumberOfCameras(); + Camera.CameraInfo info = new Camera.CameraInfo(); + for (int i = 0; i < cameraCount; i++) { + Camera.getCameraInfo(i, info); + if (Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing) { + return true; + } + } + return false; + } + + /** + * @return Number of bytes available on external storage + */ + public static long getExternalAvailableSpaceInBytes() { + long availableSpace = -1L; + try { + StatFs stat = new StatFs(Environment.getExternalStorageDirectory() + .getPath()); + availableSpace = (long) stat.getAvailableBlocks() + * (long) stat.getBlockSize(); + } catch (Exception e) { + e.printStackTrace(); + } + + return availableSpace; + } + + /** + * 获得SD卡总大小 + * + * @return + */ + private static String getSDTotalSize(Context context) { + File path = Environment.getExternalStorageDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSize(); + long totalBlocks = stat.getBlockCount(); + return Formatter.formatFileSize(context, blockSize * totalBlocks); + } + + /** + * 获得sd卡剩余容量,即可用大小 + * + * @return + */ + private static String getSDAvailableSize(Context context) { + File path = Environment.getExternalStorageDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return Formatter.formatFileSize(context, blockSize * availableBlocks); + } + + /** + * 获得机身内存总大小 + * + * @return + */ + private static String getRomTotalSize(Context context) { + File path = Environment.getDataDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSize(); + long totalBlocks = stat.getBlockCount(); + return Formatter.formatFileSize(context, blockSize * totalBlocks); + } + + /** + * 获得机身可用内存 + * + * @return + */ + private static String getRomAvailableSize(Context context) { + File path = Environment.getDataDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return Formatter.formatFileSize(context, blockSize * availableBlocks); + } + + + public static String getSDCardSpace(Context context) { + try { + String free = getSDAvailableSize(context); + String total = getSDTotalSize(context); + return free + "/" + total; + } catch (Exception e) { + return "-/-"; + } + } + + public static String getRomSpace(Context context) { + try { + String free = getRomAvailableSize(context); + String total = getRomTotalSize(context); + return free + "/" + total; + } catch (Exception e) { + return "-/-"; + } + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/FileUtil.java b/dklib/src/main/java/vip/devkit/debugkit/util/FileUtil.java new file mode 100644 index 0000000..ba20b65 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/FileUtil.java @@ -0,0 +1,248 @@ +package vip.devkit.debugkit.util; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.format.Formatter; + +import androidx.core.content.FileProvider; + +import java.io.File; +import java.util.Locale; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: FileUtil.java + * Create Date: 2019/6/28 11:05 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class FileUtil { + private static final String DATA_TYPE_ALL = "*/*"; + private static final String DATA_TYPE_APK = "application/vnd.android.package-archive"; + private static final String DATA_TYPE_VIDEO = "video/*"; + private static final String DATA_TYPE_AUDIO = "audio/*"; + private static final String DATA_TYPE_HTML = "text/html"; + private static final String DATA_TYPE_IMAGE = "image/*"; + private static final String DATA_TYPE_PPT = "application/vnd.ms-powerpoint"; + private static final String DATA_TYPE_EXCEL = "application/vnd.ms-excel"; + private static final String DATA_TYPE_WORD = "application/msword"; + private static final String DATA_TYPE_CHM = "application/x-chm"; + private static final String DATA_TYPE_TXT = "text/plain"; + private static final String DATA_TYPE_PDF = "application/pdf"; + private static final String DATA_TYPE_RTF = "application/rtf"; + + public static final String TXT = "txt"; + public static final String JPG = "jpg"; + public static final String PNG = "png"; + + public static final String DB = "db"; + public static final String SHARED_PREFS = "shared_prefs"; + public static final String XML = ".xml"; + public static final String JSON = ".json"; + private FileUtil() { + } + + public static String getFileSize(Context context, File file) { + if (!file.exists() || !file.isFile()) { + return null; + } + return Formatter.formatFileSize(context, file.length()); + } + + public static String getSuffix(File file) { + if (file == null || !file.exists()) { + return ""; + } + return file.getName() + .substring(file.getName().lastIndexOf(".") + 1) + .toLowerCase(Locale.getDefault()); + } + + public static void systemShare(Context context, File file) { + if (file == null || !file.exists()) { + return; + } + String suffix = getSuffix(file); + String type; + switch (suffix) { + case "doc": + case "docx": + type = DATA_TYPE_WORD; + break; + case "pdf": + type = DATA_TYPE_PDF; + break; + case "ppt": + case "pptx": + type = DATA_TYPE_PPT; + break; + case "xls": + case "xlsx": + type = DATA_TYPE_EXCEL; + break; + case "rtf": + type = DATA_TYPE_RTF; + break; + case "mpg": + case "mpeg": + case "3gp": + case "mp4": + type = DATA_TYPE_VIDEO; + break; + case "m4a": + case "mp3": + case "mid": + case "xmf": + case "ogg": + case "wav": + type = DATA_TYPE_AUDIO; + break; + case "gif": + case "jpg": + case "jpeg": + case "png": + case "bmp": + type = DATA_TYPE_IMAGE; + break; + case "txt": + case "sh": + type = DATA_TYPE_TXT; + break; + case "html": + type = DATA_TYPE_HTML; + break; + case "xml": + case "rss": + type = "application/rss+xml"; + break; + case "js": + type = "application/javascript"; + break; + case "chm": + type = DATA_TYPE_CHM; + break; + case "json": + type = "application/json"; + break; + case "class": + type = "application/java-vm"; + break; + case "jar": + type = "application/java-archive"; + break; + case "gtar": + type = "application/x-gtar"; + break; + case "tar": + type = "application/x-tar"; + break; + case "css": + type = "text/css"; + break; + case "7z": + type = "application/x-7z-compressed"; + break; + case "swf": + type = "application/x-7z-compressed"; + break; + case "zip": + type = "application/zip"; + break; + case "csv": + type = "text/csv"; + break; + case "apk": + type = DATA_TYPE_APK; + break; + default: + type = DATA_TYPE_ALL; + } + Intent intent = new Intent(Intent.ACTION_VIEW); + Uri uri; + uri = FileProvider.getUriForFile(context, context.getPackageName() + ".debugkitfileprovider", file); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(uri, type); + if (intent.resolveActivity(context.getPackageManager()) == null) { + intent.setDataAndType(uri, DATA_TYPE_ALL); + } + context.startActivity(intent); + } + + public static boolean isImage(File file) { + if (file == null) { + return false; + } + String suffix = getSuffix(file); + return "jpg".equals(suffix) || "jpeg".equals(suffix) || "png".equals(suffix) || "bmp".equals(suffix); + } + + public static boolean isVideo(File file) { + if (file == null) { + return false; + } + String suffix = getSuffix(file); + return "3gp".equals(suffix) || "mp4".equals(suffix) || "mkv".equals(suffix) || "webm".equals(suffix); + } + + public static boolean isDB(File file) { + if (file == null) { + return false; + } + String suffix = getSuffix(file); + return "db".equals(suffix); + } + + public static boolean isSp(File file) { + File parentFile = file.getParentFile(); + if (parentFile != null && parentFile.getName().equals(SHARED_PREFS) && file.getName().contains(XML)) { + return true; + } + return false; + } + + public static boolean isTxt(File file) { + if (file == null) { + return false; + } + String suffix = getSuffix(file); + + return TXT.equals(suffix); + } + + /** + * @param file + */ + public static void deleteDirectory(File file) { + if (file.isDirectory()) { + File[] listFiles = file.listFiles(); + for (File f : listFiles) { + deleteDirectory(f); + } + file.delete(); + } else { + file.delete(); + } + } + + public static long getDirectorySize(File directory) { + long size = 0; + File[] listFiles = directory.listFiles(); + if (listFiles == null) { + return size; + } + for (File file : listFiles) { + if (file.isDirectory()) { + size += getDirectorySize(file); + } else { + size += file.length(); + } + } + return size; + } +} + diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/NetUtils.java b/dklib/src/main/java/vip/devkit/debugkit/util/NetUtils.java new file mode 100644 index 0000000..f901ff5 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/NetUtils.java @@ -0,0 +1,283 @@ +package vip.devkit.debugkit.util; + + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; + +import static android.content.Context.WIFI_SERVICE; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: NetUtils.java + * Create Date: 2019/7/2 11:39 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class NetUtils { + public static final int NETWORK_NONE = 0; // 没有网络连接 + public static final int NETWORK_WIFI = 1; // wifi连接 + public static final int NETWORK_2G = 2; // 2G + public static final int NETWORK_3G = 3; // 3G + public static final int NETWORK_4G = 4; // 4G + public static final int NETWORK_5G = 5; // 5G + + public static final int NETWORK_MOBILE = 10; // 手机流量 + + /** + * 获取运营商名字 + * + * @param context context + * @return int + */ + public static String getOperatorName(Context context) { + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + // getSimOperatorName + return telephonyManager.getSimOperatorName(); + } + + public static String getNetworkStateName(Context context) { + int type = getNetworkState(context); + switch (type) { + case 0: + return "disconnect"; + case 1: + return "WIFI"; + case 2: + return "2G"; + case 3: + return "3G"; + case 4: + return "4G"; + case 5: + return "4G"; + case 10: + return "MOBILE"; + } + return "disconnect"; + } + + + /** + * 获取当前网络连接的类型 + * + * @param context context + * @return int + */ + public static int getNetworkState(Context context) { + ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); // 获取网络服务 + if (null == connManager) { // 为空则认为无网络 + return NETWORK_NONE; + } + // 获取网络类型,如果为空,返回无网络 + NetworkInfo activeNetInfo = connManager.getActiveNetworkInfo(); + if (activeNetInfo == null || !activeNetInfo.isAvailable()) { + return NETWORK_NONE; + } + // 判断是否为WIFI + NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (null != wifiInfo) { + NetworkInfo.State state = wifiInfo.getState(); + if (null != state) { + if (state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING) { + return NETWORK_WIFI; + } + } + } + // 若不是WIFI,则去判断是2G、3G、4G网 + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + int networkType = telephonyManager.getNetworkType(); + switch (networkType) { + /* + GPRS : 2G(2.5) General Packet Radia Service 114kbps + EDGE : 2G(2.75G) Enhanced Data Rate for GSM Evolution 384kbps + UMTS : 3G WCDMA 联通3G Universal Mobile Telecommunication System 完整的3G移动通信技术标准 + CDMA : 2G 电信 Code Division Multiple Access 码分多址 + EVDO_0 : 3G (EVDO 全程 CDMA2000 1xEV-DO) Evolution - Data Only (Data Optimized) 153.6kps - 2.4mbps 属于3G + EVDO_A : 3G 1.8mbps - 3.1mbps 属于3G过渡,3.5G + 1xRTT : 2G CDMA2000 1xRTT (RTT - 无线电传输技术) 144kbps 2G的过渡, + HSDPA : 3.5G 高速下行分组接入 3.5G WCDMA High Speed Downlink Packet Access 14.4mbps + HSUPA : 3.5G High Speed Uplink Packet Access 高速上行链路分组接入 1.4 - 5.8 mbps + HSPA : 3G (分HSDPA,HSUPA) High Speed Packet Access + IDEN : 2G Integrated Dispatch Enhanced Networks 集成数字增强型网络 (属于2G,来自维基百科) + EVDO_B : 3G EV-DO Rev.B 14.7Mbps 下行 3.5G + LTE : 4G Long Term Evolution FDD-LTE 和 TDD-LTE , 3G过渡,升级版 LTE Advanced 才是4G + EHRPD : 3G CDMA2000向LTE 4G的中间产物 Evolved High Rate Packet Data HRPD的升级 + HSPAP : 3G HSPAP 比 HSDPA 快些 + */ + // 2G + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_1xRTT: + case TelephonyManager.NETWORK_TYPE_IDEN: + return NETWORK_2G; + // 3G + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_HSPAP: + return NETWORK_3G; + // 4G + case TelephonyManager.NETWORK_TYPE_LTE: + return NETWORK_4G; + default: + return NETWORK_MOBILE; + } + } + + /** + * 判断网络是否连接 + * + * @param context context + * @return true/false + */ + public static boolean isNetConnected(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null) { + NetworkInfo info = connectivity.getActiveNetworkInfo(); + if (info != null && info.isConnected()) { + if (info.getState() == NetworkInfo.State.CONNECTED) { + return true; + } + } + } + return false; + } + + /** + * 判断是否wifi连接 + * + * @param context context + * @return true/false + */ + public static synchronized boolean isWifiConnected(Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager != null) { + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + if (networkInfo != null) { + int networkInfoType = networkInfo.getType(); + if (networkInfoType == ConnectivityManager.TYPE_WIFI || networkInfoType == ConnectivityManager.TYPE_ETHERNET) { + return networkInfo.isConnected(); + } + } + } + return false; + } + + + public static String getHostIp() { + String hostIp = null; + + try { + Enumeration nis = NetworkInterface.getNetworkInterfaces(); + InetAddress ia = null; + while (true) { + while (nis.hasMoreElements()) { + NetworkInterface ni = (NetworkInterface) nis.nextElement(); + Enumeration ias = ni.getInetAddresses(); + + while (ias.hasMoreElements()) { + ia = (InetAddress) ias.nextElement(); + if (!(ia instanceof Inet6Address)) { + String ip = ia.getHostAddress(); + if (!"127.0.0.1".equals(ip)) { + hostIp = ia.getHostAddress(); + break; + } + } + } + } + + return hostIp; + } + } catch (SocketException var6) { + return "0.0.0.0"; + } + } + + public static boolean isIp(String str) { + if (TextUtils.isEmpty(str)) { + return false; + } else { + String[] addr = str.split("\\."); + return addr.length == 4; + } + } + + + public static WifiInfo getWifiInfo(Context context) { + WifiManager wifi_service = (WifiManager) context.getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = null; + if (isWifiConnected(context)) { + wifiInfo = wifi_service.getConnectionInfo(); + } + return wifiInfo; + } + + public static int inetAddressToInt(InetAddress inetAddr) + throws IllegalArgumentException { + byte [] addr = inetAddr.getAddress(); + if (addr.length != 4) { + throw new IllegalArgumentException("Not an IPv4 address"); + } + return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) | + ((addr[1] & 0xff) << 8) | (addr[0] & 0xff); + + } + public static String getMacAddress() { + /*获取mac地址有一点需要注意的就是android 6.0版本后,以下注释方法不再适用,不管任何手机都会返回"02:00:00:00:00:00"这个默认的mac地址,这是googel官方为了加强权限管理而禁用了getSYstemService(Context.WIFI_SERVICE)方法来获得mac地址。*/ + // String macAddress= ""; +// WifiManager wifiManager = (WifiManager) MyApp.getContext().getSystemService(Context.WIFI_SERVICE); +// WifiInfo wifiInfo = wifiManager.getConnectionInfo(); +// macAddress = wifiInfo.getMacAddress(); +// return macAddress; + + String macAddress = null; + StringBuffer buf = new StringBuffer(); + NetworkInterface networkInterface = null; + try { + networkInterface = NetworkInterface.getByName("eth1"); + if (networkInterface == null) { + networkInterface = NetworkInterface.getByName("wlan0"); + } + if (networkInterface == null) { + return "02:00:00:00:00:02"; + } + byte[] addr = networkInterface.getHardwareAddress(); + for (byte b : addr) { + buf.append(String.format("%02X:", b)); + } + if (buf.length() > 0) { + buf.deleteCharAt(buf.length() - 1); + } + macAddress = buf.toString(); + } catch (SocketException e) { + e.printStackTrace(); + return "02:00:00:00:00:02"; + } + return macAddress; + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/util/ResUtil.java b/dklib/src/main/java/vip/devkit/debugkit/util/ResUtil.java new file mode 100644 index 0000000..0d92d23 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/util/ResUtil.java @@ -0,0 +1,24 @@ +package vip.devkit.debugkit.util; + +import android.content.Context; + +/** + * Package Name: vip.devkit.debugkit.util + * File Name: ResUtil.java + * Create Date: 2019/7/1 15:48 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class ResUtil { + public static String getString(Context context, int resId, String s) { + String val = String.format(context.getString(resId), s); + return val; + } + public static String getString(Context context, int resId) { + return context.getString(resId); + } +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/widget/a.java b/dklib/src/main/java/vip/devkit/debugkit/widget/a.java new file mode 100644 index 0000000..92e80f3 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/widget/a.java @@ -0,0 +1,15 @@ +package vip.devkit.debugkit.widget; + +/** + * Package Name: vip.devkit.debugkit.widget + * File Name: PermissionManagerActivity.java + * Create Date: 2019/7/1 11:51 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class a { +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseRecyclerAdapter.java b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseRecyclerAdapter.java new file mode 100644 index 0000000..33a3a4c --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseRecyclerAdapter.java @@ -0,0 +1,128 @@ +package vip.devkit.debugkit.widget.recyclerview; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + + +import androidx.annotation.IntRange; +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + + +public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter { + private static final String TAG = "BaseRecyclerAdapter"; + protected List mData; + protected Context mContext; + protected int mLayoutResId; + protected LayoutInflater mLayoutInflater; + + + private RecyclerView mRecyclerView; + private OnItemClickListener mOnItemClickListener; + private OnItemChildClickListener mOnItemChildClickListener; + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + mOnItemClickListener = onItemClickListener; + } + + public void setOnItemChildClickListener(OnItemChildClickListener onItemChildClickListener) { + mOnItemChildClickListener = onItemChildClickListener; + } + + protected RecyclerView getRecyclerView() { + return mRecyclerView; + } + + private void setRecyclerView(RecyclerView recyclerView) { + mRecyclerView = recyclerView; + } + + public BaseRecyclerAdapter(@LayoutRes int layoutResId, @Nullable List data) { + this.mData = data == null ? new ArrayList() : data; + if (layoutResId != 0) { + this.mLayoutResId = layoutResId; + } + } + + @Override + public K onCreateViewHolder(ViewGroup parent, int viewType) { + K baseViewHolder = null; + this.mContext = parent.getContext(); + this.mLayoutInflater = LayoutInflater.from(mContext); + baseViewHolder = (K) new BaseViewHolder(getItemView(mLayoutResId, parent)); + bindViewClickListener(baseViewHolder); + baseViewHolder.setAdapter(this); + return baseViewHolder; + + } + + + protected View getItemView(@LayoutRes int layoutResId, ViewGroup parent) { + return mLayoutInflater.inflate(layoutResId, parent, false); + } + + private void bindViewClickListener(final BaseViewHolder baseViewHolder) { + if (baseViewHolder == null) { + return; + } + final View view = baseViewHolder.itemView; + if (view == null) { + return; + } + if (getOnItemClickListener() != null) { + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + setOnItemClick(v, baseViewHolder.getLayoutPosition()); + } + }); + } + } + public void setOnItemClick(View v, int position) { + getOnItemClickListener().onItemClick(BaseRecyclerAdapter.this, v, position); + } + + @Override + public void onBindViewHolder(K holder, int position) { + convert(holder, getItem(position)); + } + + @Nullable + public T getItem(@IntRange(from = 0) int position) { + if (position >= 0 && position < mData.size()) + return mData.get(position); + else + return null; + } + @Override + public int getItemCount() { + return mData.size(); + } + + protected abstract void convert(K helper, T mItem); + + public interface OnItemClickListener { + void onItemClick(BaseRecyclerAdapter adapter, View view, int position); + } + + public interface OnItemChildClickListener { + + void onItemChildClick(BaseRecyclerAdapter adapter, View view, int position); + } + + public final OnItemClickListener getOnItemClickListener() { + return mOnItemClickListener; + } + + @Nullable + public final OnItemChildClickListener getOnItemChildClickListener() { + return mOnItemChildClickListener; + } + +} diff --git a/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseViewHolder.java b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseViewHolder.java new file mode 100644 index 0000000..d45cc9e --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/BaseViewHolder.java @@ -0,0 +1,519 @@ +package vip.devkit.debugkit.widget.recyclerview; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.util.Linkify; +import android.util.SparseArray; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.widget.Adapter; +import android.widget.AdapterView; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RatingBar; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; +import androidx.annotation.StringRes; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +public class BaseViewHolder extends RecyclerView.ViewHolder { + /** + * Views indexed with their IDs + */ + private final SparseArray views; + + public Set getNestViews() { + return nestViews; + } + + private final HashSet nestViews; + + private final LinkedHashSet childClickViewIds; + + private final LinkedHashSet itemChildLongClickViewIds; + private BaseRecyclerAdapter adapter; + /** + * use itemView instead + */ + @Deprecated + public View convertView; + + /** + * Package private field to retain the associated user object and detect PermissionManagerActivity change + */ + Object associatedObject; + + + public BaseViewHolder(final View view) { + super(view); + this.views = new SparseArray<>(); + this.childClickViewIds = new LinkedHashSet<>(); + this.itemChildLongClickViewIds = new LinkedHashSet<>(); + this.nestViews = new HashSet<>(); + convertView = view; + + + } + + private int getClickPosition() { + return getLayoutPosition(); + } + + public HashSet getItemChildLongClickViewIds() { + return itemChildLongClickViewIds; + } + + public HashSet getChildClickViewIds() { + return childClickViewIds; + } + + /** + * use itemView instead + * + * @return the ViewHolder root view + */ + @Deprecated + public View getConvertView() { + + return convertView; + } + + /** + * Will set the text of PermissionManagerActivity TextView. + * + * @param viewId The view id. + * @param value The text to put in the text view. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setText(@IdRes int viewId, CharSequence value) { + TextView view = getView(viewId); + view.setText(value); + return this; + } + + public BaseViewHolder setText(@IdRes int viewId, @StringRes int strId) { + TextView view = getView(viewId); + view.setText(strId); + return this; + } + + /** + * Will set the image of an ImageView from PermissionManagerActivity resource id. + * + * @param viewId The view id. + * @param imageResId The image resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) { + ImageView view = getView(viewId); + view.setImageResource(imageResId); + return this; + } + + /** + * Will set background color of PermissionManagerActivity view. + * + * @param viewId The view id. + * @param color A color, not PermissionManagerActivity resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) { + View view = getView(viewId); + view.setBackgroundColor(color); + return this; + } + + /** + * Will set background of PermissionManagerActivity view. + * + * @param viewId The view id. + * @param backgroundRes A resource to use as PermissionManagerActivity background. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes) { + View view = getView(viewId); + view.setBackgroundResource(backgroundRes); + return this; + } + + /** + * Will set text color of PermissionManagerActivity TextView. + * + * @param viewId The view id. + * @param textColor The text color (not PermissionManagerActivity resource id). + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) { + TextView view = getView(viewId); + view.setTextColor(textColor); + return this; + } + + + /** + * Will set the image of an ImageView from PermissionManagerActivity drawable. + * + * @param viewId The view id. + * @param drawable The image drawable. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) { + ImageView view = getView(viewId); + view.setImageDrawable(drawable); + return this; + } + + /** + * Add an action to set the image of an image view. Can be called multiple times. + */ + public BaseViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) { + ImageView view = getView(viewId); + view.setImageBitmap(bitmap); + return this; + } + + /** + * Add an action to set the alpha of PermissionManagerActivity view. Can be called multiple times. + * Alpha between 0-1. + */ + public BaseViewHolder setAlpha(@IdRes int viewId, float value) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + getView(viewId).setAlpha(value); + } else { + // Pre-honeycomb hack to set Alpha value + AlphaAnimation alpha = new AlphaAnimation(value, value); + alpha.setDuration(0); + alpha.setFillAfter(true); + getView(viewId).startAnimation(alpha); + } + return this; + } + + /** + * Set PermissionManagerActivity view visibility to VISIBLE (true) or GONE (false). + * + * @param viewId The view id. + * @param visible True for VISIBLE, false for GONE. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setGone(@IdRes int viewId, boolean visible) { + View view = getView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.GONE); + return this; + } + + /** + * Set PermissionManagerActivity view visibility to VISIBLE (true) or INVISIBLE (false). + * + * @param viewId The view id. + * @param visible True for VISIBLE, false for INVISIBLE. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setVisible(@IdRes int viewId, boolean visible) { + View view = getView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + return this; + } + + /** + * Add links into PermissionManagerActivity TextView. + * + * @param viewId The id of the TextView to linkify. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder linkify(@IdRes int viewId) { + TextView view = getView(viewId); + Linkify.addLinks(view, Linkify.ALL); + return this; + } + + /** + * Apply the typeface to the given viewId, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(@IdRes int viewId, Typeface typeface) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + return this; + } + + /** + * Apply the typeface to all the given viewIds, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(Typeface typeface, int... viewIds) { + for (int viewId : viewIds) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + } + return this; + } + + /** + * Sets the progress of PermissionManagerActivity ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress) { + ProgressBar view = getView(viewId); + view.setProgress(progress); + return this; + } + + /** + * Sets the progress and max of PermissionManagerActivity ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @param max The max value of PermissionManagerActivity ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + view.setProgress(progress); + return this; + } + + /** + * Sets the range of PermissionManagerActivity ProgressBar to 0...max. + * + * @param viewId The view id. + * @param max The max value of PermissionManagerActivity ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setMax(@IdRes int viewId, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + return this; + } + + /** + * Sets the rating (the number of stars filled) of PermissionManagerActivity RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating) { + RatingBar view = getView(viewId); + view.setRating(rating); + return this; + } + + /** + * Sets the rating (the number of stars filled) and max of PermissionManagerActivity RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @param max The range of the RatingBar to 0...max. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating, int max) { + RatingBar view = getView(viewId); + view.setMax(max); + view.setRating(rating); + return this; + } + + /** + * Sets the on click listener of the view. + * + * @param viewId The view id. + * @param listener The on click listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) { + View view = getView(viewId); + view.setOnClickListener(listener); + return this; + } + + + + + + + /** + * Sets the on touch listener of the view. + * + * @param viewId The view id. + * @param listener The on touch listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener) { + View view = getView(viewId); + view.setOnTouchListener(listener); + return this; + } + + + /** + * Sets the listview or gridview's item long click listener of the view + * + * @param viewId The view id. + * @param listener The item long click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemLongClickListener(@IdRes int viewId, AdapterView.OnItemLongClickListener listener) { + AdapterView view = getView(viewId); + view.setOnItemLongClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item selected click listener of the view + * + * @param viewId The view id. + * @param listener The item selected click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemSelectedClickListener(@IdRes int viewId, AdapterView.OnItemSelectedListener listener) { + AdapterView view = getView(viewId); + view.setOnItemSelectedListener(listener); + return this; + } + + /** + * Sets the on checked change listener of the view. + * + * @param viewId The view id. + * @param listener The checked change listener of compound button. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnCheckedChangeListener(@IdRes int viewId, CompoundButton.OnCheckedChangeListener listener) { + CompoundButton view = getView(viewId); + view.setOnCheckedChangeListener(listener); + return this; + } + + + public BaseViewHolder addOnClickListener(@IdRes final int viewId) { + childClickViewIds.add(viewId); + final View view = getView(viewId); + if (view != null) { + if (!view.isClickable()) { + view.setClickable(true); + } + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (adapter.getOnItemChildClickListener() != null) { + adapter.getOnItemChildClickListener().onItemChildClick(adapter, v, getClickPosition()); + } + } + }); + } + + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, Object tag) { + View view = getView(viewId); + view.setTag(tag); + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param key The key of tag; + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, int key, Object tag) { + View view = getView(viewId); + view.setTag(key, tag); + return this; + } + + /** + * Sets the checked status of PermissionManagerActivity checkable. + * + * @param viewId The view id. + * @param checked The checked status; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setChecked(@IdRes int viewId, boolean checked) { + View view = getView(viewId); + // View unable cast to Checkable + if (view instanceof Checkable) { + ((Checkable) view).setChecked(checked); + } + return this; + } + + /** + * Sets the adapter of PermissionManagerActivity adapter view. + * + * @param viewId The view id. + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + @SuppressWarnings("unchecked") + public BaseViewHolder setAdapter(@IdRes int viewId, Adapter adapter) { + AdapterView view = getView(viewId); + view.setAdapter(adapter); + return this; + } + + /** + * Sets the adapter of PermissionManagerActivity adapter view. + * + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + protected BaseViewHolder setAdapter(BaseRecyclerAdapter adapter) { + this.adapter = adapter; + return this; + } + + @SuppressWarnings("unchecked") + public T getView(@IdRes int viewId) { + View view = views.get(viewId); + if (view == null) { + view = itemView.findViewById(viewId); + views.put(viewId, view); + } + return (T) view; + } + + /** + * Retrieves the last converted object on this view. + */ + public Object getAssociatedObject() { + return associatedObject; + } + + /** + * Should be called during convert + */ + public void setAssociatedObject(Object associatedObject) { + this.associatedObject = associatedObject; + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/DividerItemDecoration.java b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/DividerItemDecoration.java new file mode 100644 index 0000000..5ef7580 --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/DividerItemDecoration.java @@ -0,0 +1,138 @@ +package vip.devkit.debugkit.widget.recyclerview; + +import android.annotation.TargetApi; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class DividerItemDecoration extends RecyclerView.ItemDecoration { + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + private static final String TAG = "TitleItem"; + private Drawable mDivider; + private int mOrientation; + private final Rect mBounds = new Rect(); + private boolean mShowHeaderDivider; + private boolean mShowFooterDivider = true; + + public DividerItemDecoration(int orientation) { + this.setOrientation(orientation); + } + + public void setOrientation(int orientation) { + if (orientation != 0 && orientation != 1) { + throw new IllegalArgumentException("Invalid orientation. It should be either HORIZONTAL or VERTICAL"); + } else { + this.mOrientation = orientation; + } + } + + public void setDrawable(@NonNull Drawable drawable) { + this.mDivider = drawable; + } + + @Override + public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { + if (parent.getLayoutManager() != null && this.mDivider != null) { + if (this.mOrientation == 1) { + this.drawVertical(c, parent); + } else { + this.drawHorizontal(c, parent); + } + } + } + + public void showHeaderDivider(boolean show) { + mShowHeaderDivider = show; + } + + public void showFooterDivider(boolean show) { + mShowFooterDivider = show; + } + + private void drawVertical(Canvas canvas, RecyclerView parent) { + canvas.save(); + int left; + int right; + if (parent.getClipToPadding()) { + left = parent.getPaddingLeft(); + right = parent.getWidth() - parent.getPaddingRight(); + int top = parent.getPaddingTop(); + int bottom = parent.getHeight() - parent.getPaddingBottom(); + canvas.clipRect(left, top, right, bottom); + } else { + left = 0; + right = parent.getWidth(); + } + + int childCount = parent.getChildCount(); + + for (int i = 0; i < childCount; ++i) { + View child = parent.getChildAt(i); + parent.getDecoratedBoundsWithMargins(child, this.mBounds); + + int top; + int bottom; + if (i == 0 && mShowHeaderDivider) { + top = 0; + this.mDivider.setBounds(left, top, right, top + this.mDivider.getIntrinsicHeight()); + this.mDivider.draw(canvas); + } + + if (i != childCount - 1 || mShowFooterDivider) { + bottom = this.mBounds.bottom + Math.round(child.getTranslationY()); + top = bottom - this.mDivider.getIntrinsicHeight(); + this.mDivider.setBounds(left, top, right, bottom); + this.mDivider.draw(canvas); + } + } + canvas.restore(); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private void drawHorizontal(Canvas canvas, RecyclerView parent) { + canvas.save(); + int top; + int bottom; + if (parent.getClipToPadding()) { + top = parent.getPaddingTop(); + bottom = parent.getHeight() - parent.getPaddingBottom(); + canvas.clipRect(parent.getPaddingLeft(), top, parent.getWidth() - parent.getPaddingRight(), bottom); + } else { + top = 0; + bottom = parent.getHeight(); + } + + int childCount = parent.getChildCount(); + + for (int i = 0; i < childCount; ++i) { + View child = parent.getChildAt(i); + parent.getLayoutManager().getDecoratedBoundsWithMargins(child, this.mBounds); + int right = this.mBounds.right + Math.round(child.getTranslationX()); + int left = right - this.mDivider.getIntrinsicWidth(); + this.mDivider.setBounds(left, top, right, bottom); + this.mDivider.draw(canvas); + } + + canvas.restore(); + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + if (this.mDivider == null) { + outRect.set(0, 0, 0, 0); + } else { + if (this.mOrientation == 1) { + outRect.set(0, 0, 0, this.mDivider.getIntrinsicHeight()); + } else { + outRect.set(0, 0, this.mDivider.getIntrinsicWidth(), 0); + } + + } + } +} \ No newline at end of file diff --git a/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/S.java b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/S.java new file mode 100644 index 0000000..cce24ca --- /dev/null +++ b/dklib/src/main/java/vip/devkit/debugkit/widget/recyclerview/S.java @@ -0,0 +1,33 @@ +package vip.devkit.debugkit.widget.recyclerview; + +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +/** + * Package Name: vip.devkit.debugkit.widget.recyclerview + * File Name: S.java + * Create Date: 2019/7/1 14:17 + * Author : K + * E-mail : vip@devkit.vip + * VersionCode : V 1.0 + * Describe : + * Code Update :(author - time) + * Update Describe: + */ +public class S extends BaseRecyclerAdapter { + + public S(int layoutResId, @Nullable List data) { + super(layoutResId, data); + } + + @Override + protected void convert(BaseViewHolder helper, String mItem) { + + } + +} diff --git a/dklib/src/main/res/drawable/shape_group_kit_background.xml b/dklib/src/main/res/drawable/shape_group_kit_background.xml new file mode 100644 index 0000000..70b4774 --- /dev/null +++ b/dklib/src/main/res/drawable/shape_group_kit_background.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/dklib/src/main/res/layout/act_kit_manager.xml b/dklib/src/main/res/layout/act_kit_manager.xml new file mode 100644 index 0000000..5342846 --- /dev/null +++ b/dklib/src/main/res/layout/act_kit_manager.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dklib/src/main/res/layout/dk_activity_base_url.xml b/dklib/src/main/res/layout/dk_activity_base_url.xml new file mode 100644 index 0000000..9fe4d2a --- /dev/null +++ b/dklib/src/main/res/layout/dk_activity_base_url.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + +