diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index dfe2a9cc..a5a6c41b 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -89,11 +89,6 @@
-
diff --git a/.travis.yml b/.travis.yml
index 794108a4..001ed074 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,13 @@
language: java
os: linux
-dist: bionic
+dist: focal
group: edge
git:
depth: false
env:
global:
- # for updates check (dl.google.com/android/repository/repository2-1.xml)
- - ANDROID_SDK_CMD_TOOLS=commandlinetools-linux-5842447_latest.zip
+ # for updates check https://developer.android.com/studio#downloads
+ - ANDROID_SDK_CMD_TOOLS=commandlinetools-linux-6825553_latest.zip
# storepass, keypass, keyalias
- secure: K4PVOrcYr6ZV16GgZWcw5RGDqxRTrilMK6pjz1r+RkQX6EPywmTsUH0y8EGP44bZc+TFMM0UfGPulHfrKzC3LDVSe+CpvNdQqq8c2Ysc9lQLubvFmVlWZ2rjHhA3jtg33FDIAWipb41WZEdmCJE1EI+OMbh8p8/7cGZ4K4tpd3B8ViXrf16ht50C56glL1lS3Jog/g9OEIPdhzYF23nYPOAeV3xJg3WBGxUUMOwp3vrpMJ/bYvnh/XLHUpPWnCcSWhKZolE3C6Itlv3CUdCyd2u8dnbTFX7KK0g4nrJdXJAyith0aE2RB6APdDDIdZkF3p2qU3aWBWVvNzjGc6tYpP9OB8sjobcx9oG8lIaO09qZnM+fLTs5b3ulvl8d3UZI0KxgSocvjxpltrqeuNODGarzwIWAmjxKr3Qnfo5LFUna1UMxKJ1ARyT7zS9yUbfE6ek42aEe7rEaqryjNFE5X6b9D2WexN+68YynvdRfDXlFx2JIW3hWTi7AG4zBI0LKhhtruwLY1hKty3JR5/Dz/dIMW6JZUmLdE7drPmLNBcKRh1H778EOcaD+1q1bzVnwbA+HLfHkO9Rzmk7UOY1ttWzFBH23W/pI6D6mn4WTFng0/iOEsw7fwHaXPGv6ZXxserC/nzmeYb0AfK3wq2p2ztEDtbSblw9lkMBYlvNi5I8=
- secure: SEcF7dl6ImTdeUYtw6dGeHRXbS4h8Ec9+Dnt2rFeobupo4e64818Fo10Uqqf+eM/5VVF2FAJLnEiq1SgfWZKjvUz9batJZNknc2JSKEGQPFaUD55USFCt2rxoLPFJKIee07kPTiXGPM2WWA+42cD+HpXAErMTd3BESsGwjni+xj2PhJuETDGrw+0D5T4TOXgd0uXNPl4p1PE+l3SejPqGQ961Wo+hbxd/y9JyZy/jZ9WW8XA6eEXXtecRY33NspwT58mBXDgZLIM/C3W0qfrGCiOPxwk0RpMo7YMbmYVPLG75AzihDtQ2F7P5edHz7v0yCAejrN23hi1LHb4Uku8tC2jzrH5eUpKfZuqap8DRcbdXq5je3oeuLSUu39FrzsDEmennS0eaD4jTsB5Sy2wld/UCmzV0QenUtPdBaFLU2Rxos3xJW4a2KyENRm5TGVNR/NAWpoacLed3zqDmb3K13WwskTGE1/mXRl+o0T0BVOBXuHXQ+nqATnGuAbw97LhhOeBZ/jA2yWBsaTxdjhB3E3uKWYZYdGIIgOwrZdM0RrVSgepg7NP+vh9iO70ckEzP+w4yws2ElKE3ZiOexEmrkFmqlxQW08b1FMaKJwpfsNiHkwW6u1jq1oeEBIzUrAMmo92uAjDAHKfn7FOsx5RVg20EKP9Rk9l2YKRA5dGJFI=
@@ -22,9 +22,10 @@ before_install:
# download and unzip Android SDK command line tools
- wget -nv https://dl.google.com/android/repository/$ANDROID_SDK_CMD_TOOLS
- mkdir -p $HOME/sdk/cmdline-tools && unzip -q $ANDROID_SDK_CMD_TOOLS -d $HOME/sdk/cmdline-tools
+ - mv $HOME/sdk/cmdline-tools/cmdline-tools $HOME/sdk/cmdline-tools/latest
# set SDK tools path variable and ANDROID_HOME
- - export PATH=$PATH:$HOME/sdk/cmdline-tools/tools/bin
- - export ANDROID_HOME=$HOME/sdk
+ - export PATH=$PATH:$HOME/sdk/cmdline-tools/latest/bin
+ - export ANDROID_SDK_ROOT=$HOME/sdk
# create empty cfg file to prevent sdkmanager warning message
- mkdir -p $HOME/.android && touch $HOME/.android/repositories.cfg
# decrypt private keystore
@@ -44,13 +45,7 @@ before_script:
# log all gradle warnings
- echo "org.gradle.warning.mode=all" >> $HOME/.gradle/gradle.properties
# control gradle build cache
- - if [[ $CACHING == "true" ]]; then
- echo "org.gradle.caching=true" >> $HOME/.gradle/gradle.properties;
- echo "android.enableBuildCache=true" >> $HOME/.gradle/gradle.properties;
- else
- echo "org.gradle.caching=false" >> $HOME/.gradle/gradle.properties;
- echo "android.enableBuildCache=false" >> $HOME/.gradle/gradle.properties;
- fi
+ - echo "org.gradle.caching=$CACHING" >> $HOME/.gradle/gradle.properties;
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -rf $HOME/.gradle/caches/*/plugin-resolution/
@@ -72,12 +67,12 @@ jobs:
- # Build debug
if: branch IN (develop, master)
env: CACHING=true
- script: "./gradlew assembleDebug --scan"
+ script: "./gradlew assembleDebug"
- # Build and deploy release on tags
if: tag IS present
env: CACHING=false
script:
- - "./gradlew assembleRelease -Pmy_storepass=$storepass -Pmy_keyalias=$keyalias -Pmy_keypass=$keypass --scan"
+ - "./gradlew assembleRelease -Pmy_storepass=$storepass -Pmy_keyalias=$keyalias -Pmy_keypass=$keypass"
- "./gradlew :app:bundleRelease -Pmy_storepass=$storepass -Pmy_keyalias=$keyalias -Pmy_keypass=$keypass"
deploy:
provider: releases
@@ -87,7 +82,7 @@ jobs:
file:
- $TRAVIS_BUILD_DIR/app/build/outputs/bundle/release/*.aab
- $TRAVIS_BUILD_DIR/app/build/outputs/apk/release/*.apk
- - $TRAVIS_BUILD_DIR/app/build/outputs/mapping/release/mapping.txt
+ - $TRAVIS_BUILD_DIR/app/build/outputs/mapping/release/*mapping.txt
draft: false
on:
tags: true
diff --git a/README.md b/README.md
index 90e983f4..b84719eb 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# Developer Widget [![Build Status](https://travis-ci.com/G00fY2/DeveloperWidget.svg?branch=develop)](https://travis-ci.com/G00fY2/DeveloperWidget) [![Release](https://img.shields.io/github/release/G00fY2/DeveloperWidget.svg)](https://github.com/G00fY2/DeveloperWidget/releases) [![API](https://img.shields.io/badge/API-14%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=14)
+# Developer Widget [![Build Status](https://travis-ci.com/G00fY2/DeveloperWidget.svg?branch=develop)](https://travis-ci.com/G00fY2/DeveloperWidget) [![Release](https://img.shields.io/github/v/release/G00fY2/DeveloperWidget)](https://github.com/G00fY2/DeveloperWidget/releases) [![Pre-Release](https://img.shields.io/github/v/release/G00fY2/DeveloperWidget?include_prereleases&label=pre-release)](https://github.com/G00fY2/DeveloperWidget/releases) [![API](https://img.shields.io/badge/API-14%2B-blue.svg?style=flat)](https://developer.android.com/studio/releases/platforms#4.0)
**Lightweight Android app that offers a widget to show device data, manage installed apps and list locally stored APK files.**
@@ -12,7 +12,10 @@
[](https://raw.githubusercontent.com/G00fY2/DeveloperWidget/gh-pages/media/store_screenshot_4.png)
[](https://raw.githubusercontent.com/G00fY2/DeveloperWidget/gh-pages/media/store_screenshot_5.png)
-created with [App Mockup](https://app-mockup.com)
+## Download
+
+
+You also find the latest APK in the [GitHub releases](https://github.com/G00fY2/DeveloperWidget/releases).
## Description
The app was built from a developer for developers. You may know the hassle of having multiple physical devices running different software. This app will help you keep track of important device information and allows you to organize your apps and local APK files. You will never again struggle to find APK files using a file browser or search for the app settings menu on a custom manufacturer UI.
@@ -48,11 +51,6 @@ The main feature of the app is an 4x1 (horizontally resizable) homescreen widget
* Show more information in the APK install view
* currently installed version, filepath, certificates ...
-## Download
-
-
-You also find the latest APK in the [GitHub releases](https://github.com/G00fY2/DeveloperWidget/releases).
-
## Release Notes
Check out the [Release Notes](https://github.com/G00fY2/DeveloperWidget/releases) to find out what changed
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index cab961bd..00000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,102 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'eu.appcom.gradle.android-versioning'
-
-android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
- defaultConfig {
- applicationId 'com.g00fy2.developerwidget'
- minSdkVersion rootProject.minSdkVersion
- targetSdkVersion rootProject.targetSdkVersion
- versionCode versioning.getVersionCode()
- versionName versioning.getVersionName()
-
- vectorDrawables.useSupportLibrary = true
- }
- signingConfigs {
- release {
- storeFile file('../keystore.jks')
- storePassword project.hasProperty('my_storepass') ? my_storepass : ''
- keyAlias project.hasProperty('my_keyalias') ? my_keyalias : ''
- keyPassword project.hasProperty('my_keypass') ? my_keypass : ''
- v1SigningEnabled true
- v2SigningEnabled true
- }
- }
- buildTypes {
- debug {
- applicationIdSuffix '.debug'
- }
- release {
- signingConfig signingConfigs.release
- shrinkResources true
- minifyEnabled true
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
- buildFeatures {
- viewBinding = true
- }
- versioning {
- baseName = 'developerwidget'
- }
- applicationVariants.all { variant ->
- if (variant.getName().toLowerCase().contains('release')) {
- variant.outputs.all {
- outputFileName = versioning.getApkName(variant)
- }
- }
- }
- sourceSets {
- main.java.srcDirs += 'src/main/kotlin'
- }
- compileOptions {
- sourceCompatibility = '1.8'
- targetCompatibility = '1.8'
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
-}
-
-repositories {
- google()
- mavenCentral()
- jcenter {
- content {
- includeModule 'com.g00fy2', 'versioncompare'
- includeModule 'org.jetbrains.trove4j', 'trove4j' // required by com.android.tools.lint:lint-gradle
- }
- }
-}
-dependencies {
- // Kotlin
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
-
- // AndroidX
- implementation "androidx.appcompat:appcompat:$appcompatVersion"
- implementation "androidx.core:core-ktx:$coreKtxVersion"
- implementation "androidx.activity:activity:$activityVersion"
- implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
- implementation "androidx.recyclerview:recyclerview:$recyclerviewVersion"
- implementation "androidx.constraintlayout:constraintlayout:$constraintlayoutVersion"
- implementation "androidx.vectordrawable:vectordrawable:$vectorDrawableVersion"
-
- // UI
- implementation "com.google.android.material:material:$materialVersion"
-
- // Misc
- implementation "com.jakewharton.timber:timber:$timberVersion"
- implementation "com.g00fy2:versioncompare:$versCompVersion"
-
- // Dagger
- implementation "com.google.dagger:dagger:$daggerVersion"
- kapt "com.google.dagger:dagger-compiler:$daggerVersion"
- implementation "com.google.dagger:dagger-android:$daggerVersion"
- implementation "com.google.dagger:dagger-android-support:$daggerVersion"
- kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
- compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
-}
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 00000000..a7bd5283
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,107 @@
+plugins {
+ id("com.android.application")
+ kotlin("android")
+ kotlin("kapt")
+ id("de.nanogiants.android-versioning")
+}
+
+android {
+ compileSdkVersion(29)
+ buildToolsVersion = "30.0.2"
+ defaultConfig {
+ applicationId = "com.g00fy2.developerwidget"
+ minSdkVersion(14)
+ targetSdkVersion(29)
+ versionCode = versioning.getVersionCode()
+ versionName = versioning.getVersionName()
+
+ vectorDrawables.useSupportLibrary = true
+ setProperty("archivesBaseName", "developerwidget")
+ }
+ signingConfigs {
+ create("release") {
+ storeFile = file("../keystore.jks")
+ storePassword = findProperty("my_storepass") as String?
+ keyAlias = findProperty("my_keyalias") as String?
+ keyPassword = findProperty("my_keypass") as String?
+ }
+ }
+ buildTypes {
+ getByName("debug") {
+ applicationIdSuffix = ".debug"
+ }
+ getByName("release") {
+ signingConfig = signingConfigs.getByName("release")
+ isShrinkResources = true
+ isMinifyEnabled = true
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+ buildFeatures {
+ viewBinding = true
+ aidl = false
+ renderScript = false
+ resValues = false
+ shaders = false
+ }
+ sourceSets {
+ getByName("main").java.srcDirs("src/main/kotlin")
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8.toString()
+ useIR = true
+ }
+ lintOptions {
+ isCheckReleaseBuilds = false // TODO remove when https://issuetracker.google.com/issues/141126614 is fixed
+ }
+ dependenciesInfo {
+ includeInApk = false
+ }
+}
+
+versioning {
+ keepOriginalMappingFile = false
+}
+
+repositories {
+ google()
+ mavenCentral()
+ jcenter {
+ content {
+ includeModule("com.g00fy2", "versioncompare")
+ includeModule("org.jetbrains.trove4j", "trove4j") // required by com.android.tools.lint:lint-gradle
+ }
+ }
+}
+dependencies {
+ // Kotlin
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
+
+ // AndroidX
+ implementation("androidx.appcompat:appcompat:1.3.0-alpha02")
+ implementation("androidx.core:core-ktx:1.5.0-alpha04")
+ implementation("androidx.activity:activity:1.2.0-beta01")
+ implementation("androidx.fragment:fragment:1.3.0-beta01")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-beta01")
+ implementation("androidx.recyclerview:recyclerview:1.2.0-alpha06")
+ implementation("androidx.constraintlayout:constraintlayout:2.0.2")
+ implementation("androidx.vectordrawable:vectordrawable:1.2.0-alpha02")
+
+ // UI
+ implementation("com.google.android.material:material:1.3.0-alpha03")
+
+ // Misc
+ implementation("com.jakewharton.timber:timber:4.7.1")
+ implementation("com.g00fy2:versioncompare:1.3.5")
+
+ // Dagger
+ implementation("com.google.dagger:dagger:2.29.1")
+ kapt("com.google.dagger:dagger-compiler:2.29.1")
+ implementation("com.google.dagger:dagger-android:2.29.1")
+ implementation("com.google.dagger:dagger-android-support:2.29.1")
+ kapt("com.google.dagger:dagger-android-processor:2.29.1")
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1ef531ce..dfcf9068 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,7 +2,7 @@
+ tools:ignore="LockedOrientationActivity,GoogleAppIndexingWarning">
@@ -14,9 +14,7 @@
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:supportsRtl="false"
- android:theme="@style/AppTheme"
- tools:ignore="GoogleAppIndexingWarning"
- tools:targetApi="q">
+ android:theme="@style/AppTheme">
= DaggerAppComponent.factory().create(this)
-
@Inject
lateinit var dayNightController: DayNightController
+ override fun applicationInjector(): AndroidInjector = DaggerAppComponent.factory().create(this)
+
override fun onCreate() {
super.onCreate()
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutActivity.kt
index 45156673..afa05e0b 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutActivity.kt
@@ -5,31 +5,43 @@ import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
+import android.os.Bundle
import android.view.MenuItem
+import android.view.View
import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
-import androidx.viewbinding.ViewBinding
import com.g00fy2.developerwidget.BuildConfig
import com.g00fy2.developerwidget.R
+import com.g00fy2.developerwidget.activities.about.dialogs.AboutFeedbackDialog
+import com.g00fy2.developerwidget.activities.about.dialogs.SearchDepthDialog
import com.g00fy2.developerwidget.activities.widgetconfig.ConfigLauncherActivity
import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.base.BaseContract.BasePresenter
import com.g00fy2.developerwidget.databinding.ActivityAboutBinding
import com.g00fy2.developerwidget.ktx.doOnApplyWindowInsets
-import com.g00fy2.developerwidget.ktx.gesturalNavigationMode
import javax.inject.Inject
class AboutActivity : BaseActivity(), AboutContract.AboutView {
@Inject
lateinit var presenter: AboutContract.AboutPresenter
- private lateinit var binding: ActivityAboutBinding
+ override val binding: ActivityAboutBinding by viewBinding(ActivityAboutBinding::inflate)
override fun providePresenter(): BasePresenter = presenter
- override fun setViewBinding(): ViewBinding {
- binding = ActivityAboutBinding.inflate(layoutInflater)
- return binding
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (intent.getBooleanExtra(SCROLL_BOTTOM, false)) {
+ intent.removeExtra(SCROLL_BOTTOM)
+ binding.aboutRootScrollview.run {
+ postDelayed({ smoothScrollTo(0, bottom) }, 300)
+ setPressedState(binding.searchDepthItem, true, 600)
+ setPressedState(binding.searchDepthItem, false, 800)
+ setPressedState(binding.searchDepthItem, true, 1000)
+ }
+ }
}
override fun initView() {
@@ -97,6 +109,9 @@ class AboutActivity : BaseActivity(), AboutContract.AboutView {
description(R.string.icon_credits_description)
action { presenter.openUrl(ICON_CREDITS) }
}
+ binding.searchDepthItem.init {
+ title(R.string.search_apk_depth)
+ }
binding.hideLauncherIconItem.init {
title(R.string.show_app_icon)
description(R.string.show_app_icon_description)
@@ -110,11 +125,14 @@ class AboutActivity : BaseActivity(), AboutContract.AboutView {
if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
binding.aboutRootScrollview.apply {
doOnApplyWindowInsets { _, insets, padding, _ ->
- updatePadding(bottom = padding.bottom + insets.systemWindowInsetBottom)
+ updatePadding(
+ bottom = padding.bottom + WindowInsetsCompat.toWindowInsetsCompat(insets)
+ .getInsets(WindowInsetsCompat.Type.systemBars()).bottom
+ )
}
viewTreeObserver.addOnScrollChangedListener {
val scrollableRange = getChildAt(0).bottom - height + paddingBottom
- if (!gesturalNavigationMode()) {
+ if (!isGesturalNavMode()) {
clipToPadding = (scrollY >= scrollableRange)
}
}
@@ -148,6 +166,16 @@ class AboutActivity : BaseActivity(), AboutContract.AboutView {
}
}
+ override fun updateSearchDepthUi(depth: Int) {
+ val description = when (depth) {
+ 0 -> getString(R.string.infinite_depth)
+ 2 -> getString(R.string.default_depth, depth)
+ else -> depth.toString()
+ }
+ binding.searchDepthItem.description(description)
+ binding.searchDepthItem.action { showSearchDepthOptions(depth) }
+ }
+
private fun updateLauncherIconSwitch() = binding.hideLauncherIconItem.switch(!isLauncherIconDisabled())
private fun updateLauncherIconItem() {
@@ -161,6 +189,13 @@ class AboutActivity : BaseActivity(), AboutContract.AboutView {
}.show()
}
+ private fun showSearchDepthOptions(currentDepth: Int) {
+ SearchDepthDialog(this).init {
+ initialValue(currentDepth)
+ onPositive { presenter.saveSearchDepth(it) }
+ }.show()
+ }
+
private fun isLauncherIconDisabled(): Boolean {
return packageManager.getComponentEnabledSetting(
ComponentName(
@@ -185,4 +220,12 @@ class AboutActivity : BaseActivity(), AboutContract.AboutView {
updateLauncherIconItem()
presenter.showRebootNotice()
}
+
+ private fun setPressedState(item: View, pressed: Boolean, delay: Int) {
+ item.run { postDelayed({ isPressed = pressed }, delay.toLong()) }
+ }
+
+ companion object {
+ const val SCROLL_BOTTOM = "scrollBottom"
+ }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutContract.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutContract.kt
index cd6545f7..fe218aa9 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutContract.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutContract.kt
@@ -7,6 +7,8 @@ interface AboutContract {
interface AboutView : BaseContract.BaseView {
fun updateThemeToggleView()
+
+ fun updateSearchDepthUi(depth: Int)
}
interface AboutPresenter : BaseContract.BasePresenter {
@@ -20,5 +22,9 @@ interface AboutContract {
fun honorClicking()
fun showRebootNotice()
+
+ fun updateSearchDepth()
+
+ fun saveSearchDepth(depth: Int)
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutPresenterImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutPresenterImpl.kt
index abef8a49..2677114a 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutPresenterImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutPresenterImpl.kt
@@ -1,23 +1,38 @@
package com.g00fy2.developerwidget.activities.about
+import androidx.lifecycle.Lifecycle.Event
+import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.lifecycleScope
import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.base.BasePresenterImpl
import com.g00fy2.developerwidget.controllers.DayNightController
import com.g00fy2.developerwidget.controllers.IntentController
+import com.g00fy2.developerwidget.controllers.PreferenceController
+import com.g00fy2.developerwidget.controllers.StringController
import com.g00fy2.developerwidget.controllers.ToastController
+import kotlinx.coroutines.launch
import javax.inject.Inject
class AboutPresenterImpl @Inject constructor() : BasePresenterImpl(), AboutContract.AboutPresenter {
@Inject
lateinit var view: AboutContract.AboutView
+
@Inject
lateinit var intentController: IntentController
+
@Inject
lateinit var toastController: ToastController
+
@Inject
lateinit var dayNightController: DayNightController
+ @Inject
+ lateinit var stringController: StringController
+
+ @Inject
+ lateinit var preferenceController: PreferenceController
+
private var clickCount = 0
private var clickStart: Long = 0
@@ -47,4 +62,21 @@ class AboutPresenterImpl @Inject constructor() : BasePresenterImpl(), AboutContr
}
override fun showRebootNotice() = toastController.showToast(R.string.reboot_notice)
+
+ @OnLifecycleEvent(Event.ON_CREATE)
+ override fun updateSearchDepth() {
+ view.lifecycleScope.launch {
+ val actualDepth = preferenceController.get(PreferenceController.SEARCH_DEPTH, 2)
+ val depth = if (actualDepth == Int.MAX_VALUE) 0 else actualDepth
+ view.updateSearchDepthUi(depth)
+ }
+ }
+
+ override fun saveSearchDepth(depth: Int) {
+ val actualDepth = if (depth == 0) Int.MAX_VALUE else depth
+ view.lifecycleScope.launch {
+ preferenceController.set(PreferenceController.SEARCH_DEPTH, actualDepth)
+ }
+ updateSearchDepth()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutFeedbackDialog.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/AboutFeedbackDialog.kt
similarity index 82%
rename from app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutFeedbackDialog.kt
rename to app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/AboutFeedbackDialog.kt
index 5fc55e7b..017c3250 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/AboutFeedbackDialog.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/AboutFeedbackDialog.kt
@@ -1,4 +1,4 @@
-package com.g00fy2.developerwidget.activities.about
+package com.g00fy2.developerwidget.activities.about.dialogs
import android.content.Context
import androidx.appcompat.app.AppCompatDialog
@@ -7,8 +7,8 @@ import com.g00fy2.developerwidget.databinding.AboutFeedbackDialogBinding
class AboutFeedbackDialog(context: Context) {
- private var binding: AboutFeedbackDialogBinding
- private val dialog = AppCompatDialog(context, R.style.DialogTheme).apply {
+ private val binding: AboutFeedbackDialogBinding
+ private val dialog = AppCompatDialog(context, R.style.DialogNestedTheme).apply {
setCancelable(true)
setCanceledOnTouchOutside(true)
binding = AboutFeedbackDialogBinding.inflate(layoutInflater)
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/SearchDepthDialog.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/SearchDepthDialog.kt
new file mode 100644
index 00000000..d40b2cfd
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/about/dialogs/SearchDepthDialog.kt
@@ -0,0 +1,40 @@
+package com.g00fy2.developerwidget.activities.about.dialogs
+
+import android.content.Context
+import android.view.WindowManager
+import androidx.appcompat.app.AppCompatDialog
+import com.g00fy2.developerwidget.R
+import com.g00fy2.developerwidget.databinding.AboutSearchDepthDialogBinding
+
+class SearchDepthDialog(context: Context) {
+
+ private val binding: AboutSearchDepthDialogBinding
+ private val dialog = AppCompatDialog(context, R.style.DialogNestedTheme).apply {
+ setCancelable(true)
+ setCanceledOnTouchOutside(true)
+ binding = AboutSearchDepthDialogBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ binding.dialogCancelTextview.setOnClickListener { dismiss() }
+ binding.inputEdittext.requestFocus()
+ window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
+ }
+
+ fun initialValue(depth: Int): SearchDepthDialog {
+ binding.inputEdittext.setText(depth.toString())
+ binding.inputEdittext.setSelection(depth.toString().length)
+ return this
+ }
+
+ fun onPositive(onPositiveAction: (Int) -> Unit): SearchDepthDialog {
+ binding.dialogOkTextview.setOnClickListener {
+ onPositiveAction(binding.inputEdittext.text.toString().toIntOrNull() ?: 2)
+ dialog.dismiss()
+ }
+ return this
+ }
+
+ fun init(func: SearchDepthDialog.() -> Unit): AppCompatDialog {
+ func()
+ return dialog
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivity.kt
index 446eba38..df123bf9 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivity.kt
@@ -1,14 +1,19 @@
package com.g00fy2.developerwidget.activities.apkinstall
+import android.content.Intent
import android.view.View
import androidx.appcompat.widget.TooltipCompat
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.viewbinding.ViewBinding
import com.g00fy2.developerwidget.R
+import com.g00fy2.developerwidget.activities.about.AboutActivity
+import com.g00fy2.developerwidget.activities.about.AboutActivity.Companion.SCROLL_BOTTOM
+import com.g00fy2.developerwidget.activities.apkinstall.dialogs.ApkDeleteDialog
+import com.g00fy2.developerwidget.activities.apkinstall.dialogs.ApkWarningDialog
import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.base.BaseContract.BasePresenter
import com.g00fy2.developerwidget.databinding.ActivityApkBinding
+import com.g00fy2.developerwidget.ktx.setClickableText
import javax.inject.Inject
class ApkActivity : BaseActivity(true), ApkContract.ApkView {
@@ -16,33 +21,28 @@ class ApkActivity : BaseActivity(true), ApkContract.ApkView {
@Inject
lateinit var presenter: ApkContract.ApkPresenter
+ override val binding: ActivityApkBinding by viewBinding(ActivityApkBinding::inflate)
private lateinit var adapter: ApkAdapter
- private lateinit var binding: ActivityApkBinding
override fun providePresenter(): BasePresenter = presenter
- override fun setViewBinding(): ViewBinding {
- binding = ActivityApkBinding.inflate(layoutInflater)
- return binding
- }
-
override fun initView() {
adapter = ApkAdapter()
- adapter.setOnApkClicked { apkFile -> presenter.installApk(apkFile) }
+ adapter.setOnApkClicked { apkFile -> presenter.installOrShowPermissionWarning(apkFile) }
adapter.setOnApkSelect { selectedCount -> showOptions(selectedCount > 0) }
- adapter.setCommitCallback(Runnable {
+ adapter.setCommitCallback {
adapter.itemCount.let {
binding.recyclerview.overScrollMode = if (it == 0) View.OVER_SCROLL_NEVER else View.OVER_SCROLL_ALWAYS
binding.noItemsTextview.visibility = if (it == 0) View.VISIBLE else View.INVISIBLE
binding.noItemsImageview.visibility = if (it == 0) View.VISIBLE else View.INVISIBLE
}
- })
+ }
binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(this)
binding.recyclerview.adapter = adapter
binding.cancelTextview.setOnClickListener { finish() }
- TooltipCompat.setTooltipText(binding.clearImageview, binding.clearImageview.contentDescription)
+ TooltipCompat.setTooltipText(binding.deleteImageview, binding.deleteImageview.contentDescription)
binding.deleteImageview.setOnClickListener { showConfirmationDialog() }
TooltipCompat.setTooltipText(binding.clearImageview, binding.clearImageview.contentDescription)
binding.clearImageview.setOnClickListener {
@@ -51,23 +51,21 @@ class ApkActivity : BaseActivity(true), ApkContract.ApkView {
}
}
- override fun onResume() {
- super.onResume()
- if (adapter.itemCount == 0) {
- binding.progressbar.visibility = View.VISIBLE
- binding.noItemsImageview.visibility = View.INVISIBLE
- binding.noItemsTextview.text = getString(R.string.scanning_apks)
- binding.noItemsTextview.visibility = View.VISIBLE
- }
- }
-
- override fun toggleResultView(apkFiles: List, missingPermissions: Boolean) {
+ override fun toggleResultView(apkFiles: List, missingPermissions: Boolean, searchDepth: Int) {
if (missingPermissions) {
binding.progressbar.visibility = View.GONE
binding.noItemsTextview.text = getString(R.string.missing_permissions)
} else {
binding.noItemsTextview.visibility = View.INVISIBLE
- binding.noItemsTextview.text = getString(R.string.no_apk_found)
+ if (searchDepth != Int.MAX_VALUE) {
+ binding.noItemsTextview.setClickableText(
+ getString(R.string.no_apk_found) + "\n" + getString(R.string.no_apk_found_search_depth, searchDepth),
+ getString(R.string.no_apk_found_search_depth, searchDepth)
+ ) { openAboutActivity() }
+ } else {
+ binding.noItemsTextview.text = getString(R.string.no_apk_found)
+ }
+
ViewCompat.animate(binding.progressbar).alpha(0f)
.setDuration(resources.getInteger(android.R.integer.config_shortAnimTime).toLong()).withEndAction {
binding.progressbar.visibility = View.INVISIBLE
@@ -77,6 +75,20 @@ class ApkActivity : BaseActivity(true), ApkContract.ApkView {
adapter.submitList(apkFiles)
}
+ override fun showPermissionWarning(apkFile: ApkFile) {
+ ApkWarningDialog(this).init {
+ installCallback { presenter.installApk(apkFile) }
+ permissionList(apkFile.dangerousPermissions)
+ }.show()
+ }
+
+ private fun openAboutActivity() {
+ startActivity(Intent(this, AboutActivity::class.java).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ putExtra(SCROLL_BOTTOM, true)
+ })
+ }
+
private fun showOptions(show: Boolean) {
binding.deleteHeaderGroup.visibility = if (show) View.VISIBLE else View.GONE
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivityModule.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivityModule.kt
index 72ee1cd9..93bfd1a0 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivityModule.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkActivityModule.kt
@@ -1,5 +1,7 @@
package com.g00fy2.developerwidget.activities.apkinstall
+import com.g00fy2.developerwidget.activities.apkinstall.controllers.StorageDirsController
+import com.g00fy2.developerwidget.activities.apkinstall.controllers.StorageDirsControllerImpl
import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.ActivityModule
import com.g00fy2.developerwidget.di.annotations.ActivityScope
@@ -24,4 +26,8 @@ abstract class ApkActivityModule {
@Binds
@ActivityScope
abstract fun provideApkFileBuilder(apkFileBuilder: ApkFile.ApkFileBuilderImpl): ApkFile.ApkFileBuilder
+
+ @Binds
+ @ActivityScope
+ abstract fun provideStorageDirsController(storageDirsController: StorageDirsControllerImpl): StorageDirsController
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkAdapter.kt
index 8059ba29..4eb2efbb 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkAdapter.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkAdapter.kt
@@ -31,10 +31,11 @@ class ApkAdapter : BaseAdapter(ApksDiffUtilsCallback())
binding.fileDateTextview.text = item.lastModified
binding.appIconImageview.setImageDrawable(item.appIcon)
if (VERSION.SDK_INT >= VERSION_CODES.O) {
- binding.appIconImageview.setBackgroundResource(if (item.appIcon is InsetDrawable) R.drawable.bg_adaptive_launcher_icon else 0)
+ binding.appIconImageview
+ .setBackgroundResource(if (item.appIcon is InsetDrawable) R.drawable.bg_adaptive_launcher_icon else 0)
}
}
- setSelected(adapterPosition)
+ setSelected(bindingAdapterPosition)
}
fun setSelected(position: Int) {
@@ -49,7 +50,7 @@ class ApkAdapter : BaseAdapter(ApksDiffUtilsCallback())
return ApkViewHolder(ApkItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply {
addRipple()
itemView.setOnClickListener {
- adapterPosition.let {
+ bindingAdapterPosition.let {
if (selectedPositions.isNotEmpty()) {
if (selectedPositions.contains(it)) {
selectedPositions.remove(it)
@@ -64,7 +65,7 @@ class ApkAdapter : BaseAdapter(ApksDiffUtilsCallback())
}
}
itemView.setOnLongClickListener {
- adapterPosition.let {
+ bindingAdapterPosition.let {
if (selectedPositions.contains(it)) {
selectedPositions.remove(it)
} else {
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkContract.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkContract.kt
index 8706a99b..56fabfde 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkContract.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkContract.kt
@@ -6,11 +6,15 @@ interface ApkContract {
interface ApkView : BaseContract.BaseView {
- fun toggleResultView(apkFiles: List, missingPermissions: Boolean)
+ fun toggleResultView(apkFiles: List, missingPermissions: Boolean, searchDepth: Int = 0)
+
+ fun showPermissionWarning(apkFile: ApkFile)
}
interface ApkPresenter : BaseContract.BasePresenter {
+ fun installOrShowPermissionWarning(apkFile: ApkFile?)
+
fun installApk(apkFile: ApkFile?)
fun deleteApkFiles(apkFiles: List?)
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkFile.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkFile.kt
index 17d41413..8f5436bf 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkFile.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkFile.kt
@@ -1,7 +1,8 @@
package com.g00fy2.developerwidget.activities.apkinstall
-import android.content.Context
import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.InsetDrawable
@@ -11,6 +12,7 @@ import android.os.Build.VERSION_CODES
import android.text.format.DateFormat
import androidx.core.content.FileProvider
import androidx.core.content.pm.PackageInfoCompat
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import timber.log.Timber
import java.io.File
@@ -45,6 +47,10 @@ class ApkFile private constructor() : Comparable {
private set
var fileUri: Uri? = null
private set
+ var dangerousPermissions: List> = emptyList()
+ private set
+ var targetSdkVersion: Int = 0
+ private set
override fun compareTo(other: ApkFile) = compareValues(other.lastModifiedTimestamp, lastModifiedTimestamp)
@@ -53,11 +59,11 @@ class ApkFile private constructor() : Comparable {
fun build(file: File): ApkFile
}
- class ApkFileBuilderImpl @Inject constructor(@Named(ACTIVITY) private val context: Context) : ApkFileBuilder {
+ class ApkFileBuilderImpl @Inject constructor(@Named(ACTIVITY) private val activity: BaseActivity) : ApkFileBuilder {
- private val dateFormat = DateFormat.getDateFormat(context)
- private val timeFormat = DateFormat.getTimeFormat(context)
- private val packageManager = context.packageManager
+ private val dateFormat = DateFormat.getDateFormat(activity)
+ private val timeFormat = DateFormat.getTimeFormat(activity)
+ private val packageManager = activity.packageManager
override fun build(file: File): ApkFile {
return ApkFile().apply {
@@ -67,12 +73,14 @@ class ApkFile private constructor() : Comparable {
size = getFormattedSize(file.length())
file.absolutePath.let { filePath ->
- packageManager.getPackageArchiveInfo(filePath, 0)?.let { packageInfo ->
+ packageManager.getPackageArchiveInfo(filePath, PackageManager.GET_PERMISSIONS)?.let { packageInfo ->
packageInfo.versionName?.let { versionName = it }
PackageInfoCompat.getLongVersionCode(packageInfo).let { versionCode = it.toString() }
+ dangerousPermissions = extractDangerousPermissions(packageInfo.requestedPermissions)
packageInfo.applicationInfo
}?.let { appInfo ->
valid = true
+ targetSdkVersion = appInfo.targetSdkVersion
appInfo.sourceDir = filePath
appInfo.publicSourceDir = filePath
packageManager.getApplicationLabel(appInfo).let { appName = it.toString() }
@@ -90,7 +98,7 @@ class ApkFile private constructor() : Comparable {
filePath = file.path
try {
fileUri = if (VERSION.SDK_INT >= VERSION_CODES.N) {
- FileProvider.getUriForFile(context, context.applicationContext.packageName + ".fileprovider", file)
+ FileProvider.getUriForFile(activity, activity.applicationContext.packageName + ".fileprovider", file)
} else {
Uri.fromFile(file)
}
@@ -100,6 +108,31 @@ class ApkFile private constructor() : Comparable {
}
}
+ private fun extractDangerousPermissions(requestedPermissions: Array?): List> {
+ return mutableListOf>().apply {
+ requestedPermissions?.distinct()?.forEach { permission ->
+ try {
+ packageManager.getPermissionInfo(permission, 0).let {
+ if (it.hasDangerousPermissions()) {
+ add(Pair(it.name.substringAfterLast("."), it.loadDescription(packageManager)?.toString()))
+ }
+ }
+ } catch (e: Exception) {
+ // unknown permission qualifier
+ }
+ }
+ }
+ }
+
+ private fun PermissionInfo.hasDangerousPermissions(): Boolean {
+ return if (VERSION.SDK_INT >= VERSION_CODES.P) {
+ protection == PermissionInfo.PROTECTION_DANGEROUS
+ } else {
+ @Suppress("DEPRECATION")
+ protectionLevel == PermissionInfo.PROTECTION_DANGEROUS
+ }
+ }
+
private fun getFormattedSize(bytes: Long): String {
return (round(bytes / 1048576.0 * 100.0) / 100.0).let { sizeMB ->
if (sizeMB < 1) {
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkPresenterImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkPresenterImpl.kt
index e06a7bc6..c7c89523 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkPresenterImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkPresenterImpl.kt
@@ -1,13 +1,16 @@
package com.g00fy2.developerwidget.activities.apkinstall
import android.Manifest
+import android.os.Build.VERSION
+import android.os.Build.VERSION_CODES
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.lifecycleScope
+import com.g00fy2.developerwidget.activities.apkinstall.controllers.StorageDirsController
import com.g00fy2.developerwidget.base.BasePresenterImpl
import com.g00fy2.developerwidget.controllers.IntentController
import com.g00fy2.developerwidget.controllers.PermissionController
-import com.g00fy2.developerwidget.controllers.StorageDirsController
+import com.g00fy2.developerwidget.controllers.PreferenceController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -18,55 +21,74 @@ class ApkPresenterImpl @Inject constructor() : BasePresenterImpl(), ApkContract.
@Inject
lateinit var view: ApkContract.ApkView
+
@Inject
lateinit var intentController: IntentController
+
@Inject
lateinit var permissionController: PermissionController
+
@Inject
lateinit var storageDirsController: StorageDirsController
+
@Inject
lateinit var apkFileBuilder: ApkFile.ApkFileBuilder
+ @Inject
+ lateinit var preferenceController: PreferenceController
+
@OnLifecycleEvent(Event.ON_CREATE)
- fun requestPermission() {
- permissionController.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ fun scanStoreageIfPermissionGranted() {
+ permissionController.requestPermissions(
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ onGranted = { scanStorageForApks() },
+ onDenied = { view.toggleResultView(emptyList(), true) })
}
- @OnLifecycleEvent(Event.ON_RESUME)
- fun scanStorageForApks() {
- if (permissionController.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- view.lifecycleScope.launch {
- withContext(Dispatchers.IO) {
- mutableSetOf().apply {
- for (dir in storageDirsController.getStorageDirectories()) {
- addAll(searchAPKs(dir))
- }
+ private fun scanStorageForApks() {
+ var depth: Int
+ view.lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ depth = preferenceController.get(PreferenceController.SEARCH_DEPTH, 2)
+ mutableSetOf().apply {
+ for (dir in storageDirsController.getStorageDirectories()) {
+ addAll(searchAPKs(dir, depth))
}
- }.let {
- view.toggleResultView(it.sorted(), false)
- }
+ }.sorted()
+ }.let {
+ view.toggleResultView(it, false, depth)
}
- } else {
- view.toggleResultView(emptyList(), true)
}
}
- private fun searchAPKs(dir: File): Collection {
+ private fun searchAPKs(dir: File, depth: Int): Collection {
return dir.walk()
- .filter { !it.isDirectory }
+ .maxDepth(depth)
.filter { it.extension.equals("apk", true) }
+ .filterNot { it.isDirectory }
.map { apkFileBuilder.build(it) }
.filter { it.valid }
.toList()
}
+ override fun installOrShowPermissionWarning(apkFile: ApkFile?) {
+ apkFile?.let {
+ if (VERSION.SDK_INT >= VERSION_CODES.M && it.targetSdkVersion < VERSION_CODES.M
+ && it.dangerousPermissions.isNotEmpty()
+ ) {
+ view.showPermissionWarning(it)
+ } else {
+ installApk(it)
+ }
+ }
+ }
+
override fun installApk(apkFile: ApkFile?) {
apkFile?.let { intentController.installApk(it) }
}
override fun deleteApkFiles(apkFiles: List?) {
- if (permissionController.hasPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE))
- ) {
+ if (permissionController.hasPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
view.lifecycleScope.launch {
withContext(Dispatchers.IO) {
apkFiles?.let { files ->
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsController.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsController.kt
similarity index 60%
rename from app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsController.kt
rename to app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsController.kt
index c8082414..aa3b1929 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsController.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsController.kt
@@ -1,4 +1,4 @@
-package com.g00fy2.developerwidget.controllers
+package com.g00fy2.developerwidget.activities.apkinstall.controllers
import java.io.File
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsControllerImpl.kt
similarity index 93%
rename from app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsControllerImpl.kt
rename to app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsControllerImpl.kt
index ad0571dd..1c61d029 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StorageDirsControllerImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/controllers/StorageDirsControllerImpl.kt
@@ -1,10 +1,10 @@
-package com.g00fy2.developerwidget.controllers
+package com.g00fy2.developerwidget.activities.apkinstall.controllers
-import android.content.Context
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Environment
import androidx.annotation.RequiresApi
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import timber.log.Timber
import java.io.File
@@ -19,7 +19,7 @@ class StorageDirsControllerImpl @Inject constructor() : StorageDirsController {
@Inject
@Named(ACTIVITY)
- lateinit var context: Context
+ lateinit var activity: BaseActivity
/**
* Return all storage directories.
@@ -79,7 +79,7 @@ class StorageDirsControllerImpl @Inject constructor() : StorageDirsController {
@RequiresApi(VERSION_CODES.KITKAT)
private fun getExtSdCardPaths(): Collection {
val dirs = mutableListOf()
- for (file in context.getExternalFilesDirs("external")) {
+ for (file in activity.getExternalFilesDirs("external")) {
file?.let {
val index = it.absolutePath.lastIndexOf("/Android/data")
if (index < 0) {
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkDeleteDialog.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkDeleteDialog.kt
similarity index 83%
rename from app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkDeleteDialog.kt
rename to app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkDeleteDialog.kt
index 641ec618..eab7bc6f 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/ApkDeleteDialog.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkDeleteDialog.kt
@@ -1,4 +1,4 @@
-package com.g00fy2.developerwidget.activities.apkinstall
+package com.g00fy2.developerwidget.activities.apkinstall.dialogs
import android.content.Context
import androidx.appcompat.app.AppCompatDialog
@@ -7,8 +7,8 @@ import com.g00fy2.developerwidget.databinding.ApkDeleteDialogBinding
class ApkDeleteDialog(context: Context) {
- private var binding: ApkDeleteDialogBinding
- private val dialog = AppCompatDialog(context, R.style.DialogTheme).apply {
+ private val binding: ApkDeleteDialogBinding
+ private val dialog = AppCompatDialog(context, R.style.DialogNestedTheme).apply {
setCancelable(true)
binding = ApkDeleteDialogBinding.inflate(layoutInflater)
setContentView(binding.root)
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkWarningDialog.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkWarningDialog.kt
new file mode 100644
index 00000000..c9d8b8d8
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/ApkWarningDialog.kt
@@ -0,0 +1,44 @@
+package com.g00fy2.developerwidget.activities.apkinstall.dialogs
+
+import android.content.Context
+import androidx.appcompat.app.AppCompatDialog
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.g00fy2.developerwidget.R
+import com.g00fy2.developerwidget.databinding.ApkWarningDialogBinding
+
+class ApkWarningDialog(context: Context) {
+
+ private val binding: ApkWarningDialogBinding
+ private val adapter: PermissionsAdapter
+ private var installAction: () -> Unit = {}
+ private val dialog = AppCompatDialog(context, R.style.DialogNestedTheme).apply {
+ setCancelable(true)
+ binding = ApkWarningDialogBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ binding.dialogCancelTextview.setOnClickListener { dismiss() }
+ binding.dialogInstallTextview.setOnClickListener {
+ dismiss()
+ installAction()
+ }
+
+ adapter = PermissionsAdapter()
+ binding.recyclerview.setHasFixedSize(true)
+ binding.recyclerview.layoutManager = LinearLayoutManager(context)
+ binding.recyclerview.adapter = adapter
+ }
+
+ fun permissionList(permissions: List>): ApkWarningDialog {
+ adapter.submitList(permissions)
+ return this
+ }
+
+ fun installCallback(action: () -> Unit): ApkWarningDialog {
+ installAction = action
+ return this
+ }
+
+ fun init(func: ApkWarningDialog.() -> Unit): AppCompatDialog {
+ func()
+ return dialog
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/PermissionsAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/PermissionsAdapter.kt
new file mode 100644
index 00000000..84b7d1f2
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/apkinstall/dialogs/PermissionsAdapter.kt
@@ -0,0 +1,23 @@
+package com.g00fy2.developerwidget.activities.apkinstall.dialogs
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.g00fy2.developerwidget.activities.apkinstall.dialogs.PermissionsAdapter.PermissionViewHolder
+import com.g00fy2.developerwidget.base.BaseAdapter
+import com.g00fy2.developerwidget.base.BaseViewHolder
+import com.g00fy2.developerwidget.databinding.PermissionItemBinding
+
+class PermissionsAdapter : BaseAdapter, PermissionViewHolder>(null) {
+
+ class PermissionViewHolder(val binding: PermissionItemBinding) : BaseViewHolder>(binding) {
+ override fun onBind(item: Pair) {
+ item.run {
+ binding.permissionTitle.text = item.first
+ binding.permissionDescription.text = item.second ?: ""
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ PermissionViewHolder(PermissionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppInfo.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppInfo.kt
index 9b5e6c76..320448c4 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppInfo.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppInfo.kt
@@ -1,6 +1,5 @@
package com.g00fy2.developerwidget.activities.appmanager
-import android.content.Context
import android.content.pm.PackageInfo
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.Drawable
@@ -8,6 +7,7 @@ import android.graphics.drawable.InsetDrawable
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.core.content.pm.PackageInfoCompat
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import javax.inject.Inject
import javax.inject.Named
@@ -34,8 +34,30 @@ class AppInfo private constructor() : Comparable {
fun build(packageInfo: PackageInfo): AppInfo
}
- class AppInfoBuilderImpl @Inject constructor(@Named(ACTIVITY) context: Context) : AppInfoBuilder {
- private val packageManager = context.packageManager
+ fun filterPackageName(filter: String): Boolean {
+ var result = false
+ val filterInputs = filter.split("*")
+ var tempValue = packageName
+ for (i in filterInputs) {
+ if (tempValue.contains(i, true)) {
+ tempValue = tempValue.substringAfter(i)
+ result = true
+ } else {
+ return false
+ }
+ }
+ return result
+ }
+
+ fun filterPackageName(filterEntries: Collection): Boolean {
+ for (i in filterEntries) {
+ if (filterPackageName(i)) return true
+ }
+ return false
+ }
+
+ class AppInfoBuilderImpl @Inject constructor(@Named(ACTIVITY) activity: BaseActivity) : AppInfoBuilder {
+ private val packageManager = activity.packageManager
override fun getInstalledPackages(): List {
return packageManager.getInstalledPackages(0)
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsActivity.kt
index 4bceadf7..198ea881 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsActivity.kt
@@ -21,7 +21,6 @@ import androidx.core.widget.doAfterTextChanged
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.viewbinding.ViewBinding
import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.base.BaseContract.BasePresenter
@@ -36,23 +35,18 @@ class AppsActivity : BaseActivity(true), AppsContract.AppsView {
@Inject
lateinit var presenter: AppsContract.AppsPresenter
- private lateinit var binding: ActivityAppsBinding
+ override val binding: ActivityAppsBinding by viewBinding(ActivityAppsBinding::inflate)
private lateinit var adapter: AppsAdapter
private var scrollToTopAfterCommit = false
private val clearDrawable by lazy { initClearDrawable() }
override fun providePresenter(): BasePresenter = presenter
- override fun setViewBinding(): ViewBinding {
- binding = ActivityAppsBinding.inflate(layoutInflater)
- return binding
- }
-
override fun initView() {
adapter = AppsAdapter()
adapter.setOnAppClicked { appInfo -> presenter.openAppSettingsActivity(appInfo) }
- adapter.setCommitCallback(Runnable {
+ adapter.setCommitCallback {
adapter.itemCount.let {
binding.noItemsTextview.visibility = if (it == 0) View.VISIBLE else View.INVISIBLE
binding.noItemsImageview.visibility = if (it == 0) View.VISIBLE else View.INVISIBLE
@@ -62,7 +56,7 @@ class AppsActivity : BaseActivity(true), AppsContract.AppsView {
scrollToTopAfterCommit = false
binding.recyclerview.scrollToPosition(0)
}
- })
+ }
binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.itemAnimator = null
binding.recyclerview.layoutManager = LinearLayoutManager(this)
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsAdapter.kt
index 12ca4a3f..e8dc8bf1 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsAdapter.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsAdapter.kt
@@ -11,14 +11,13 @@ import com.g00fy2.developerwidget.activities.appmanager.AppsAdapter.AppViewHolde
import com.g00fy2.developerwidget.base.BaseAdapter
import com.g00fy2.developerwidget.base.BaseViewHolder
import com.g00fy2.developerwidget.databinding.AppItemBinding
-import com.g00fy2.developerwidget.ktx.filterPackageName
class AppsAdapter : BaseAdapter(AppsDiffUtilsCallback()) {
private var onAppClicked: ((AppInfo?) -> Unit) = {}
private var itemsCopy = ArrayList()
- inner class AppViewHolder(val binding: AppItemBinding) : BaseViewHolder(binding) {
+ class AppViewHolder(val binding: AppItemBinding) : BaseViewHolder(binding) {
override fun onBind(item: AppInfo) {
item.run {
binding.appenameTextview.text = appName
@@ -27,7 +26,8 @@ class AppsAdapter : BaseAdapter(AppsDiffUtilsCallback())
String.format(itemView.context.getString(R.string.apk_version), versionName, versionCode)
binding.appIconImageview.setImageDrawable(appIcon)
if (VERSION.SDK_INT >= VERSION_CODES.O) {
- binding.appIconImageview.setBackgroundResource(if (appIcon is InsetDrawable) R.drawable.bg_adaptive_launcher_icon else 0)
+ binding.appIconImageview
+ .setBackgroundResource(if (appIcon is InsetDrawable) R.drawable.bg_adaptive_launcher_icon else 0)
}
}
}
@@ -37,7 +37,7 @@ class AppsAdapter : BaseAdapter(AppsDiffUtilsCallback())
return AppViewHolder(AppItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply {
addRipple()
itemView.setOnClickListener {
- onAppClicked(getSelectedPackageName(adapterPosition))
+ onAppClicked(getSelectedPackageName(bindingAdapterPosition))
}
}
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsPresenterImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsPresenterImpl.kt
index ceff7583..43c8f5b1 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsPresenterImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/appmanager/AppsPresenterImpl.kt
@@ -83,7 +83,10 @@ class AppsPresenterImpl @Inject constructor() : BasePresenterImpl(), AppsContrac
private fun getInstalledUserApps(): List {
return appInfoBuilder.getInstalledPackages()
- .filter { it.applicationInfo.flags.let { flags -> flags and ApplicationInfo.FLAG_SYSTEM == 0 || flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0 } }
+ .filter {
+ it.applicationInfo.flags
+ .let { flags -> flags and ApplicationInfo.FLAG_SYSTEM == 0 || flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0 }
+ }
.map { appInfoBuilder.build(it) }
.sorted()
.toList()
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/CreateShortcutActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/CreateShortcutActivity.kt
index 7aa08ea5..3ffb11a6 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/CreateShortcutActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/CreateShortcutActivity.kt
@@ -14,12 +14,13 @@ import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.appcompat.content.res.AppCompatResources
+import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toBitmap
+import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.viewbinding.ViewBinding
import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.activities.apkinstall.ApkActivity
import com.g00fy2.developerwidget.activities.appmanager.AppsActivity
@@ -34,17 +35,13 @@ class CreateShortcutActivity : BaseActivity(), CreateShortcutContract.CreateShor
@Inject
lateinit var presenter: CreateShortcutContract.CreateShortcutPresenter
- private lateinit var binding: ActivityCreateShortcutBinding
+
+ override val binding: ActivityCreateShortcutBinding by viewBinding(ActivityCreateShortcutBinding::inflate)
private lateinit var adapter: ShortcutAdapter
private lateinit var shortcutInfoList: List
override fun providePresenter(): BasePresenter = presenter
- override fun setViewBinding(): ViewBinding {
- binding = ActivityCreateShortcutBinding.inflate(layoutInflater)
- return binding
- }
-
override fun initView() {
setResult(Activity.RESULT_CANCELED)
@@ -52,7 +49,7 @@ class CreateShortcutActivity : BaseActivity(), CreateShortcutContract.CreateShor
binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(this)
binding.recyclerview.adapter = adapter
- getDrawable(R.drawable.divider_line)?.let {
+ ContextCompat.getDrawable(this, R.drawable.divider_line)?.let {
binding.recyclerview.addItemDecoration(
DividerItemDecoration(
this,
@@ -64,8 +61,11 @@ class CreateShortcutActivity : BaseActivity(), CreateShortcutContract.CreateShor
adapter.submitList(shortcutInfoList)
adapter.setOnShortcutSelected { shortcutPosition -> onItemClick(shortcutPosition) }
if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
- binding.recyclerview.doOnApplyWindowInsets { view, insets, padding, _ ->
- view.updatePadding(bottom = padding.bottom + insets.systemWindowInsetBottom)
+ binding.root.doOnApplyWindowInsets { view, insets, padding, _ ->
+ view.updatePadding(
+ bottom = padding.bottom + WindowInsetsCompat.toWindowInsetsCompat(insets)
+ .getInsets(WindowInsetsCompat.Type.systemBars()).bottom
+ )
}
}
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/ShortcutAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/ShortcutAdapter.kt
index c020832e..16d5c2dc 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/ShortcutAdapter.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/shortcut/ShortcutAdapter.kt
@@ -15,7 +15,7 @@ class ShortcutAdapter : BaseAdapter(ShortcutDi
private var onShortcutSelected: ((Int) -> Unit) = {}
- inner class ShortcutViewHolder(val binding: ShortcutItemBinding) : BaseViewHolder(binding) {
+ class ShortcutViewHolder(val binding: ShortcutItemBinding) : BaseViewHolder(binding) {
override fun onBind(item: ShortcutInfo) {
item.run {
binding.shortcutTitleTextview.text = item.longLabel ?: item.shortLabel ?: ""
@@ -26,7 +26,7 @@ class ShortcutAdapter : BaseAdapter(ShortcutDi
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShortcutViewHolder {
return ShortcutViewHolder(ShortcutItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply {
addRipple()
- itemView.setOnClickListener { onShortcutSelected(adapterPosition) }
+ itemView.setOnClickListener { onShortcutSelected(bindingAdapterPosition) }
}
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/DeviceDataAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/DeviceDataAdapter.kt
index e58e73e4..ff8cebe4 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/DeviceDataAdapter.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/DeviceDataAdapter.kt
@@ -12,17 +12,17 @@ import com.g00fy2.developerwidget.databinding.DeviceDataValueItemBinding
class DeviceDataAdapter :
BaseAdapter, BaseViewHolder>>(DeviceDataDiffUtilsCallback()) {
- inner class DeviceDataHeaderViewHolder(val binding: DeviceDataHeaderItemBinding) :
+ class DeviceDataHeaderViewHolder(val binding: DeviceDataHeaderItemBinding) :
BaseViewHolder>(binding) {
override fun onBind(item: Pair) {
item.run {
- binding.headerDividerView.visibility = if (adapterPosition == 0) View.INVISIBLE else View.VISIBLE
+ binding.headerDividerView.visibility = if (bindingAdapterPosition == 0) View.INVISIBLE else View.VISIBLE
binding.headerTitleTextview.text = itemView.context.getString(second.title)
}
}
}
- inner class DeviceDataValueViewHolder(val binding: DeviceDataValueItemBinding) :
+ class DeviceDataValueViewHolder(val binding: DeviceDataValueItemBinding) :
BaseViewHolder>(binding) {
override fun onBind(item: Pair) {
item.run {
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigActivity.kt
index f957436e..81b1732e 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigActivity.kt
@@ -26,9 +26,9 @@ import android.webkit.WebView
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.getSystemService
import androidx.core.content.res.ResourcesCompat
+import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.viewbinding.ViewBinding
import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.activities.about.AboutActivity
import com.g00fy2.developerwidget.base.BaseActivity
@@ -36,7 +36,6 @@ import com.g00fy2.developerwidget.base.BaseContract.BasePresenter
import com.g00fy2.developerwidget.data.DeviceDataItem
import com.g00fy2.developerwidget.databinding.ActivityWidgetConfigBinding
import com.g00fy2.developerwidget.ktx.doOnApplyWindowInsets
-import com.g00fy2.developerwidget.ktx.gesturalNavigationMode
import com.g00fy2.developerwidget.ktx.hideKeyboard
import com.g00fy2.developerwidget.ktx.showKeyboard
import com.g00fy2.developerwidget.ktx.updateMargin
@@ -48,7 +47,7 @@ class WidgetConfigActivity : BaseActivity(), WidgetConfigContract.WidgetConfigVi
@Inject
lateinit var presenter: WidgetConfigContract.WidgetConfigPresenter
- private lateinit var binding: ActivityWidgetConfigBinding
+ override val binding: ActivityWidgetConfigBinding by viewBinding(ActivityWidgetConfigBinding::inflate)
private lateinit var adapter: DeviceDataAdapter
private var updateExistingWidget = false
private var launchedFromAppLauncher = true
@@ -66,11 +65,6 @@ class WidgetConfigActivity : BaseActivity(), WidgetConfigContract.WidgetConfigVi
override fun providePresenter(): BasePresenter = presenter
- override fun setViewBinding(): ViewBinding {
- binding = ActivityWidgetConfigBinding.inflate(layoutInflater)
- return binding
- }
-
override fun initView() {
setResult(Activity.RESULT_CANCELED)
@@ -95,7 +89,7 @@ class WidgetConfigActivity : BaseActivity(), WidgetConfigContract.WidgetConfigVi
} else {
binding.shareFab.show()
}
- if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && !gesturalNavigationMode()) {
+ if (VERSION.SDK_INT >= VERSION_CODES.O_MR1 && !isGesturalNavMode()) {
clipToPadding = (scrollY >= scrollableRange)
}
}
@@ -137,10 +131,16 @@ class WidgetConfigActivity : BaseActivity(), WidgetConfigContract.WidgetConfigVi
binding.shareFab.setOnClickListener { presenter.shareDeviceData() }
if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
binding.widgetConfigRootScrollview.doOnApplyWindowInsets { view, insets, padding, _ ->
- view.updatePadding(bottom = padding.bottom + insets.systemWindowInsetBottom)
+ view.updatePadding(
+ bottom = padding.bottom + WindowInsetsCompat.toWindowInsetsCompat(insets)
+ .getInsets(WindowInsetsCompat.Type.systemBars()).bottom
+ )
}
binding.shareFab.doOnApplyWindowInsets { view, insets, _, margin ->
- view.updateMargin(bottom = margin.bottom + insets.systemWindowInsetBottom)
+ view.updateMargin(
+ bottom = margin.bottom + WindowInsetsCompat.toWindowInsetsCompat(insets)
+ .getInsets(WindowInsetsCompat.Type.systemBars()).bottom
+ )
}
}
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigPresenterImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigPresenterImpl.kt
index 4f5e4050..7cb05e46 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigPresenterImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigPresenterImpl.kt
@@ -102,8 +102,8 @@ class WidgetConfigPresenterImpl @Inject constructor() : BasePresenterImpl(),
override fun shareDeviceData() {
view.lifecycleScope.launch {
withContext(Dispatchers.IO) {
- getDeviceData()
- }.let { intentController.shareDeviceData(formatDeviceDataString(it)) }
+ formatDeviceDataString(getDeviceData())
+ }.let { intentController.shareDeviceData(it) }
}
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseActivity.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseActivity.kt
index d3543620..4440690d 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseActivity.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseActivity.kt
@@ -4,11 +4,15 @@ import android.content.res.Configuration
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Bundle
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
+import androidx.annotation.RequiresApi
+import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.viewbinding.ViewBinding
+import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.controllers.DayNightController
import com.g00fy2.developerwidget.ktx.doOnApplyWindowInsets
import dagger.android.support.DaggerAppCompatActivity
@@ -20,20 +24,22 @@ abstract class BaseActivity(private val isDialogActivity: Boolean = false) : Dag
@Inject
lateinit var dayNightController: DayNightController
+ protected abstract val binding: ViewBinding
+
override fun onCreate(savedInstanceState: Bundle?) {
Timber.d("Lifecycle: %s1 onCreate %s2", localClassName, hashCode())
if (isDialogActivity) {
requestWindowFeature(Window.FEATURE_NO_TITLE)
super.onCreate(savedInstanceState)
- setContentView(setViewBinding().root)
+ setContentView(binding.root)
val width = (resources.displayMetrics.widthPixels * 0.95).toInt()
val height = (resources.displayMetrics.heightPixels * 0.80).toInt()
window.setLayout(width, height)
} else {
super.onCreate(savedInstanceState)
- setContentView(setViewBinding().root)
+ setContentView(binding.root)
}
dayNightController.loadCustomDefaultMode()
@@ -49,12 +55,17 @@ abstract class BaseActivity(private val isDialogActivity: Boolean = false) : Dag
lifecycle.removeObserver(providePresenter())
}
- // TODO check if there will be a fix for https://issuetracker.google.com/issues/139738913 in AppCompatActivity or next Android release
- override fun onBackPressed() {
- if (VERSION.SDK_INT == VERSION_CODES.Q && isTaskRoot && supportFragmentManager.backStackEntryCount == 0) {
- finishAfterTransition()
- } else {
- super.onBackPressed()
+ inline fun DaggerAppCompatActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) =
+ lazy(LazyThreadSafetyMode.NONE) { bindingInflater.invoke(layoutInflater) }
+
+ @RequiresApi(VERSION_CODES.Q)
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ if (isGesturalNavMode()) {
+ getColor(R.color.transparent).let {
+ window.navigationBarColor = it
+ window.navigationBarDividerColor = it
+ }
}
}
@@ -73,25 +84,37 @@ abstract class BaseActivity(private val isDialogActivity: Boolean = false) : Dag
}
}
+ protected fun isGesturalNavMode(): Boolean {
+ return resources.getIdentifier("config_navBarInteractionMode", "integer", "android")
+ .takeIf { it != 0 }?.let { resources.getInteger(it) == 2 } ?: false
+ }
+
private fun initGestureNavigation() {
if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
+ // TODO check how to use API 30 features
+ @Suppress("DEPRECATION")
window.decorView.let {
it.systemUiVisibility.let { flags ->
it.systemUiVisibility =
flags or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
}
+
findViewById(Window.ID_ANDROID_CONTENT)?.let {
it.doOnApplyWindowInsets { view, insets, padding, _ ->
- view.updatePadding(top = padding.top + insets.systemWindowInsetTop)
+ view.updatePadding(
+ top = padding.top + WindowInsetsCompat.toWindowInsetsCompat(insets)
+ .getInsets(WindowInsetsCompat.Type.systemBars()).top
+ )
}
}
}
}
+ @Suppress("DEPRECATION")
private fun initCompatNavigationBar() {
// api 27+ allow applying flag via xml (windowLightNavigationBar)
- if (VERSION.SDK_INT == VERSION_CODES.O && isInNightMode()) {
+ if (VERSION.SDK_INT == VERSION_CODES.O && !isNightMode()) {
window.decorView.let {
it.systemUiVisibility.let { flags ->
it.systemUiVisibility = flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
@@ -100,13 +123,10 @@ abstract class BaseActivity(private val isDialogActivity: Boolean = false) : Dag
}
}
- // TODO move back to controller if https://issuetracker.google.com/issues/134379747 should get fixed
- private fun isInNightMode() =
- resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_NO
+ private fun isNightMode() =
+ resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
abstract fun providePresenter(): BaseContract.BasePresenter
- abstract fun setViewBinding(): ViewBinding
-
abstract fun initView()
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseAdapter.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseAdapter.kt
index a92a2dc7..eb23df63 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseAdapter.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/base/BaseAdapter.kt
@@ -3,8 +3,8 @@ package com.g00fy2.developerwidget.base
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
-abstract class BaseAdapter> constructor(diffCallback: DiffUtil.ItemCallback) :
- ListAdapter(diffCallback) {
+abstract class BaseAdapter> constructor(diffCallback: DiffUtil.ItemCallback?) :
+ ListAdapter(diffCallback ?: EmptyDiffUtil()) {
private var commitCallback: Runnable? = null
@@ -23,4 +23,9 @@ abstract class BaseAdapter> constructor(diffCallback:
fun setCommitCallback(commitCallback: Runnable) {
this.commitCallback = commitCallback
}
+
+ class EmptyDiffUtil : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: T, newItem: T) = false
+ override fun areContentsTheSame(oldItem: T, newItem: T) = false
+ }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt
index 6d00d830..c451290f 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt
@@ -1,6 +1,5 @@
package com.g00fy2.developerwidget.controllers
-import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build.VERSION
@@ -12,6 +11,7 @@ import com.g00fy2.developerwidget.BuildConfig
import com.g00fy2.developerwidget.R
import com.g00fy2.developerwidget.activities.about.DEVELOPER_EMAIL
import com.g00fy2.developerwidget.activities.apkinstall.ApkFile
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import timber.log.Timber
import javax.inject.Inject
@@ -21,7 +21,7 @@ class IntentControllerImpl @Inject constructor() : IntentController {
@Inject
@Named(ACTIVITY)
- lateinit var context: Context
+ lateinit var activity: BaseActivity
@Inject
lateinit var toastController: ToastController
@@ -72,12 +72,12 @@ class IntentControllerImpl @Inject constructor() : IntentController {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, data)
type = "text/plain"
- }, context.getString(R.string.share_device_data)))
+ }, activity.getString(R.string.share_device_data)))
}
private fun startActivity(intent: Intent) {
- if (intent.resolveActivity(context.packageManager) != null) {
- context.startActivity(intent)
+ if (intent.resolveActivity(activity.packageManager) != null) {
+ activity.startActivity(intent)
} else {
Timber.w("Intent could not get resolved.")
}
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionController.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionController.kt
index 5c31dbc9..76517d19 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionController.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionController.kt
@@ -2,11 +2,7 @@ package com.g00fy2.developerwidget.controllers
interface PermissionController {
- fun hasPermission(permission: String): Boolean
+ fun hasPermissions(vararg permissions: String): Boolean
- fun hasPermissions(permissions: Array): Boolean
-
- fun requestPermission(permission: String)
-
- fun requestPermissions(permissions: Array)
+ fun requestPermissions(vararg permissions: String, onGranted: (() -> Unit) = {}, onDenied: () -> Unit = {})
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionControllerImpl.kt
index a9340d52..8bbc08f5 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionControllerImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PermissionControllerImpl.kt
@@ -1,12 +1,9 @@
package com.g00fy2.developerwidget.controllers
-import android.app.Activity
-import android.content.Context
import android.content.pm.PackageManager
-import android.os.Build.VERSION
-import android.os.Build.VERSION_CODES
-import androidx.annotation.RequiresApi
+import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
import androidx.core.content.ContextCompat
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import javax.inject.Inject
import javax.inject.Named
@@ -15,34 +12,15 @@ class PermissionControllerImpl @Inject constructor() : PermissionController {
@Inject
@Named(ACTIVITY)
- lateinit var context: Context
+ lateinit var activity: BaseActivity
- override fun hasPermission(permission: String): Boolean {
- return if (VERSION.SDK_INT >= VERSION_CODES.M) {
- ContextCompat.checkSelfPermission(
- context,
- permission
- ) == PackageManager.PERMISSION_GRANTED
- } else {
- true
- }
+ override fun hasPermissions(vararg permissions: String): Boolean {
+ return permissions.all { ContextCompat.checkSelfPermission(activity, it) == PackageManager.PERMISSION_GRANTED }
}
- override fun hasPermissions(permissions: Array): Boolean {
- var granted = true
- for (permission in permissions) {
- granted = granted && hasPermission(permission)
- }
- return granted
- }
-
- @RequiresApi(VERSION_CODES.M)
- override fun requestPermission(permission: String) {
- requestPermissions(arrayOf(permission))
- }
-
- @RequiresApi(VERSION_CODES.M)
- override fun requestPermissions(permissions: Array) {
- if (!hasPermissions(permissions)) (context as Activity).requestPermissions(permissions, 1)
+ override fun requestPermissions(vararg permissions: String, onGranted: (() -> Unit), onDenied: () -> Unit) {
+ activity.registerForActivityResult(RequestMultiplePermissions()) { result ->
+ if (result.all { it.value }) onGranted() else onDenied()
+ }.launch(permissions)
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceController.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceController.kt
new file mode 100644
index 00000000..7f6c1b88
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceController.kt
@@ -0,0 +1,25 @@
+package com.g00fy2.developerwidget.controllers
+
+interface PreferenceController {
+
+
+ companion object {
+ const val SEARCH_DEPTH = "search_depth"
+ }
+
+ suspend fun get(key: String, default: String): String
+
+ suspend fun set(key: String, data: String)
+
+ suspend fun get(key: String, default: Long): Long
+
+ suspend fun set(key: String, data: Long)
+
+ suspend fun get(key: String, default: Int): Int
+
+ suspend fun set(key: String, data: Int)
+
+ suspend fun get(key: String, default: Boolean): Boolean
+
+ suspend fun set(key: String, data: Boolean)
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceControllerImpl.kt
new file mode 100644
index 00000000..f5d3e494
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/PreferenceControllerImpl.kt
@@ -0,0 +1,68 @@
+package com.g00fy2.developerwidget.controllers
+
+import android.content.Context
+import com.g00fy2.developerwidget.base.BaseActivity
+import com.g00fy2.developerwidget.di.annotations.ACTIVITY
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import javax.inject.Inject
+import javax.inject.Named
+
+class PreferenceControllerImpl @Inject constructor() : PreferenceController {
+
+ @Inject
+ @Named(ACTIVITY)
+ lateinit var activity: BaseActivity
+
+ private val sharedPreference by lazy {
+ activity.getSharedPreferences(activity.packageName + ".preferences", Context.MODE_PRIVATE)
+ }
+
+ override suspend fun get(key: String, default: String): String {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.getString(key, default) ?: default
+ }
+ }
+
+ override suspend fun get(key: String, default: Long): Long {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.getLong(key, default)
+ }
+ }
+
+ override suspend fun get(key: String, default: Int): Int {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.getInt(key, default)
+ }
+ }
+
+ override suspend fun get(key: String, default: Boolean): Boolean {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.getBoolean(key, default)
+ }
+ }
+
+ override suspend fun set(key: String, data: String) {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.edit().putString(key, data).apply()
+ }
+ }
+
+ override suspend fun set(key: String, data: Long) {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.edit().putLong(key, data).apply()
+ }
+ }
+
+ override suspend fun set(key: String, data: Int) {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.edit().putInt(key, data).apply()
+ }
+ }
+
+ override suspend fun set(key: String, data: Boolean) {
+ return withContext(Dispatchers.IO) {
+ sharedPreference.edit().putBoolean(key, data).apply()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StringControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StringControllerImpl.kt
index 52ca07ad..88df5a3a 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StringControllerImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/StringControllerImpl.kt
@@ -1,6 +1,6 @@
package com.g00fy2.developerwidget.controllers
-import android.content.Context
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import javax.inject.Inject
import javax.inject.Named
@@ -9,7 +9,7 @@ class StringControllerImpl @Inject constructor() : StringController {
@Inject
@Named(ACTIVITY)
- lateinit var context: Context
+ lateinit var activity: BaseActivity
- override fun getString(resId: Int): String = context.getString(resId)
+ override fun getString(resId: Int): String = activity.getString(resId)
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/WidgetPreferenceControllerImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/WidgetPreferenceControllerImpl.kt
index b7b247a5..f4820da0 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/WidgetPreferenceControllerImpl.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/WidgetPreferenceControllerImpl.kt
@@ -2,6 +2,7 @@ package com.g00fy2.developerwidget.controllers
import android.content.Context
import androidx.core.content.edit
+import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import com.g00fy2.developerwidget.di.annotations.WIDGET_ID
import javax.inject.Inject
@@ -11,13 +12,13 @@ class WidgetPreferenceControllerImpl @Inject constructor() : WidgetPreferenceCon
@Inject
@Named(ACTIVITY)
- lateinit var context: Context
+ lateinit var activity: BaseActivity
@Inject
@Named(WIDGET_ID)
lateinit var widgetId: String
private val sharedPreference by lazy {
- context.getSharedPreferences(context.packageName + ".preferences_" + widgetId, Context.MODE_PRIVATE)
+ activity.getSharedPreferences(activity.packageName + ".preferences_" + widgetId, Context.MODE_PRIVATE)
}
override fun getAppFilters(): MutableList {
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/cpu/CPUDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/cpu/CPUDataProvider.kt
index 01319fbd..95b4e37a 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/cpu/CPUDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/cpu/CPUDataProvider.kt
@@ -9,60 +9,57 @@ import java.io.RandomAccessFile
import java.util.regex.Pattern
import kotlin.math.max
-class CPUDataProvider {
+object CPUDataProvider {
- companion object {
+ private const val CPU_SYS_FOLDER = "/sys/devices/system/cpu/"
+ private val CPU_PATTERN = Pattern.compile("cpu[0-9]+")
- private const val CPU_SYS_FOLDER = "/sys/devices/system/cpu/"
- private val CPU_PATTERN = Pattern.compile("cpu[0-9]+")
-
- fun getPrimaryABI(): String {
- return if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- Build.SUPPORTED_ABIS.firstOrNull() ?: ""
- } else {
- @Suppress("DEPRECATION")
- Build.CPU_ABI
- }
- }
-
- fun getCPUCoreNum(): Int {
- return max(
- File(CPU_SYS_FOLDER)
- .walk()
- .maxDepth(1)
- .count { CPU_PATTERN.matcher(it.name).matches() },
- Runtime.getRuntime().availableProcessors()
- )
+ fun getPrimaryABI(): String {
+ return if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ Build.SUPPORTED_ABIS.firstOrNull() ?: ""
+ } else {
+ @Suppress("DEPRECATION")
+ Build.CPU_ABI
}
+ }
- fun getGroupedCPUCoreFrequencies(): String {
- val frequencies = mutableListOf>()
- val cores = getCPUCoreNum()
- for (i in 0 until cores) {
- getCPUFrequenciesPerCore(i)?.let { frequencies.add(it) }
- }
+ fun getCPUCoreNum(): Int {
+ return max(
+ File(CPU_SYS_FOLDER)
+ .walk()
+ .maxDepth(1)
+ .count { CPU_PATTERN.matcher(it.name).matches() },
+ Runtime.getRuntime().availableProcessors()
+ )
+ }
- return frequencies.sortedByDescending { it.second }
- .groupingBy { it.second.toString() + "MHz - " + it.first + "MHz" }
- .eachCount()
- .map { it.value.toString() + " x " + it.key }
- .plus(if (frequencies.size < cores) (cores - frequencies.size).toString() + " x offline" else "")
- .filter { it.isNotEmpty() }
- .joinToString(separator = "\n")
+ fun getGroupedCPUCoreFrequencies(): String {
+ val frequencies = mutableListOf>()
+ val cores = getCPUCoreNum()
+ for (i in 0 until cores) {
+ getCPUFrequenciesPerCore(i)?.let { frequencies.add(it) }
}
- private fun getCPUFrequenciesPerCore(core: Int): Pair? {
- return try {
- val max = RandomAccessFile(CPU_SYS_FOLDER + "cpu$core/cpufreq/cpuinfo_max_freq", "r").use { reader ->
- (reader.readLine().toLong() / 1000).toInt()
- }
- val min = RandomAccessFile(CPU_SYS_FOLDER + "cpu$core/cpufreq/cpuinfo_min_freq", "r").use { reader ->
- (reader.readLine().toLong() / 1000).toInt()
- }
- Pair(min, max)
- } catch (e: FileNotFoundException) {
- null
+ return frequencies.sortedByDescending { it.second }
+ .groupingBy { it.second.toString() + "MHz - " + it.first + "MHz" }
+ .eachCount()
+ .map { it.value.toString() + " x " + it.key }
+ .plus(if (frequencies.size < cores) (cores - frequencies.size).toString() + " x offline" else "")
+ .filter { it.isNotEmpty() }
+ .joinToString(separator = "\n")
+ }
+
+ private fun getCPUFrequenciesPerCore(core: Int): Pair? {
+ return try {
+ val max = RandomAccessFile(CPU_SYS_FOLDER + "cpu$core/cpufreq/cpuinfo_max_freq", "r").use { reader ->
+ (reader.readLine().toLong() / 1000).toInt()
+ }
+ val min = RandomAccessFile(CPU_SYS_FOLDER + "cpu$core/cpufreq/cpuinfo_min_freq", "r").use { reader ->
+ (reader.readLine().toLong() / 1000).toInt()
}
+ Pair(min, max)
+ } catch (e: FileNotFoundException) {
+ null
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/devicebuild/BuildDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/devicebuild/BuildDataProvider.kt
index 379bc0d6..447927b2 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/devicebuild/BuildDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/devicebuild/BuildDataProvider.kt
@@ -3,33 +3,30 @@ package com.g00fy2.developerwidget.data.device.devicebuild
import android.annotation.SuppressLint
import android.os.Build
-class BuildDataProvider {
-
- companion object {
-
- @SuppressLint("DefaultLocale")
- fun getCombinedDeviceName(): String {
- return if (Build.MODEL.contains(Build.MANUFACTURER, true)) {
- Build.MODEL.capitalize()
- } else {
- Build.MANUFACTURER.capitalize() + " " + Build.MODEL.capitalize()
- }
+object BuildDataProvider {
+
+ @SuppressLint("DefaultLocale")
+ fun getCombinedDeviceName(): String {
+ return if (Build.MODEL.contains(Build.MANUFACTURER, true)) {
+ Build.MODEL.capitalize()
+ } else {
+ Build.MANUFACTURER.capitalize() + " " + Build.MODEL.capitalize()
}
+ }
- fun getBoard(): String = Build.BOARD
+ fun getBoard(): String = Build.BOARD
- fun getDevice(): String = Build.DEVICE
+ fun getDevice(): String = Build.DEVICE
- fun getHardware(): String = Build.HARDWARE
+ fun getHardware(): String = Build.HARDWARE
- fun getProduct(): String = Build.PRODUCT
+ fun getProduct(): String = Build.PRODUCT
- fun getModel(): String = Build.MODEL
+ fun getModel(): String = Build.MODEL
- fun getManufacture(): String = Build.MANUFACTURER
+ fun getManufacture(): String = Build.MANUFACTURER
- fun getBootloader(): String = Build.BOOTLOADER
+ fun getBootloader(): String = Build.BOOTLOADER
- fun getID(): String = Build.ID
- }
+ fun getID(): String = Build.ID
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/display/DisplayDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/display/DisplayDataProvider.kt
index 5223e3f0..24f79f5b 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/display/DisplayDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/display/DisplayDataProvider.kt
@@ -9,69 +9,70 @@ import androidx.core.content.getSystemService
import java.text.NumberFormat
import kotlin.math.roundToInt
-class DisplayDataProvider {
+object DisplayDataProvider {
- companion object {
-
- @SuppressLint("NewApi")
- fun getResolution(context: Context): Point? {
- context.getSystemService()?.defaultDisplay?.let { windowManager ->
- Point().let { point ->
- try {
- windowManager.getRealSize(point)
- } catch (e: NoSuchMethodError) {
- windowManager.getSize(point)
- }
- return point
+ @SuppressLint("NewApi")
+ fun getResolution(context: Context): Point? {
+ getDisplay(context)?.let { windowManager ->
+ Point().let { point ->
+ try {
+ windowManager.getRealSize(point)
+ } catch (e: NoSuchMethodError) {
+ @Suppress("DEPRECATION")
+ windowManager.getSize(point)
}
+ return point
}
- return null
}
+ return null
+ }
- @SuppressLint("NewApi")
- fun geDisplayDpi(context: Context): String {
- context.getSystemService()?.defaultDisplay?.let { windowManager ->
- DisplayMetrics().let { displayMetrics ->
- try {
- windowManager.getRealMetrics(displayMetrics)
- } catch (e: NoSuchMethodError) {
- windowManager.getMetrics(displayMetrics)
- }
- return displayMetrics.xdpi.roundToInt().toString() + " / " + displayMetrics.ydpi.roundToInt() + " dpi"
+ @SuppressLint("NewApi")
+ fun geDisplayDpi(context: Context): String {
+ getDisplay(context)?.let { windowManager ->
+ DisplayMetrics().let { displayMetrics ->
+ try {
+ windowManager.getRealMetrics(displayMetrics)
+ } catch (e: NoSuchMethodError) {
+ @Suppress("DEPRECATION")
+ windowManager.getMetrics(displayMetrics)
}
+ return displayMetrics.xdpi.roundToInt().toString() + " / " + displayMetrics.ydpi.roundToInt() + " dpi"
}
- return ""
}
+ return ""
+ }
+
+ fun getDisplayRatio(resolution: Point): String {
+ if (resolution.x > resolution.y) {
+ val temp = resolution.x
+ resolution.x = resolution.y
+ resolution.y = temp
+ }
+ val gcd = gcd(resolution.x, resolution.y)
- fun getDisplayRatio(resolution: Point): String {
- if (resolution.x > resolution.y) {
- val temp = resolution.x
- resolution.x = resolution.y
- resolution.y = temp
- }
- val gcd = gcd(resolution.x, resolution.y)
+ val result = if (resolution.y / gcd == 8) {
+ (resolution.y / gcd * 2).toString() + ":" + (resolution.x / gcd * 2)
+ } else {
+ (resolution.y / gcd).toString() + ":" + (resolution.x / gcd)
+ }
- val result = if (resolution.y / gcd == 8) {
- (resolution.y / gcd * 2).toString() + ":" + (resolution.x / gcd * 2)
+ val altResult =
+ if ((resolution.x / gcd) > 9 && ((resolution.y / gcd / 2.0f) % 1.0f) == 0.5f && ((resolution.x / gcd / 2.0f) % 1.0f) == 0.0f) {
+ NumberFormat.getInstance().let {
+ it.format((resolution.y / gcd / 2.0f)).toString() + ":" + it.format((resolution.x / gcd / 2.0f))
+ }
} else {
- (resolution.y / gcd).toString() + ":" + (resolution.x / gcd)
+ ""
}
- val altResult =
- if ((resolution.x / gcd) > 9 && ((resolution.y / gcd / 2.0f) % 1.0f) == 0.5f && ((resolution.x / gcd / 2.0f) % 1.0f) == 0.0f) {
- NumberFormat.getInstance().let {
- it.format((resolution.y / gcd / 2.0f)).toString() + ":" + it.format((resolution.x / gcd / 2.0f))
- }
- } else {
- ""
- }
+ return result + if (altResult.isBlank()) "" else " ($altResult)"
+ }
- return result + if (altResult.isBlank()) "" else " ($altResult)"
- }
+ private fun getDisplay(context: Context) = context.getSystemService()?.defaultDisplay
- private fun gcd(p: Int, q: Int): Int {
- return if (q == 0) p
- else gcd(q, p % q)
- }
+ private fun gcd(p: Int, q: Int): Int {
+ return if (q == 0) p
+ else gcd(q, p % q)
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/hardwarefeature/HardwareFeatureProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/hardwarefeature/HardwareFeatureProvider.kt
index 55f9dd0d..e0be2229 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/hardwarefeature/HardwareFeatureProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/hardwarefeature/HardwareFeatureProvider.kt
@@ -9,25 +9,22 @@ import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.core.content.getSystemService
-class HardwareFeatureProvider {
+object HardwareFeatureProvider {
- companion object {
+ fun hasNFC(context: Context): Boolean =
+ context.getSystemService()?.defaultAdapter?.let { true } ?: false
- fun hasNFC(context: Context): Boolean =
- context.getSystemService()?.defaultAdapter?.let { true } ?: false
-
- fun hasGPS(context: Context): Boolean {
- return context.getSystemService()?.allProviders?.contains(
- LocationManager.GPS_PROVIDER
- ) ?: false
- }
+ fun hasGPS(context: Context): Boolean {
+ return context.getSystemService()?.allProviders?.contains(
+ LocationManager.GPS_PROVIDER
+ ) ?: false
+ }
- fun hasBluetooth(context: Context): Boolean {
- return if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
- context.getSystemService()?.adapter?.let { true } ?: false
- } else {
- BluetoothAdapter.getDefaultAdapter()?.let { true } ?: false
- }
+ fun hasBluetooth(context: Context): Boolean {
+ return if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
+ context.getSystemService()?.adapter?.let { true } ?: false
+ } else {
+ BluetoothAdapter.getDefaultAdapter()?.let { true } ?: false
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/ram/RamDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/ram/RamDataProvider.kt
index c3879bae..ae32a091 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/ram/RamDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/ram/RamDataProvider.kt
@@ -10,43 +10,40 @@ import java.io.RandomAccessFile
import java.util.regex.Pattern
import kotlin.math.roundToLong
-class RamDataProvider {
+object RamDataProvider {
- companion object {
-
- fun getTotalRam(context: Context): String {
- var ramSize = 0L
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
- context.getSystemService()?.let {
- ActivityManager.MemoryInfo().let { info ->
- it.getMemoryInfo(info)
- ramSize = info.totalMem
- }
+ fun getTotalRam(context: Context): String {
+ var ramSize = 0L
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+ context.getSystemService()?.let {
+ ActivityManager.MemoryInfo().let { info ->
+ it.getMemoryInfo(info)
+ ramSize = info.totalMem
}
- } else {
- try {
- RandomAccessFile("/proc/meminfo", "r").use {
- val matcher = Pattern.compile("(\\d+)").matcher(it.readLine())
- var memTotal: String? = null
- while (matcher.find()) memTotal = matcher.group(1)
- memTotal?.let { stringValue ->
- ramSize = stringValue.toLong()
- return@use
- }
+ }
+ } else {
+ try {
+ RandomAccessFile("/proc/meminfo", "r").use {
+ val matcher = Pattern.compile("(\\d+)").matcher(it.readLine())
+ var memTotal: String? = null
+ while (matcher.find()) memTotal = matcher.group(1)
+ memTotal?.let { stringValue ->
+ ramSize = stringValue.toLong()
+ return@use
}
- } catch (e: IOException) {
- // ignore and keep ramSize 0
}
+ } catch (e: IOException) {
+ // ignore and keep ramSize 0
}
- return if (ramSize > 0) (2 * ((ramSize / (1024.0 * 1024.0) / 2).roundToLong())).toString() + " MB" else ""
}
+ return if (ramSize > 0) (2 * ((ramSize / (1024.0 * 1024.0) / 2).roundToLong())).toString() + " MB" else ""
+ }
- fun hasLowRamFlag(context: Context): String {
- return if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- context.getSystemService()?.isLowRamDevice?.toString() ?: ""
- } else {
- ""
- }
+ fun hasLowRamFlag(context: Context): String {
+ return if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ context.getSystemService()?.isLowRamDevice?.toString() ?: ""
+ } else {
+ ""
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/system/SystemDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/system/SystemDataProvider.kt
index 7ee9e9c2..e4b3861c 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/system/SystemDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/system/SystemDataProvider.kt
@@ -5,49 +5,46 @@ import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import com.g00fy2.versioncompare.Version
-class SystemDataProvider {
+object SystemDataProvider {
- companion object {
+ fun getVersionAndSDK(): Pair = Pair(getAndroidVersion(), getSDKLevel())
- fun getVersionAndSDK(): Pair = Pair(getAndroidVersion(), getSDKLevel())
+ fun getAndroidVersion(): String = VERSION.RELEASE
- fun getAndroidVersion(): String = VERSION.RELEASE
+ fun getCodename(): String = VERSION.CODENAME
- fun getCodename(): String = VERSION.CODENAME
-
- @SuppressLint("DefaultLocale")
- fun getSDKLevel(): String {
- getCodename().let {
- return if (it.isBlank() || it.equals("REL", true)) {
- VERSION.SDK_INT.toString()
- } else {
- it.toUpperCase()
- }
- }
- }
-
- fun getPreviewSDK(): String {
- return if (VERSION.SDK_INT >= VERSION_CODES.M) {
- VERSION.PREVIEW_SDK_INT.toString()
+ @SuppressLint("DefaultLocale")
+ fun getSDKLevel(): String {
+ getCodename().let {
+ return if (it.isBlank() || it.equals("REL", true)) {
+ VERSION.SDK_INT.toString()
} else {
- ""
+ it.toUpperCase()
}
}
+ }
- fun getPatchLevel(): String {
- return if (VERSION.SDK_INT >= VERSION_CODES.M) {
- VERSION.SECURITY_PATCH
- } else {
- ""
- }
+ fun getPreviewSDK(): String {
+ return if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ VERSION.PREVIEW_SDK_INT.toString()
+ } else {
+ ""
}
+ }
- fun getVMVersion(): String {
- val vmVersion = System.getProperty("java.vm.version")
- val vmName = if (Version(vmVersion).isAtLeast("2", true)) "ART" else "Dalvik"
- return "$vmName $vmVersion"
+ fun getPatchLevel(): String {
+ return if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ VERSION.SECURITY_PATCH
+ } else {
+ ""
}
+ }
- fun getKernelVersion(): String = System.getProperty("os.version") ?: ""
+ fun getVMVersion(): String {
+ val vmVersion = System.getProperty("java.vm.version")
+ val vmName = if (Version(vmVersion).isAtLeast("2", true)) "ART" else "Dalvik"
+ return "$vmName $vmVersion"
}
+
+ fun getKernelVersion(): String = System.getProperty("os.version") ?: ""
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/systemapps/SystemAppsDataProvider.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/systemapps/SystemAppsDataProvider.kt
index 0a3c398e..ff0400b7 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/systemapps/SystemAppsDataProvider.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/data/device/systemapps/SystemAppsDataProvider.kt
@@ -9,47 +9,44 @@ import android.os.Build.VERSION_CODES
import android.webkit.WebView
import com.g00fy2.versioncompare.Version
-class SystemAppsDataProvider {
+object SystemAppsDataProvider {
- companion object {
-
- fun getGooglePlayServicesVersion(context: Context): String {
- return try {
- context.packageManager.getPackageInfo("com.google.android.gms", 0).versionName
- } catch (e: NameNotFoundException) {
- ""
- }
+ fun getGooglePlayServicesVersion(context: Context): String {
+ return try {
+ context.packageManager.getPackageInfo("com.google.android.gms", 0).versionName
+ } catch (e: NameNotFoundException) {
+ ""
}
+ }
- @SuppressLint("PrivateApi", "WebViewApiAvailability")
- fun getWebViewImplementation(context: Context): String {
- return when {
- VERSION.SDK_INT >= VERSION_CODES.O -> {
- WebView.getCurrentWebViewPackage()?.let {
+ @SuppressLint("PrivateApi", "WebViewApiAvailability")
+ fun getWebViewImplementation(context: Context): String {
+ return when {
+ VERSION.SDK_INT >= VERSION_CODES.O -> {
+ WebView.getCurrentWebViewPackage()?.let {
+ context.packageManager.getApplicationLabel(it.applicationInfo).toString() + " " + it.versionName
+ } ?: ""
+ }
+ VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP -> {
+ try {
+ (Class.forName("android.webkit.WebViewFactory")
+ .getMethod("getLoadedPackageInfo")
+ .invoke(null) as PackageInfo?)?.let {
context.packageManager.getApplicationLabel(it.applicationInfo).toString() + " " + it.versionName
- } ?: ""
- }
- VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP -> {
- try {
- (Class.forName("android.webkit.WebViewFactory")
- .getMethod("getLoadedPackageInfo")
- .invoke(null) as PackageInfo?)?.let {
- context.packageManager.getApplicationLabel(it.applicationInfo).toString() + " " + it.versionName
- }
- ?: ""
- } catch (t: Throwable) {
- ""
}
+ ?: ""
+ } catch (t: Throwable) {
+ ""
}
- Version(VERSION.RELEASE).isAtLeast("4.4.3") -> "WebView v33.0.0.0"
- VERSION.SDK_INT >= VERSION_CODES.KITKAT -> "WebView v30.0.0.0"
- else -> try {
- context.packageManager.getPackageInfo("com.google.android.webview", 0)
- } catch (e: NameNotFoundException) {
- null
- }?.let { context.packageManager.getApplicationLabel(it.applicationInfo).toString() + " " + it.versionName }
- ?: ""
}
+ Version(VERSION.RELEASE).isAtLeast("4.4.3") -> "WebView v33.0.0.0"
+ VERSION.SDK_INT >= VERSION_CODES.KITKAT -> "WebView v30.0.0.0"
+ else -> try {
+ context.packageManager.getPackageInfo("com.google.android.webview", 0)
+ } catch (e: NameNotFoundException) {
+ null
+ }?.let { context.packageManager.getApplicationLabel(it.applicationInfo).toString() + " " + it.versionName }
+ ?: ""
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/di/ActivityModule.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/di/ActivityModule.kt
index 3231410b..b375948a 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/di/ActivityModule.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/di/ActivityModule.kt
@@ -1,6 +1,5 @@
package com.g00fy2.developerwidget.di
-import android.content.Context
import com.g00fy2.developerwidget.base.BaseActivity
import com.g00fy2.developerwidget.di.annotations.ACTIVITY
import com.g00fy2.developerwidget.di.annotations.ActivityScope
@@ -14,5 +13,5 @@ abstract class ActivityModule {
@Binds
@ActivityScope
@Named(ACTIVITY)
- abstract fun provideActivityContext(activity: BaseActivity): Context
+ abstract fun provideBaseActivity(activity: BaseActivity): BaseActivity
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/di/AppComponent.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/di/AppComponent.kt
index 2e8781d5..b908c681 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/di/AppComponent.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/di/AppComponent.kt
@@ -7,7 +7,14 @@ import dagger.android.AndroidInjector
import javax.inject.Singleton
@Singleton
-@Component(modules = [AndroidInjectionModule::class, AppModule::class, ActivityBindingModule::class, BroadcastBindingModule::class, SingletonControllerModule::class, DeviceDataModule::class])
+@Component(
+ modules = [AndroidInjectionModule::class,
+ AppModule::class,
+ ActivityBindingModule::class,
+ BroadcastBindingModule::class,
+ GlobalControllerModule::class,
+ DeviceDataModule::class]
+)
interface AppComponent : AndroidInjector {
@Component.Factory
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/di/ControllerModule.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/di/ControllerModule.kt
index ec318ff2..8a693d2b 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/di/ControllerModule.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/di/ControllerModule.kt
@@ -6,8 +6,8 @@ import com.g00fy2.developerwidget.controllers.IntentController
import com.g00fy2.developerwidget.controllers.IntentControllerImpl
import com.g00fy2.developerwidget.controllers.PermissionController
import com.g00fy2.developerwidget.controllers.PermissionControllerImpl
-import com.g00fy2.developerwidget.controllers.StorageDirsController
-import com.g00fy2.developerwidget.controllers.StorageDirsControllerImpl
+import com.g00fy2.developerwidget.controllers.PreferenceController
+import com.g00fy2.developerwidget.controllers.PreferenceControllerImpl
import com.g00fy2.developerwidget.controllers.StringController
import com.g00fy2.developerwidget.controllers.StringControllerImpl
import com.g00fy2.developerwidget.controllers.ToastController
@@ -17,13 +17,14 @@ import com.g00fy2.developerwidget.controllers.WidgetPreferenceControllerImpl
import com.g00fy2.developerwidget.di.annotations.ActivityScope
import dagger.Binds
import dagger.Module
+import dagger.Reusable
import javax.inject.Singleton
@Module
-abstract class SingletonControllerModule {
+abstract class GlobalControllerModule {
@Binds
- @Singleton
+ @Reusable
abstract fun providesDayNightController(dayNightControllerImpl: DayNightControllerImpl): DayNightController
@Binds
@@ -52,5 +53,5 @@ abstract class ActivityControllerModule {
@Binds
@ActivityScope
- abstract fun provideStorageDirsController(storageDirsControllerImpl: StorageDirsControllerImpl): StorageDirsController
+ abstract fun providePreferenceController(preferenceControllerImpl: PreferenceControllerImpl): PreferenceController
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/di/DeviceDataModule.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/di/DeviceDataModule.kt
index 9118ac95..1dd4cc2f 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/di/DeviceDataModule.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/di/DeviceDataModule.kt
@@ -6,16 +6,16 @@ import com.g00fy2.developerwidget.data.WidgetsPreferencesDataSource
import com.g00fy2.developerwidget.data.WidgetsPreferencesDataSourceImpl
import dagger.Binds
import dagger.Module
-import javax.inject.Singleton
+import dagger.Reusable
@Module
abstract class DeviceDataModule {
@Binds
- @Singleton
+ @Reusable
abstract fun providesDeviceDataModule(deviceDataSourceImpl: DeviceDataSourceImpl): DeviceDataSource
@Binds
- @Singleton
+ @Reusable
abstract fun providesWidgetsPreferencesDataSource(widgetsPreferencesDataSourceImpl: WidgetsPreferencesDataSourceImpl): WidgetsPreferencesDataSource
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/di/annotations/ScopeNames.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/di/annotations/DaggerConstants.kt
similarity index 100%
rename from app/src/main/kotlin/com/g00fy2/developerwidget/di/annotations/ScopeNames.kt
rename to app/src/main/kotlin/com/g00fy2/developerwidget/di/annotations/DaggerConstants.kt
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ActivityExtension.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ActivityExtension.kt
deleted file mode 100644
index de3ba401..00000000
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ActivityExtension.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.g00fy2.developerwidget.ktx
-
-import android.app.Activity
-import android.os.Build.VERSION
-import android.os.Build.VERSION_CODES
-
-fun Activity.gesturalNavigationMode(): Boolean {
- return if (VERSION.SDK_INT >= VERSION_CODES.Q) {
- window.decorView.rootWindowInsets.systemGestureInsets.left > 0
- } else {
- false
- }
-}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/AppInfoExtensions.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/AppInfoExtensions.kt
deleted file mode 100644
index 64861d5a..00000000
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/AppInfoExtensions.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.g00fy2.developerwidget.ktx
-
-import com.g00fy2.developerwidget.activities.appmanager.AppInfo
-
-fun AppInfo.filterPackageName(filter: String): Boolean {
- var result = false
- val filterInputs = filter.split("*")
- var tempValue = packageName
- for (i in filterInputs) {
- if (tempValue.contains(i, true)) {
- tempValue = tempValue.substringAfter(i)
- result = true
- } else {
- return false
- }
- }
- return result
-}
-
-fun AppInfo.filterPackageName(filterEntries: Collection): Boolean {
- for (i in filterEntries) {
- if (filterPackageName(i)) return true
- }
- return false
-}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/TextViewExtensions.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/TextViewExtensions.kt
new file mode 100644
index 00000000..eb983316
--- /dev/null
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/TextViewExtensions.kt
@@ -0,0 +1,32 @@
+package com.g00fy2.developerwidget.ktx
+
+import android.text.SpannableString
+import android.text.Spanned
+import android.text.TextPaint
+import android.text.method.LinkMovementMethod
+import android.text.style.ClickableSpan
+import android.view.View
+import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
+import com.g00fy2.developerwidget.R
+
+fun TextView.setClickableText(text: String, linkTarget: String, onClick: () -> Unit) {
+ val result = SpannableString(text)
+ val clickableSpan = object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ onClick()
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ super.updateDrawState(ds)
+ ds.color = ResourcesCompat.getColor(context.resources, R.color.colorAccent, null)
+ ds.isUnderlineText = false
+ }
+ }
+ val linkStart = result.indexOf(linkTarget)
+ if (linkStart >= 0) {
+ result.setSpan(clickableSpan, linkStart, linkStart + linkTarget.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ }
+ this.text = result
+ movementMethod = LinkMovementMethod.getInstance()
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ViewExtension.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ViewExtension.kt
index b49dcb11..aa86ea9d 100644
--- a/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ViewExtension.kt
+++ b/app/src/main/kotlin/com/g00fy2/developerwidget/ktx/ViewExtension.kt
@@ -8,6 +8,7 @@ import android.view.ViewGroup
import android.view.WindowInsets
import androidx.annotation.Px
import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
import androidx.core.view.marginBottom
import androidx.core.view.marginLeft
import androidx.core.view.marginRight
@@ -16,9 +17,9 @@ import androidx.core.view.marginTop
fun View.addRipple(asForeground: Boolean = false) {
TypedValue().apply { context.theme.resolveAttribute(android.R.attr.selectableItemBackground, this, true) }
.resourceId.let {
- if (VERSION.SDK_INT < VERSION_CODES.M || !asForeground) setBackgroundResource(it) else foreground =
- context.getDrawable(it)
- }
+ if (VERSION.SDK_INT < VERSION_CODES.M || !asForeground) setBackgroundResource(it) else foreground =
+ ContextCompat.getDrawable(context, it)
+ }
}
fun View.updateMargin(
diff --git a/app/src/main/res/drawable-night/ic_about.xml b/app/src/main/res/drawable-night/ic_about.xml
deleted file mode 100644
index 9771b2e1..00000000
--- a/app/src/main/res/drawable-night/ic_about.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night/ic_check.xml b/app/src/main/res/drawable-night/ic_check.xml
deleted file mode 100644
index b3b91ba2..00000000
--- a/app/src/main/res/drawable-night/ic_check.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night/ic_clear.xml b/app/src/main/res/drawable-night/ic_clear.xml
deleted file mode 100644
index f775ee90..00000000
--- a/app/src/main/res/drawable-night/ic_clear.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night/ic_delete.xml b/app/src/main/res/drawable-night/ic_delete.xml
deleted file mode 100644
index 86f608cc..00000000
--- a/app/src/main/res/drawable-night/ic_delete.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/bg_dialog_button_bright_ripple.xml b/app/src/main/res/drawable-v21/bg_dialog_button_bright_ripple.xml
new file mode 100644
index 00000000..8bf21499
--- /dev/null
+++ b/app/src/main/res/drawable-v21/bg_dialog_button_bright_ripple.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/bg_dialog_colored_button.xml b/app/src/main/res/drawable-v21/bg_dialog_colored_button.xml
new file mode 100644
index 00000000..63d853ca
--- /dev/null
+++ b/app/src/main/res/drawable-v21/bg_dialog_colored_button.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_dialog_button_bright_ripple.xml b/app/src/main/res/drawable/bg_dialog_button_bright_ripple.xml
new file mode 100644
index 00000000..f77aaece
--- /dev/null
+++ b/app/src/main/res/drawable/bg_dialog_button_bright_ripple.xml
@@ -0,0 +1,31 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_dialog_colored_button.xml b/app/src/main/res/drawable/bg_dialog_colored_button.xml
new file mode 100644
index 00000000..a82d4cad
--- /dev/null
+++ b/app/src/main/res/drawable/bg_dialog_colored_button.xml
@@ -0,0 +1,31 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_dialog_shape_bright.xml b/app/src/main/res/drawable/bg_dialog_shape_bright.xml
new file mode 100644
index 00000000..5812e181
--- /dev/null
+++ b/app/src/main/res/drawable/bg_dialog_shape_bright.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/about_feedback_dialog.xml b/app/src/main/res/layout/about_feedback_dialog.xml
index 2670aa83..ddd26b3d 100644
--- a/app/src/main/res/layout/about_feedback_dialog.xml
+++ b/app/src/main/res/layout/about_feedback_dialog.xml
@@ -2,24 +2,24 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index e2c05c85..0908d04b 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -163,6 +163,11 @@
android:layout_height="1dp"
android:background="@color/dividerGrey"
/>
+
@@ -62,6 +63,7 @@
android:scaleType="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
+ app:tint="@color/backgroundColor"
app:srcCompat="@drawable/ic_delete"
/>
@@ -122,8 +124,8 @@
android:layout_marginTop="8dp"
android:ellipsize="end"
android:gravity="center"
- android:singleLine="true"
android:text="@string/scanning_apks"
+ android:textColorHighlight="@color/backgroundColor"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/recyclerview"
app:layout_constraintEnd_toEndOf="parent"
@@ -139,7 +141,6 @@
android:layout_marginEnd="@dimen/action_bar_inset"
android:layout_marginRight="@dimen/action_bar_inset"
android:layout_marginTop="4dp"
- android:background="@drawable/bg_dialog_button_ripple"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
diff --git a/app/src/main/res/layout/activity_apps.xml b/app/src/main/res/layout/activity_apps.xml
index 1973a67a..4be3708f 100644
--- a/app/src/main/res/layout/activity_apps.xml
+++ b/app/src/main/res/layout/activity_apps.xml
@@ -43,7 +43,7 @@
android:contentDescription="@string/filter"
android:focusable="true"
android:scaleType="center"
- android:tint="@color/iconTintColor"
+ app:tint="@color/iconTintColor"
app:srcCompat="@drawable/ic_filter"
/>
@@ -119,7 +119,7 @@
android:layout_height="12dp"
android:layout_gravity="center|start"
android:contentDescription="@string/show_all"
- android:tint="@color/colorAccent"
+ app:tint="@color/colorAccent"
app:srcCompat="@drawable/ic_chevron_right"
/>
@@ -214,7 +214,6 @@
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
- android:background="@drawable/bg_dialog_button_ripple"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
diff --git a/app/src/main/res/layout/activity_widget_config.xml b/app/src/main/res/layout/activity_widget_config.xml
index fcfc1f88..1c80d6a0 100644
--- a/app/src/main/res/layout/activity_widget_config.xml
+++ b/app/src/main/res/layout/activity_widget_config.xml
@@ -92,8 +92,6 @@
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="@string/add_widget"
- android:textAllCaps="false"
- android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="@+id/top_view"
app:layout_constraintStart_toStartOf="parent"
style="@style/ConfigureButtonAppearance"
@@ -120,6 +118,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="12dp"
+ android:contentDescription="@string/share_device_data"
android:visibility="invisible"
app:tint="@color/backgroundColor"
app:rippleColor="@color/rippleBackground"
diff --git a/app/src/main/res/layout/apk_delete_dialog.xml b/app/src/main/res/layout/apk_delete_dialog.xml
index 1ff7ea9a..ef386331 100644
--- a/app/src/main/res/layout/apk_delete_dialog.xml
+++ b/app/src/main/res/layout/apk_delete_dialog.xml
@@ -3,63 +3,41 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
>
\ No newline at end of file
diff --git a/app/src/main/res/layout/apk_item.xml b/app/src/main/res/layout/apk_item.xml
index 0a0bd490..9cc72e1a 100644
--- a/app/src/main/res/layout/apk_item.xml
+++ b/app/src/main/res/layout/apk_item.xml
@@ -35,6 +35,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_check"
+ app:tint="@color/backgroundColor"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/appwidget_layout.xml b/app/src/main/res/layout/appwidget_layout.xml
index 9df5663b..53183876 100644
--- a/app/src/main/res/layout/appwidget_layout.xml
+++ b/app/src/main/res/layout/appwidget_layout.xml
@@ -6,7 +6,7 @@
android:background="@drawable/bg_widget_outer_shape"
android:baselineAligned="false"
android:orientation="horizontal"
- tools:ignore="ContentDescription"
+ tools:ignore="ContentDescription,UseAppTint"
>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/configuration_menu.xml b/app/src/main/res/menu/configuration_menu.xml
index 4af93ad5..36758215 100644
--- a/app/src/main/res/menu/configuration_menu.xml
+++ b/app/src/main/res/menu/configuration_menu.xml
@@ -5,5 +5,6 @@
android:id="@+id/about_button"
android:icon="@drawable/ic_about"
android:title="@string/about"
+ app:iconTint="@color/menuItem"
app:showAsAction="always"/>
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index 953bd2f7..8a469e66 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -10,6 +10,7 @@
@color/nightBackground
@color/transparentBackground50_night
#5f6368
+ #424242
#A6202124
#a0a0a0
@@ -20,4 +21,5 @@
@color/nightGrey
#33000000
+ @color/iconTintColor
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
index f689c799..59c24f7c 100644
--- a/app/src/main/res/values-night/styles.xml
+++ b/app/src/main/res/values-night/styles.xml
@@ -15,8 +15,10 @@
-
diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml
index 243c227f..f909aca8 100644
--- a/app/src/main/res/values-sw600dp/dimens.xml
+++ b/app/src/main/res/values-sw600dp/dimens.xml
@@ -4,4 +4,5 @@
80dp
22dp
28dp
+ 608dp
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 423f71d9..be13a37a 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -14,6 +14,7 @@
#80ffffff
#80202124
@color/lighterGrey
+ @color/backgroundColor
@color/black
@color/navigationBarColor
@@ -27,6 +28,7 @@
@color/lighterGrey
#33808080
+ @color/colorAccent
#00000000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 2a46f5da..4ee1fbfb 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -5,4 +5,5 @@
14dp
24dp
14sp
+ 336dp
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6cc3b7e6..2cf715d9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3,9 +3,11 @@
Developer Widget
Install APK
Manage Apps
+ OK
Cancel
Missing permissions
No APK files found
+ search depth %d
No apps found
Loading data…
Filter
@@ -34,6 +36,7 @@
Release notes
Feedback
Request features or report bugs
+ APK search depth
Show app icon
Display application icon on launcher
You may need to reboot to take effect.
@@ -62,6 +65,13 @@
You have to manually add a new widget using your launcher.
You may need to restart the app to fully take effect.
Share device data
+ Potentially harmful app
+ This app contains code that attempts to bypass Android\'s security protections.
+ Permissions without runtime request:
+ Keep me safe
+ Install anyway
+ Infinite (can slow down APK search)
+ %d (Default)
Device
System
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 6e2d40d9..d4be6427 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -13,6 +13,8 @@
- @style/ActionBarAccent
- @style/ActionBarBackground
- @null
+
+ - sans-serif
- @color/colorEdgeEffect
- @color/navigationBarColor
@@ -42,6 +44,8 @@
- @color/textPrimary
- @color/textTertiary
+ - @dimen/dialog_width
+ - @dimen/dialog_width
- true
- @drawable/bg_dialog_shape
@@ -50,13 +54,40 @@
- @color/colorEdgeEffect
+
+
+
+
-
+
+
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index e185f339..00000000
--- a/build.gradle
+++ /dev/null
@@ -1,68 +0,0 @@
-import com.android.tools.r8.Version
-import com.github.jk1.license.filter.*
-import com.github.jk1.license.render.*
-
-apply plugin: 'com.github.jk1.dependency-license-report'
-
-buildscript {
- ext {
- // SDK and plugins
- compileSdkVersion = 29
- buildToolsVersion = '29.0.2'
- minSdkVersion = 14
- targetSdkVersion = 29
- androidGradleVersion = '4.0.0-alpha08'
- versioningPluginVersion = '1.0.2'
- licenseReportVersion = '1.12'
-
- // Library versions
- kotlinVersion = '1.3.61'
- coroutinesVersion = '1.3.3'
- appcompatVersion = '1.2.0-alpha01'
- coreKtxVersion = '1.2.0-rc01'
- activityVersion = '1.1.0-rc03'
- lifecycleVersion = '2.2.0-rc03'
- materialVersion = '1.2.0-alpha03'
- recyclerviewVersion = '1.2.0-alpha01'
- vectorDrawableVersion = '1.1.0'
- constraintlayoutVersion = '2.0.0-beta4'
- timberVersion = '4.7.1'
- daggerVersion = '2.25.4'
- versCompVersion = '1.3.4'
- }
- repositories {
- google()
- mavenCentral()
- jcenter() {
- content {
- includeModule 'eu.appcom.gradle', 'android-versioning'
- includeModule 'org.jetbrains.trove4j', 'trove4j'
- }
- }
- gradlePluginPortal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$androidGradleVersion"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
- classpath "eu.appcom.gradle:android-versioning:$versioningPluginVersion"
- classpath "com.github.jk1:gradle-license-report:$licenseReportVersion"
- }
-}
-
-licenseReport {
- configurations = ['releaseRuntimeClasspath']
- renderers = [new SimpleHtmlReportRenderer(), new JsonReportRenderer()]
- filters = [new LicenseBundleNormalizer()]
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
-
-task printR8Version() {
- try {
- println "R8 version: " + Version.getVersionString()
- } catch (ignored) {
- println 'R8 version: unknown'
- }
-}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..ecf136ee
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,3 @@
+tasks.register("clean") {
+ delete(buildDir)
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index b52439ea..a375ce61 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,19 +1,20 @@
-android.useAndroidX=true
-
-# Enable jetifier, currently only because dagger still uses android.support.annotation
-android.enableJetifier=true
+# Versions used for dependency resolution in settings.gradle.kts
+kotlinVersion=1.4.10
+androidGradlePluginVersion=4.2.0-alpha13
+nanogiantsVersioning=2.4.0
+gradleEnterpriseVersion=3.4.1
+# Allow usage of AndroidX instead of the old support libraries.
+android.useAndroidX=true
# Use R8 in full mode instead of ProGuard compatibility mode.
android.enableR8.fullMode=true
-
-# Enable rudimentary R class namespacing where each library only contains
-# references to the resources it declares instead of declarations plus all
-# transitive dependency references.
-android.namespacedRClass=true
-
-# Only keep the single relevant constructor for types mentioned in XML files
-# instead of using a parameter wildcard which keeps them all.
-android.useMinimalKeepRules=true
-
+# Enable rudimentary R class namespacing where each library only contains references to the resources it declares
+# instead of declarations plus all transitive dependency references.
+android.nonTransitiveRClass=true
+# Generate the compile time only R class using the app's local resources
+android.enableAppCompileTimeRClass=true
+# Enable supported AAPT2 optimize suboperations (ResourceObfuscation, SparseResourceEncoding, ResourcePathShortening) as
+# an effort to reduce APK size.
+android.enableResourceOptimizations=true
# Set the build VMs heap size.
-org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f3d88b1c..e708b1c0 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e3185a77..8c6ce341 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-rc-2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-rc-4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 2fe81a7d..4f906e0c 100755
--- a/gradlew
+++ b/gradlew
@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
diff --git a/gradlew.bat b/gradlew.bat
index 9618d8d9..107acd32 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index 0c0a85aa..00000000
--- a/settings.gradle
+++ /dev/null
@@ -1,12 +0,0 @@
-plugins {
- id 'com.gradle.enterprise' version '3.1.1'
-}
-
-gradleEnterprise {
- buildScan {
- termsOfServiceUrl = 'https://gradle.com/terms-of-service'
- termsOfServiceAgree = 'yes'
- }
-}
-
-include ':app'
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 00000000..d910d6c7
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,36 @@
+include("app")
+
+pluginManagement {
+ val kotlinVersion: String by settings
+ val androidGradlePluginVersion: String by settings
+ val nanogiantsVersioning: String by settings
+ val gradleEnterpriseVersion: String by settings
+ repositories {
+ google()
+ gradlePluginPortal()
+ mavenCentral()
+ }
+ resolutionStrategy {
+ eachPlugin {
+ when (requested.id.id) {
+ "com.android.application" -> useModule("com.android.tools.build:gradle:$androidGradlePluginVersion")
+ "de.nanogiants.android-versioning" -> useVersion(nanogiantsVersioning)
+ "com.gradle.enterprise" -> useVersion(gradleEnterpriseVersion)
+ }
+ if (requested.id.namespace == "org.jetbrains.kotlin") useVersion(kotlinVersion)
+ }
+ }
+}
+
+plugins {
+ id("com.gradle.enterprise")
+}
+
+gradleEnterprise {
+ buildScan {
+ termsOfServiceUrl = "https://gradle.com/terms-of-service"
+ termsOfServiceAgree = "yes"
+ publishAlwaysIf(!System.getenv("CI").isNullOrEmpty())
+ isUploadInBackground = false
+ }
+}
\ No newline at end of file