diff --git a/app/src/main/java/de/jrpie/android/launcher/Application.kt b/app/src/main/java/de/jrpie/android/launcher/Application.kt index 6e924c2..c856066 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Application.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Application.kt @@ -17,12 +17,14 @@ import androidx.preference.PreferenceManager import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo +import de.jrpie.android.launcher.apps.isPrivateSpaceLocked import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion import de.jrpie.android.launcher.preferences.resetPreferences class Application : android.app.Application() { val apps = MutableLiveData>() + val privateSpaceLocked = MutableLiveData() private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -144,6 +146,7 @@ class Application : android.app.Application() { } private fun loadApps() { + privateSpaceLocked.postValue(isPrivateSpaceLocked(this)) AsyncTask.execute { apps.postValue(getApps(packageManager, applicationContext)) } } } diff --git a/app/src/main/java/de/jrpie/android/launcher/Functions.kt b/app/src/main/java/de/jrpie/android/launcher/Functions.kt index 721caa2..7cc5c39 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -22,6 +22,8 @@ import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo +import de.jrpie.android.launcher.apps.getPrivateSpaceUser +import de.jrpie.android.launcher.apps.isPrivateSpaceSupported import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.tutorial.TutorialActivity @@ -48,14 +50,15 @@ fun isDefaultHomeScreen(context: Context): Boolean { } fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) { - if (checkDefault && isDefaultHomeScreen(context)) { + val isDefault = isDefaultHomeScreen(context) + if (checkDefault && isDefault) { // Launcher is already the default home app return } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && context is Activity - && checkDefault // using role manager only works when µLauncher is not already the default. + && !isDefault // using role manager only works when µLauncher is not already the default. ) { val roleManager = context.getSystemService(RoleManager::class.java) context.startActivityForResult( @@ -78,16 +81,6 @@ fun getUserFromId(userId: Int?, context: Context): UserHandle { return profiles.firstOrNull { it.hashCode() == userId } ?: profiles[0] } -fun getPrivateSpaceUser(context: Context): UserHandle? { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { - return null - } - val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager - val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps - return userManager.userProfiles.firstOrNull { u -> - launcherApps.getLauncherUserInfo(u)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE - } -} fun openInBrowser(url: String, context: Context) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) @@ -116,6 +109,8 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList= Build.VERSION_CODES.VANILLA_ICE_CREAM && + if (isPrivateSpaceSupported() && launcherApps.getLauncherUserInfo(user)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE ) { continue @@ -135,7 +130,7 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList openAppsList(context, true) }, + { context -> openAppsList(context, favorite = true) }, true ), + CHOOSE_FROM_PRIVATE_SPACE( + "choose_from_private_space", + R.string.list_other_list_private_space, + R.drawable.baseline_security_24, + { context -> + openAppsList(context, private = true) + }, + available = { _ -> + isPrivateSpaceSupported() + } + ), TOGGLE_PRIVATE_SPACE_LOCK( "toggle_private_space_lock", R.string.list_other_toggle_private_space_lock, R.drawable.baseline_security_24, ::togglePrivateSpaceLock, - available = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM } + available = { _ -> isPrivateSpaceSupported() } ), VOLUME_UP( "volume_up", @@ -107,7 +113,7 @@ enum class LauncherAction( LOCK_SCREEN( "lock_screen", R.string.list_other_lock_screen, - R.drawable.baseline_lock_24px, + R.drawable.baseline_lock_24, { c -> LauncherPreferences.actions().lockMethod().lockOrEnable(c) } ), TORCH( @@ -230,37 +236,6 @@ private fun expandNotificationsPanel(context: Context) { } } -private fun togglePrivateSpaceLock(context: Context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { - Toast.makeText( - context, - context.getString(R.string.alert_requires_android_v), - Toast.LENGTH_LONG - ).show() - return - } - val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager - val privateSpaceUser = getPrivateSpaceUser(context) - if (privateSpaceUser == null) { - Toast.makeText(context, context.getString(R.string.toast_private_space_not_available), Toast.LENGTH_LONG).show() - - if (!isDefaultHomeScreen(context)) { - Toast.makeText(context, context.getString(R.string.toast_private_space_default_home_screen), Toast.LENGTH_LONG).show() - return - } - - try { - context.startActivity(Intent(Settings.ACTION_PRIVACY_SETTINGS)) - } catch (_: ActivityNotFoundException) {} - return - } - if (userManager.isQuietModeEnabled(privateSpaceUser)) { - userManager.requestQuietModeEnabled(false, privateSpaceUser) - return - } - userManager.requestQuietModeEnabled(true, privateSpaceUser) - Toast.makeText(context, context.getString(R.string.toast_private_space_locked), Toast.LENGTH_LONG).show() -} private fun expandSettingsPanel(context: Context) { /* https://stackoverflow.com/a/31898506 */ @@ -283,7 +258,12 @@ private fun openSettings(context: Context) { context.startActivity(Intent(context, SettingsActivity::class.java)) } -fun openAppsList(context: Context, favorite: Boolean = false, hidden: Boolean = false) { +fun openAppsList( + context: Context, + favorite: Boolean = false, + hidden: Boolean = false, + private: Boolean = false +) { val intent = Intent(context, ListActivity::class.java) intent.putExtra("intention", ListActivity.ListActivityIntention.VIEW.toString()) intent.putExtra( @@ -302,6 +282,16 @@ fun openAppsList(context: Context, favorite: Boolean = false, hidden: Boolean = AppFilter.Companion.AppSetVisibility.HIDDEN } ) + intent.putExtra( + "privateSpaceVisibility", + if (private) { + AppFilter.Companion.AppSetVisibility.EXCLUSIVE + } else if (!hidden && LauncherPreferences.apps().hidePrivateSpaceApps()) { + AppFilter.Companion.AppSetVisibility.HIDDEN + } else { + AppFilter.Companion.AppSetVisibility.VISIBLE + } + ) context.startActivity(intent) } diff --git a/app/src/main/java/de/jrpie/android/launcher/apps/AppFilter.kt b/app/src/main/java/de/jrpie/android/launcher/apps/AppFilter.kt index f3640d2..ecc7eaa 100644 --- a/app/src/main/java/de/jrpie/android/launcher/apps/AppFilter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/apps/AppFilter.kt @@ -15,6 +15,7 @@ class AppFilter( var query: String, var favoritesVisibility: AppSetVisibility = AppSetVisibility.VISIBLE, var hiddenVisibility: AppSetVisibility = AppSetVisibility.HIDDEN, + var privateSpaceVisibility: AppSetVisibility = AppSetVisibility.VISIBLE ) { operator fun invoke(apps: List): List { @@ -23,10 +24,12 @@ class AppFilter( val hidden = LauncherPreferences.apps().hidden() ?: setOf() val favorites = LauncherPreferences.apps().favorites() ?: setOf() + val private = apps.filter { it.isPrivateSpaceApp }.map { it.app }.toSet() apps = apps.filter { info -> favoritesVisibility.predicate(favorites, info) && hiddenVisibility.predicate(hidden, info) + && privateSpaceVisibility.predicate(private, info) } if (LauncherPreferences.apps().hideBoundApps()) { diff --git a/app/src/main/java/de/jrpie/android/launcher/apps/DetailedAppInfo.kt b/app/src/main/java/de/jrpie/android/launcher/apps/DetailedAppInfo.kt index 519798d..1984d47 100644 --- a/app/src/main/java/de/jrpie/android/launcher/apps/DetailedAppInfo.kt +++ b/app/src/main/java/de/jrpie/android/launcher/apps/DetailedAppInfo.kt @@ -15,10 +15,11 @@ class DetailedAppInfo( val app: AppInfo, val label: CharSequence, val icon: Drawable, + val isPrivateSpaceApp: Boolean, val isSystemApp: Boolean = false, ) { - constructor(activityInfo: LauncherActivityInfo) : this( + constructor(activityInfo: LauncherActivityInfo, private: Boolean) : this( AppInfo( activityInfo.applicationInfo.packageName, activityInfo.name, @@ -26,6 +27,7 @@ class DetailedAppInfo( ), activityInfo.label, activityInfo.getBadgedIcon(0), + private, activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0 ) @@ -51,7 +53,9 @@ class DetailedAppInfo( companion object { fun fromAppInfo(appInfo: AppInfo, context: Context): DetailedAppInfo? { - return appInfo.getLauncherActivityInfo(context)?.let { DetailedAppInfo(it) } + return appInfo.getLauncherActivityInfo(context)?.let { + DetailedAppInfo(it, it.user == getPrivateSpaceUser(context)) + } } } } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/apps/PrivateSpace.kt b/app/src/main/java/de/jrpie/android/launcher/apps/PrivateSpace.kt new file mode 100644 index 0000000..9b37d60 --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/apps/PrivateSpace.kt @@ -0,0 +1,118 @@ +package de.jrpie.android.launcher.apps + +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.content.pm.LauncherApps +import android.os.Build +import android.os.UserHandle +import android.os.UserManager +import android.provider.Settings +import android.widget.Toast +import de.jrpie.android.launcher.R +import de.jrpie.android.launcher.isDefaultHomeScreen +import de.jrpie.android.launcher.setDefaultHomeScreen + + +/* + * Checks whether the device supports private space. + */ +fun isPrivateSpaceSupported(): Boolean { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM +} + +fun getPrivateSpaceUser(context: Context): UserHandle? { + if (!isPrivateSpaceSupported()) { + return null + } + val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager + val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + return userManager.userProfiles.firstOrNull { u -> + launcherApps.getLauncherUserInfo(u)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE + } +} + +/** + * Check whether the user has created a private space and whether µLauncher can access it. + */ +fun isPrivateSpaceSetUp( + context: Context, + showToast: Boolean = false, + launchSettings: Boolean = false +): Boolean { + if (!isPrivateSpaceSupported()) { + if (showToast) { + Toast.makeText( + context, + context.getString(R.string.alert_requires_android_v), + Toast.LENGTH_LONG + ).show() + } + return false + } + val privateSpaceUser = getPrivateSpaceUser(context) + if (privateSpaceUser != null) { + return true + } + if (!isDefaultHomeScreen(context)) { + if (showToast) { + Toast.makeText( + context, + context.getString(R.string.toast_private_space_default_home_screen), + Toast.LENGTH_LONG + ).show() + } + if (launchSettings) { + setDefaultHomeScreen(context) + } + } else { + if (showToast) { + Toast.makeText( + context, + context.getString(R.string.toast_private_space_not_available), + Toast.LENGTH_LONG + ).show() + } + if (launchSettings) { + try { + context.startActivity(Intent(Settings.ACTION_PRIVACY_SETTINGS)) + } catch (_: ActivityNotFoundException) { + } + } + } + return false +} + +fun isPrivateSpaceLocked(context: Context): Boolean { + if (!isPrivateSpaceSupported()) { + return false + } + val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager + val privateSpaceUser = getPrivateSpaceUser(context) ?: return false + return userManager.isQuietModeEnabled(privateSpaceUser) +} +fun lockPrivateSpace(context: Context, lock: Boolean) { + if (!isPrivateSpaceSupported()) { + return + } + val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager + val privateSpaceUser = getPrivateSpaceUser(context) ?: return + userManager.requestQuietModeEnabled(lock, privateSpaceUser) +} + +fun togglePrivateSpaceLock(context: Context) { + if (!isPrivateSpaceSetUp(context, showToast = true, launchSettings = true)) { + return + } + + val lock = isPrivateSpaceLocked(context) + lockPrivateSpace(context, !lock) + if (!lock) { + Toast.makeText( + context, + context.getString(R.string.toast_private_space_locked), + Toast.LENGTH_LONG + ).show() + } +} + diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java b/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java index 98496ce..c216911 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java @@ -30,6 +30,7 @@ import eu.jonahbauer.android.preference.annotations.Preferences; @Preference(name = "custom_names", type = HashMap.class, serializer = MapAppInfoStringPreferenceSerializer.class), @Preference(name = "hide_bound_apps", type = boolean.class, defaultValue = "false"), @Preference(name = "hide_paused_apps", type = boolean.class, defaultValue = "false"), + @Preference(name = "hide_private_space_apps", type = boolean.class, defaultValue = "false"), }), @PreferenceGroup(name = "list", prefix = "settings_list_", suffix = "_key", value = { @Preference(name = "layout", type = ListLayout.class, defaultValue = "DEFAULT") diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/list/ListActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/list/ListActivity.kt index 1fe5afb..902e561 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/list/ListActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/list/ListActivity.kt @@ -16,10 +16,14 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.google.android.material.tabs.TabLayout +import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.R import de.jrpie.android.launcher.REQUEST_UNINSTALL import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.apps.AppFilter +import de.jrpie.android.launcher.apps.isPrivateSpaceLocked +import de.jrpie.android.launcher.apps.isPrivateSpaceSetUp +import de.jrpie.android.launcher.apps.togglePrivateSpaceLock import de.jrpie.android.launcher.databinding.ListBinding import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.UIObject @@ -30,6 +34,8 @@ import de.jrpie.android.launcher.ui.list.other.ListFragmentOther // TODO: Better solution for this intercommunication functionality (used in list-fragments) var intention = ListActivity.ListActivityIntention.VIEW var favoritesVisibility: AppFilter.Companion.AppSetVisibility = AppFilter.Companion.AppSetVisibility.VISIBLE +var privateSpaceVisibility: AppFilter.Companion.AppSetVisibility = + AppFilter.Companion.AppSetVisibility.VISIBLE var hiddenVisibility: AppFilter.Companion.AppSetVisibility = AppFilter.Companion.AppSetVisibility.HIDDEN var forGesture: String? = null @@ -44,6 +50,29 @@ class ListActivity : AppCompatActivity(), UIObject { private lateinit var binding: ListBinding + private fun updateLockIcon(locked: Boolean) { + binding.listLock.setImageDrawable( + getDrawable( + if (locked) { + R.drawable.baseline_lock_24 + } else { + R.drawable.baseline_lock_open_24 + } + ) + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + binding.listLock.tooltipText = getString( + if (locked) { + R.string.tooltip_unlock_private_space + } else { + R.string.tooltip_lock_private_space + } + ) + } + } + + + enum class ListActivityIntention(val titleResource: Int) { VIEW(R.string.list_title_view), /* view list of apps */ PICK(R.string.list_title_pick) /* choose app or action to associate to a gesture */ @@ -70,8 +99,10 @@ class ListActivity : AppCompatActivity(), UIObject { favoritesVisibility = bundle.getSerializable("favoritesVisibility") as? AppFilter.Companion.AppSetVisibility ?: favoritesVisibility + privateSpaceVisibility = bundle.getSerializable("privateSpaceVisibility") + as? AppFilter.Companion.AppSetVisibility ?: privateSpaceVisibility hiddenVisibility = bundle.getSerializable("hiddenVisibility") - as? AppFilter.Companion.AppSetVisibility ?: favoritesVisibility + as? AppFilter.Companion.AppSetVisibility ?: hiddenVisibility if (intention != ListActivityIntention.VIEW) forGesture = bundle.getString("forGesture") @@ -86,6 +117,31 @@ class ListActivity : AppCompatActivity(), UIObject { LauncherAction.SETTINGS.launch(this@ListActivity) } + binding.listLock.visibility = + if (intention != ListActivityIntention.VIEW) { + View.GONE + } else if (!isPrivateSpaceSetUp(this)) { + View.GONE + } else if (LauncherPreferences.apps().hidePrivateSpaceApps()) { + if (privateSpaceVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { + View.VISIBLE + } else { + View.GONE + } + } else { + View.VISIBLE + } + + if (privateSpaceVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { + isPrivateSpaceSetUp(this, showToast = true, launchSettings = true) + if (isPrivateSpaceLocked(this)) { + togglePrivateSpaceLock(this) + } + } + updateLockIcon(isPrivateSpaceLocked(this)) + + val privateSpaceLocked = (this.applicationContext as Application).privateSpaceLocked + privateSpaceLocked.observe(this) { updateLockIcon(it) } // android:windowSoftInputMode="adjustResize" doesn't work in full screen. // workaround from https://stackoverflow.com/a/57623505 @@ -144,6 +200,8 @@ class ListActivity : AppCompatActivity(), UIObject { if (intention == ListActivityIntention.VIEW) { titleResource = if (hiddenVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { R.string.list_title_hidden + } else if (privateSpaceVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { + R.string.list_title_private_space } else if (favoritesVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { R.string.list_title_favorite } else { @@ -161,6 +219,12 @@ class ListActivity : AppCompatActivity(), UIObject { override fun setOnClicks() { binding.listClose.setOnClickListener { finish() } + binding.listLock.setOnClickListener { + togglePrivateSpaceLock(this) + if (privateSpaceVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { + finish() + } + } } override fun adjustLayout() { diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt index c52f951..3a6e403 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt @@ -19,6 +19,7 @@ import de.jrpie.android.launcher.ui.list.favoritesVisibility import de.jrpie.android.launcher.ui.list.forGesture import de.jrpie.android.launcher.ui.list.hiddenVisibility import de.jrpie.android.launcher.ui.list.intention +import de.jrpie.android.launcher.ui.list.privateSpaceVisibility import de.jrpie.android.launcher.ui.openSoftKeyboard @@ -72,6 +73,7 @@ class ListFragmentApps : Fragment(), UIObject { requireContext(), "", favoritesVisibility = favoritesVisibility, + privateSpaceVisibility = privateSpaceVisibility, hiddenVisibility = hiddenVisibility ), layout = LauncherPreferences.list().layout() diff --git a/app/src/main/res/drawable/baseline_lock_24px.xml b/app/src/main/res/drawable/baseline_lock_24.xml similarity index 100% rename from app/src/main/res/drawable/baseline_lock_24px.xml rename to app/src/main/res/drawable/baseline_lock_24.xml diff --git a/app/src/main/res/drawable/baseline_lock_open_24.xml b/app/src/main/res/drawable/baseline_lock_open_24.xml new file mode 100644 index 0000000..f0f6ea3 --- /dev/null +++ b/app/src/main/res/drawable/baseline_lock_open_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/list.xml b/app/src/main/res/layout/list.xml index 062cab4..4fd6962 100644 --- a/app/src/main/res/layout/list.xml +++ b/app/src/main/res/layout/list.xml @@ -53,8 +53,8 @@ android:text="@string/list_title_pick" android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" android:textSize="30sp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/list_lock" + app:layout_constraintStart_toEndOf="@id/list_settings" app:layout_constraintTop_toTopOf="parent" /> + apps.custom_names apps.hide_bound_apps apps.hide_paused_apps + apps.hide_private_space_apps list.layout general.select_launcher diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9c07ed6..97d7384 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -150,6 +150,7 @@ Hidden apps Don\'t show apps that are bound to a gesture in the app list Hide paused apps + Hide private space from app list Layout of app list Default @@ -197,6 +198,7 @@ All Apps Favorite Apps Hidden Apps + Private Space Choose App Apps @@ -219,6 +221,7 @@ µLauncher Settings All Applications Favorite Applications + Private Space Toggle Private Space Lock Music: Louder Music: Quieter @@ -273,6 +276,8 @@ Private space unlocked Private space is not available µLauncher needs to be the default home screen to access private space. + Lock private space + Unlock private space Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead. µLauncher - lock screen diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 314f85f..406f81a 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -151,6 +151,11 @@ android:title="@string/settings_apps_hide_paused_apps" android:defaultValue="false" /> + +