From e0c89fa0c26b605be95d5468c4180d26c58c8601 Mon Sep 17 00:00:00 2001 From: Thomas Wirth Date: Tue, 2 Jul 2019 18:54:01 +0200 Subject: [PATCH 1/6] Try newer display methods on api < 17 and fix 16:10 ratio --- .../device/display/DisplayDataProvider.kt | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) 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 58438c2f..c71fd151 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 @@ -1,9 +1,8 @@ package com.g00fy2.developerwidget.data.device.display +import android.annotation.SuppressLint import android.content.Context import android.graphics.Point -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES import android.util.DisplayMetrics import android.view.WindowManager import androidx.core.content.getSystemService @@ -16,12 +15,13 @@ class DisplayDataProvider { companion object { + @SuppressLint("NewApi") fun getResolution(context: Context): Point? { context.getSystemService()?.defaultDisplay?.let { windowManager -> Point().let { point -> - if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { + try { windowManager.getRealSize(point) - } else { + } catch (e: NoSuchMethodError) { windowManager.getSize(point) } return point @@ -30,12 +30,13 @@ class DisplayDataProvider { return null } + @SuppressLint("NewApi") fun geDisplayDpi(context: Context): String { context.getSystemService()?.defaultDisplay?.let { windowManager -> DisplayMetrics().let { displayMetrics -> - if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { + try { windowManager.getRealMetrics(displayMetrics) - } else { + } catch (e: NoSuchMethodError) { windowManager.getMetrics(displayMetrics) } return displayMetrics.xdpi.roundToInt().toString() + " / " + displayMetrics.ydpi.roundToInt() + " dpi" @@ -45,11 +46,19 @@ class DisplayDataProvider { } fun getDisplayRatio(resolution: Point): String { - val resX = min(resolution.x, resolution.y) - val resY = max(resolution.x, resolution.y) - val gcd = gcd(resX, resY) + 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 = (resY / gcd).toString() + ":" + (resX / 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 { From 06ba72eba657869f1bf7dcc21fbeb02255fdf8cf Mon Sep 17 00:00:00 2001 From: Thomas Wirth Date: Wed, 3 Jul 2019 11:42:36 +0200 Subject: [PATCH 2/6] Update dependencies and add vector drawable support library --- app/build.gradle | 3 +++ .../activities/appmanager/AppsActivity.kt | 3 ++- .../widgetconfig/WidgetConfigActivity.kt | 3 ++- .../receiver/widget/WidgetProviderImpl.kt | 10 ++++++++++ app/src/main/res/layout/activity_about.xml | 2 +- app/src/main/res/layout/activity_apk.xml | 6 +++--- app/src/main/res/layout/activity_apps.xml | 5 +++-- app/src/main/res/layout/apk_item.xml | 4 ++-- app/src/main/res/layout/app_filter_info.xml | 3 ++- app/src/main/res/layout/appwidget_layout.xml | 4 ++-- .../main/res/layout/appwidget_layout_day.xml | 4 ++-- .../res/layout/appwidget_layout_night.xml | 4 ++-- .../layout/appwidget_layout_placeholder.xml | 20 ++++--------------- build.gradle | 7 ++++--- 14 files changed, 42 insertions(+), 36 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d29134f8..bed0f805 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,6 +16,8 @@ android { targetSdkVersion rootProject.targetSdkVersion versionCode versioning.getVersionCode() versionName versioning.getVersionName() + + vectorDrawables.useSupportLibrary = true } signingConfigs { release { @@ -74,6 +76,7 @@ dependencies { // UI implementation "com.google.android.material:material:$materialVersion" + implementation "androidx.vectordrawable:vectordrawable:$vectorDrawableVersion" // Misc implementation "com.jakewharton.timber:timber:$timberVersion" 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 0193c88c..92f2538d 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 @@ -15,6 +15,7 @@ import android.view.MotionEvent import android.view.View import android.view.inputmethod.EditorInfo import android.widget.EditText +import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.widget.TooltipCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.ViewCompat @@ -194,7 +195,7 @@ class AppsActivity : BaseActivity(R.layout.activity_apps, true), AppsContract.Ap } private fun initClearDrawable(): Drawable? { - return ResourcesCompat.getDrawable(resources, R.drawable.ic_clear, null)?.apply { + return AppCompatResources.getDrawable(this, R.drawable.ic_clear)?.apply { if (VERSION.SDK_INT >= VERSION_CODES.Q) { colorFilter = BlendModeColorFilter(ResourcesCompat.getColor(resources, R.color.iconTintColor, null), SRC_IN) 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 b6707491..4e453d19 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 @@ -23,6 +23,7 @@ import android.view.View import android.view.View.OnFocusChangeListener import android.view.inputmethod.EditorInfo import android.webkit.WebView +import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.getSystemService import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.LinearLayoutManager @@ -268,7 +269,7 @@ class WidgetConfigActivity : BaseActivity(R.layout.activity_widget_config), Widg ).size private fun initEditDrawable(): Drawable? { - return ResourcesCompat.getDrawable(resources, R.drawable.ic_edit, null)?.apply { + return AppCompatResources.getDrawable(this, R.drawable.ic_edit)?.apply { if (VERSION.SDK_INT >= VERSION_CODES.Q) { colorFilter = BlendModeColorFilter(ResourcesCompat.getColor(resources, R.color.iconTintColor, null), BlendMode.SRC_IN) diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/receiver/widget/WidgetProviderImpl.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/receiver/widget/WidgetProviderImpl.kt index 101e4acf..ccdd4507 100644 --- a/app/src/main/kotlin/com/g00fy2/developerwidget/receiver/widget/WidgetProviderImpl.kt +++ b/app/src/main/kotlin/com/g00fy2/developerwidget/receiver/widget/WidgetProviderImpl.kt @@ -9,6 +9,8 @@ import android.content.Intent import android.util.SparseArray import android.widget.RemoteViews import androidx.appcompat.app.AppCompatDelegate +import androidx.appcompat.content.res.AppCompatResources +import androidx.core.graphics.drawable.toBitmap import com.g00fy2.developerwidget.BuildConfig import com.g00fy2.developerwidget.R import com.g00fy2.developerwidget.activities.apkinstall.ApkActivity @@ -108,6 +110,14 @@ class WidgetProviderImpl : AppWidgetProvider(), WidgetProvider { data[DeviceDataSourceImpl.SDK]?.let { sdk -> views.setTextViewText(R.id.sdk_int_textview, context.getString(sdk.title) + " " + sdk.value) } + views.setImageViewBitmap( + R.id.apps_imageview, + AppCompatResources.getDrawable(context, R.drawable.ic_apps_grid)?.toBitmap() + ) + views.setImageViewBitmap( + R.id.apk_imageview, + AppCompatResources.getDrawable(context, R.drawable.ic_apps)?.toBitmap() + ) } private fun updateWidgetButtonIntents(widgetId: Int, views: RemoteViews) { diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 47a97a12..83c34ec1 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -36,7 +36,7 @@ android:layout_width="96dp" android:layout_height="96dp" android:layout_gravity="center" - android:src="@drawable/ic_launcher_foreground" + app:srcCompat="@drawable/ic_launcher_foreground" tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/layout/activity_apk.xml b/app/src/main/res/layout/activity_apk.xml index d05c81e3..52c723b0 100644 --- a/app/src/main/res/layout/activity_apk.xml +++ b/app/src/main/res/layout/activity_apk.xml @@ -43,9 +43,9 @@ android:contentDescription="@string/clear" android:focusable="true" android:scaleType="center" - android:src="@drawable/ic_clear" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_clear" /> @@ -41,8 +42,8 @@ android:contentDescription="@string/filter" android:focusable="true" android:scaleType="center" - android:src="@drawable/ic_filter" android:tint="@color/iconTintColor" + app:srcCompat="@drawable/ic_filter" /> @@ -136,8 +137,8 @@ android:layout_height="96dp" android:layout_gravity="center" android:contentDescription="@string/no_apps_found" - android:src="@drawable/ic_sad" android:visibility="invisible" + app:srcCompat="@drawable/ic_sad" /> diff --git a/app/src/main/res/layout/app_filter_info.xml b/app/src/main/res/layout/app_filter_info.xml index c39f00a6..df4d5898 100644 --- a/app/src/main/res/layout/app_filter_info.xml +++ b/app/src/main/res/layout/app_filter_info.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="40dp" + xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="horizontal" android:paddingLeft="@dimen/action_bar_inset" android:paddingRight="@dimen/action_bar_inset" @@ -13,8 +14,8 @@ android:layout_height="12dp" android:layout_gravity="center|start" android:contentDescription="@string/show_all" - android:src="@drawable/ic_chevron_right" android:tint="@color/colorAccent" + app:srcCompat="@drawable/ic_chevron_right" /> - - Date: Wed, 3 Jul 2019 18:47:43 +0200 Subject: [PATCH 3/6] Add device data share feature --- .../widgetconfig/WidgetConfigActivity.kt | 12 +++++++++++ .../widgetconfig/WidgetConfigContract.kt | 2 ++ .../widgetconfig/WidgetConfigPresenterImpl.kt | 20 +++++++++++++++++++ .../controllers/IntentController.kt | 2 ++ .../controllers/IntentControllerImpl.kt | 8 ++++++++ app/src/main/res/drawable/ic_share.xml | 9 +++++++++ .../res/layout/activity_widget_config.xml | 17 ++++++++++++++-- app/src/main/res/values/strings.xml | 1 + 8 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/ic_share.xml 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 4e453d19..86d316f6 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,6 +26,7 @@ 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.marginBottom import androidx.recyclerview.widget.LinearLayoutManager import com.g00fy2.developerwidget.R import com.g00fy2.developerwidget.activities.about.AboutActivity @@ -74,6 +75,16 @@ class WidgetConfigActivity : BaseActivity(R.layout.activity_widget_config), Widg } setActionbarElevationListener(widget_config_root_scrollview) + widget_config_root_scrollview.viewTreeObserver.addOnScrollChangedListener { + val scrollableRange = + widget_config_root_scrollview.computeVerticalScrollRange() - widget_config_root_scrollview.height + val fabOffset = (share_fab.height / 2) + share_fab.marginBottom + if (widget_config_root_scrollview.scrollY < scrollableRange - fabOffset) { + share_fab.hide() + } else { + share_fab.show() + } + } adapter = DeviceDataAdapter() recyclerview.setHasFixedSize(false) @@ -203,6 +214,7 @@ class WidgetConfigActivity : BaseActivity(R.layout.activity_widget_config), Widg true } } + share_fab.setOnClickListener { presenter.shareDeviceData()} } private fun toggleDeviceNameEdit(editable: Boolean) { diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigContract.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigContract.kt index 4cff01ba..dbe3a20e 100644 --- a/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigContract.kt +++ b/app/src/main/kotlin/com/g00fy2/developerwidget/activities/widgetconfig/WidgetConfigContract.kt @@ -27,5 +27,7 @@ interface WidgetConfigContract { fun showManuallyAddWidgetNotice() fun showHomescreen() + + fun shareDeviceData() } } \ No newline at end of file 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 3d2b9bbb..f4f0c9b0 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 @@ -13,6 +13,7 @@ import com.g00fy2.developerwidget.data.DeviceDataSource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import timber.log.Timber import javax.inject.Inject class WidgetConfigPresenterImpl @Inject constructor() : BasePresenterImpl(), @@ -95,5 +96,24 @@ class WidgetConfigPresenterImpl @Inject constructor() : BasePresenterImpl(), ) } + override fun shareDeviceData() { + launch { + withContext(Dispatchers.IO) { + getDeviceData() + }.let { intentController.shareDeviceData(formatDeviceDataString(it)) } + } + } + + private fun formatDeviceDataString(data: List>): String { + return data.joinToString("") { + if (it.second.isHeader) { + "\n" + stringController.getString(it.second.title) + "\n" + } else { + stringController.getString(it.second.title) + ": \t" + it.second.value.replace("\n", " ") + "\n" + } + }.removeSurrounding("\n") + } + + override fun showManuallyAddWidgetNotice() = toastController.showToast(R.string.manually_add_widget) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentController.kt b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentController.kt index 399b264d..1b93dba5 100644 --- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentController.kt +++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentController.kt @@ -13,4 +13,6 @@ interface IntentController { fun sendMailToDeveloper() fun showHomescreen() + + fun shareDeviceData(data: String) } \ 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 26fcdeb7..50f12af2 100644 --- a/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt +++ b/app/src/main/kotlin/com/g00fy2/developerwidget/controllers/IntentControllerImpl.kt @@ -67,6 +67,14 @@ class IntentControllerImpl @Inject constructor() : IntentController { }) } + override fun shareDeviceData(data: String) { + startActivity(Intent.createChooser(Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, data) + type = "text/plain" + }, context.getString(R.string.share_device_data))) + } + private fun startActivity(intent: Intent) { if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 00000000..9f0bc3e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_widget_config.xml b/app/src/main/res/layout/activity_widget_config.xml index 6043eeb3..01fe79a1 100644 --- a/app/src/main/res/layout/activity_widget_config.xml +++ b/app/src/main/res/layout/activity_widget_config.xml @@ -100,9 +100,22 @@ android:layout_height="wrap_content" android:paddingBottom="8dp" app:layout_constraintTop_toBottomOf="@+id/top_view" - > + /> - + Show all 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 Device System From ae12a89aced4e46d0a43aff6b1eeda70a27311b9 Mon Sep 17 00:00:00 2001 From: Thomas Wirth Date: Fri, 5 Jul 2019 10:23:10 +0200 Subject: [PATCH 4/6] Update kotlin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ea5942f2..5c2ad455 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { versioningPluginVersion = '1.0.0' // Library versions - kotlinVersion = '1.3.40' + kotlinVersion = '1.3.41' coroutinesVersion = '1.2.1' appcompatVersion = '1.1.0-rc01' coreKtxVersion = '1.2.0-alpha02' From 38345fe51d009366fdf8979fe310aecda4f56a78 Mon Sep 17 00:00:00 2001 From: Thomas Wirth Date: Fri, 5 Jul 2019 16:07:06 +0200 Subject: [PATCH 5/6] Update Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd6562dc..13615f99 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

DeveloperWidget Icon

-# 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-green.svg?style=flat)](https://android-arsenal.com/api?level=14) [![License](https://img.shields.io/github/license/G00fY2/DeveloperWidget.svg)](https://github.com/G00fY2/DeveloperWidget/blob/develop/LICENSE) +# 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-green.svg?style=flat)](https://android-arsenal.com/api?level=14) **Small Android app that offers a widget to show device data, manage installed apps and list locally stored APK files.** From 0cbca41f727c7ab678beff92133790c6bf0a382d Mon Sep 17 00:00:00 2001 From: Thomas Wirth Date: Fri, 5 Jul 2019 16:39:32 +0200 Subject: [PATCH 6/6] Update Readme --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 13615f99..a0c62c58 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [](https://raw.githubusercontent.com/G00fY2/DeveloperWidget/gh-pages/media/store_screenshot_5.png) ## 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 as well as organize your apps and local APK files. Never again will you struggle to find APK files using a file browser or search for the app settings menu on a custom manufacturer UI. +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 as well as 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. The main feature of the app is an 4x1 (horizontally resizable) homescreen widget that shows dynamically fetched device data and allows you to browse your installed apps and local APK files. @@ -21,22 +21,21 @@ The main feature of the app is an 4x1 (horizontally resizable) homescreen widget * Homescreen widget with customizable device name * Overview of dynamically fetched device data * device model, system, cpu, memory, display, hardware features, software + * Share/export the data * Browse all installed (non system) apps and filter them by **package name** - * Opens the specific Android app settings - * Save multiple filters per widget by *enter* and *confirm* a search term + * Save multiple filters per widget * Wildcard support (e.g. **`com.*xyz`**) - * Option to temporary disable the filter * Manage local APK files - * Scan internal storage and SD-cards for valid (parsable) APK files + * Scan internal storage and SD-cards for APK files * Show file name, modification time, file size, app name, debuggable flag, versionname and versioncode * Directly install them from within the app - * Delete files by long clicking + * Delete files by long pressing * Offers useful app shortcuts starting from API 25 - * Native language settings shortcut - * Native Android developer settings shortcut - * Custom installed apps browser shortcut + * Android developer settings shortcut + * Language settings shortcut + * Browse installed apps shortcut * Manage local APK files shortcut -* Material design with **Dark mode support** (can be controlled by the user) +* Material design with **Dark mode support** (can be toggled by the user) * Allow hiding the launcher icon (< API 29) * Written in Kotlin using Coroutines and Dagger * No internet permission