Skip to content

Commit

Permalink
Implemented "Scheduled Rules" feature (#8)
Browse files Browse the repository at this point in the history
Implemented "Deactivate Apps" feature
Improved app list (show app categories, when available)
Improved install instructions (#21)
UI tweaks
Removed GitReports feature (service is offline)
Updated Android framework libraries
  • Loading branch information
flxapps committed Jan 27, 2022
1 parent 9e40e37 commit 1443d9e
Show file tree
Hide file tree
Showing 44 changed files with 1,005 additions and 247 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
> This project is currently in an alpha state. I am happy for all people who are willing to test the app and contribute by suggestions, feedback and bug reports.
# DetoxDroid

[![GitHub release](https://img.shields.io/github/release/flxapps/DetoxDroid.svg)](https://github.com/flxapps/DetoxDroid/releases/) [![GitHub license](https://img.shields.io/github/license/flxapps/DetoxDroid.svg)](https://github.com/flxapps/DetoxDroid/blob/master/LICENSE) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/flxapps/DetoxDroid/graphs/commit-activity) [![Ko-Fi](https://img.shields.io/static/v1?label=Buy%20me%20a%20coffee&message=3%20EUR&color=red)](https://ko-fi.com/flxapps/3) [![LiberaPay](https://img.shields.io/liberapay/receives/DetoxDroid)](https://liberapay.com/DetoxDroid)
Expand All @@ -22,11 +20,14 @@ According to former Google design ethicist Tristan Harris, founder of the Center
### 2. Automatically enter the "Do Not Disturb" mode
Notifications are the number one way for apps to draw our attention. Any app on our phones competes for our attention, and even games will remind us to play them if we have not opened them for a while. Reclaim your time by turning them off with the "Do Not Disturb" mode.

### 3. Break "Infinite Scrolling"
### 3. Make Apps Disappear
You can select apps that will completely vanish and be deactivated while DetoxDroid is running. Move Twitter, Reddit and other distractions into this vault during your productive hours and only open these apps, when you deliberately take pauses. Hence, you can completely forget about them, rather than being bothered by lockout screens.

### 4. Break "Infinite Scrolling"
Infinite scrolling (sometimes also referred as "doom scrolling") is a manipulative design technology that eliminates those brief moments where you might turn to another activity. DetoxDroid can try to detect if you have been lost in such behavior and offer you an exit strategy.

### 4. Opt-out > Opt-in
You are encouraged to deliberately to pause the app, allowing colors and notifications. If the pause is over, DetoxDroid automatically comes back into life. Let this become your new default rather than having to repeatedly decide for it.
### 5. Opt-out > Opt-in
You are encouraged to deliberately to pause DetoxDroid, allowing colors and notifications. If the pause is over, DetoxDroid automatically comes back into life. Let this become your new default rather than having to repeatedly decide for it.

## Installation
1. [Enable developer mode and USB debugging](https://www.youtube.com/watch?v=0usgePpr8_Y):
Expand Down
42 changes: 23 additions & 19 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 29
compileSdkVersion 31

defaultConfig {
applicationId "com.flx_apps.digitaldetox"
minSdkVersion 21
targetSdkVersion 29
versionCode 11000
versionName "1.1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
targetSdkVersion 31
versionCode 12000
versionName "1.2.0"

javaCompileOptions {
annotationProcessorOptions {
Expand All @@ -31,6 +29,7 @@ android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true // java 8 libs in lower api levels
}
kotlinOptions {
jvmTarget = '1.8'
Expand All @@ -41,24 +40,27 @@ android {
}

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' // java 8 libs in lower api levels

implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.fragment:fragment:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.0'
implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.navigation:navigation-fragment:2.3.5'
implementation 'androidx.navigation:navigation-ui:2.3.5'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'

// Android Annotations
annotationProcessor "org.androidannotations:androidannotations:4.7.0"
implementation "org.androidannotations:androidannotations-api:4.7.0"
kapt "org.androidannotations:androidannotations:4.7.0"
annotationProcessor "org.androidannotations:androidannotations:4.8.0"
implementation "org.androidannotations:androidannotations-api:4.8.0"
kapt "org.androidannotations:androidannotations:4.8.0"

// About Info Screen
implementation 'com.github.ditacristianionut:AppInfoBadge:1.3'
Expand All @@ -72,6 +74,8 @@ dependencies {
// Preferences
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.2'
implementation 'com.takisoft.preferencex:preferencex:1.1.0'
implementation 'com.takisoft.preferencex:preferencex-datetimepicker:1.1.0'

// implementation 'androidx.room:room-runtime:2.3.0-alpha03'
// kapt 'androidx.room:room-compiler:2.3.0-alpha03'
Expand Down

This file was deleted.

28 changes: 24 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
<!-- To (de-)activate zen mode ("do not disturb" mode) -->
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />

<!-- To show the user notifications / warning messages outside of the actual app -->
<!-- To show the user notifications / (doom scrolling–) warning messages outside of the actual app -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<!-- To self-uninstall DetoxDroid when it is in DeviceOwner mode -->
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand All @@ -29,7 +32,8 @@
<activity
android:name=".MainActivity_"
android:label="@string/app.name_"
android:theme="@style/AppTheme.NoActionBar">
android:theme="@style/AppTheme.NoActionBar"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand All @@ -41,7 +45,8 @@
android:name=".DetoxAccessibilityService_"
android:description="@string/app.accessibilityService.description"
android:label="@string/app.accessibilityService.name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
Expand All @@ -54,11 +59,26 @@
android:name=".QuickSettingsTileService"
android:icon="@drawable/ic_quick_settings_tile"
android:label="@string/app.quickSettingsTile"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="false">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>

<receiver
android:name="com.flx_apps.digitaldetox.DetoxDroidDeviceAdminReceiver"
android:label="Detox Droid Device Admin"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="false">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_config" />

<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>

</manifest>
5 changes: 2 additions & 3 deletions app/src/main/java/com/flx_apps/digitaldetox/AboutFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import android.os.Bundle
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.dci.dev.appinfobadge.AppInfoBadge
import com.dci.dev.appinfobadge.BaseInfoItem
import com.dci.dev.appinfobadge.InfoItemWithLink

class AboutFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val appInfoBadgeFragment = AppInfoBadge
.headerColor { ContextCompat.getColor(context!!, R.color.colorPrimaryDark) }
.headerColor { ContextCompat.getColor(requireContext(), R.color.colorPrimaryDark) }
.withAppIcon { true }
.withCustomItems { listOf(
InfoItemWithLink(
Expand Down Expand Up @@ -42,6 +41,6 @@ class AboutFragment : Fragment() {
.withLibraries { false }
.withLicenses { false }
.show()
fragmentManager!!.beginTransaction().replace(R.id.nav_host_fragment, appInfoBadgeFragment).commit()
parentFragmentManager.beginTransaction().replace(R.id.nav_host_fragment, appInfoBadgeFragment).commit()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.flx_apps.digitaldetox

import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Build
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
Expand Down Expand Up @@ -84,6 +85,9 @@ open class AppExceptionsListFragment : Fragment() {
pckg = it.packageName
isException = exceptions.contains(it.packageName)
isSystemApp = (it.flags and isSystemAppMask) !== 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
category = ApplicationInfo.getCategoryTitle(context, it.category)?.toString()
}
}
)
}
Expand All @@ -97,8 +101,10 @@ open class AppExceptionsListFragment : Fragment() {

itemAdapter = ItemAdapter()
itemAdapter.itemFilter.filterPredicate = { item: AppItem, constraint: CharSequence? ->
var showItem = RANDOM_STRING.equals(constraint) ||
item.name.toString().toLowerCase(Locale.getDefault())
var showItem = RANDOM_STRING == constraint ||
item.name.orEmpty().toLowerCase(Locale.getDefault())
.contains(constraint.toString().toLowerCase(Locale.getDefault())) ||
item.category.orEmpty().toLowerCase(Locale.getDefault())
.contains(constraint.toString().toLowerCase(Locale.getDefault()))
showItem = showItem && ((!item.isSystemApp && itemFilter.showUserApps) || (item.isSystemApp && itemFilter.showSystemApps))
showItem
Expand Down Expand Up @@ -154,6 +160,7 @@ open class AppExceptionsListFragment : Fragment() {
open class AppItem : AbstractItem<AppItem.ViewHolder>() {
var name: String? = null
var pckg: String? = null
var category: String? = null
var isException = false
var isSystemApp = false

Expand All @@ -170,23 +177,27 @@ open class AppExceptionsListFragment : Fragment() {
}

class ViewHolder(view: View) : FastAdapter.ViewHolder<AppItem>(view) {
val appTitle: TextView = view.findViewById(R.id.appTitle)
val appPackage: TextView = view.findViewById(R.id.appPackage)
val title: TextView = view.findViewById(R.id.appTitle)
val subtitle: TextView = view.findViewById(R.id.appPackage)
val btnToggleExceptionState: SwitchCompat = view.findViewById(R.id.btnToggleExceptionState)
val appIcon: ImageView = view.findViewById(R.id.appIcon)
val icon: ImageView = view.findViewById(R.id.appIcon)

override fun bindView(item: AppItem, payloads: List<Any>) {
appTitle.text = item.name
appPackage.text = item.pckg
appIcon.setImageDrawable(appIcon.context.packageManager.getApplicationIcon(item.pckg))
title.text = item.name
subtitle.text = item.category
if (subtitle.text.isNullOrEmpty()) {
subtitle.visibility = View.GONE
}
icon.setImageDrawable(icon.context.packageManager.getApplicationIcon(item.pckg!!))
btnToggleExceptionState.isChecked = item.isException
}

override fun unbindView(item: AppItem) {
appTitle.text = null
appPackage.text = null
title.text = null
subtitle.text = null
subtitle.visibility = View.VISIBLE
btnToggleExceptionState.isChecked = false
appIcon.setImageDrawable(null)
icon.setImageDrawable(null)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.flx_apps.digitaldetox

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton

/**
* Creation Date: 1/19/22
* @author felix
*/
open class CloseableBottomSheetDialogFragment(var contentFragment: Fragment) : BottomSheetDialogFragment() {
val viewId = View.generateViewId()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LinearLayout(requireContext()).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
orientation = LinearLayout.VERTICAL
id = viewId
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// init close button for the dialog
val closeButton = MaterialButton(view.context, null, R.attr.borderlessButtonStyle).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
text = getText(R.string.action_close)
setOnClickListener { dialog!!.dismiss() }
}

(dialog as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED
childFragmentManager
.beginTransaction()
.add(viewId, contentFragment)
.runOnCommit { (view as LinearLayout).addView(closeButton) }
.commit()
}
}
Loading

0 comments on commit 1443d9e

Please sign in to comment.