implement #98 - add option to show private space in different list

This commit is contained in:
Josia Pietsch 2025-02-09 18:49:41 +01:00
parent 944eb89fef
commit d69e3caf71
Signed by: jrpie
GPG key ID: E70B571D66986A2D
15 changed files with 279 additions and 62 deletions

View file

@ -17,12 +17,14 @@ import androidx.preference.PreferenceManager
import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.actions.TorchManager
import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo 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.LauncherPreferences
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
import de.jrpie.android.launcher.preferences.resetPreferences import de.jrpie.android.launcher.preferences.resetPreferences
class Application : android.app.Application() { class Application : android.app.Application() {
val apps = MutableLiveData<List<DetailedAppInfo>>() val apps = MutableLiveData<List<DetailedAppInfo>>()
val privateSpaceLocked = MutableLiveData<Boolean>()
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() { private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
@ -144,6 +146,7 @@ class Application : android.app.Application() {
} }
private fun loadApps() { private fun loadApps() {
privateSpaceLocked.postValue(isPrivateSpaceLocked(this))
AsyncTask.execute { apps.postValue(getApps(packageManager, applicationContext)) } AsyncTask.execute { apps.postValue(getApps(packageManager, applicationContext)) }
} }
} }

View file

@ -22,6 +22,8 @@ import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo 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.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
@ -48,14 +50,15 @@ fun isDefaultHomeScreen(context: Context): Boolean {
} }
fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) { 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 // Launcher is already the default home app
return return
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& context is Activity && 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) val roleManager = context.getSystemService(RoleManager::class.java)
context.startActivityForResult( context.startActivityForResult(
@ -78,16 +81,6 @@ fun getUserFromId(userId: Int?, context: Context): UserHandle {
return profiles.firstOrNull { it.hashCode() == userId } ?: profiles[0] 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) { fun openInBrowser(url: String, context: Context) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
@ -116,6 +109,8 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
val privateSpaceUser = getPrivateSpaceUser(context)
// TODO: shortcuts - launcherApps.getShortcuts() // TODO: shortcuts - launcherApps.getShortcuts()
val users = userManager.userProfiles val users = userManager.userProfiles
for (user in users) { for (user in users) {
@ -127,7 +122,7 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
continue continue
} }
// hide apps from private space // hide apps from private space
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && if (isPrivateSpaceSupported() &&
launcherApps.getLauncherUserInfo(user)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE launcherApps.getLauncherUserInfo(user)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE
) { ) {
continue continue
@ -135,7 +130,7 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
} }
} }
launcherApps.getActivityList(null, user).forEach { launcherApps.getActivityList(null, user).forEach {
loadList.add(DetailedAppInfo(it)) loadList.add(DetailedAppInfo(it, it.user == privateSpaceUser))
} }
} }
@ -150,7 +145,8 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
val detailedAppInfo = DetailedAppInfo( val detailedAppInfo = DetailedAppInfo(
app, app,
ri.loadLabel(packageManager), ri.loadLabel(packageManager),
ri.activityInfo.loadIcon(packageManager) ri.activityInfo.loadIcon(packageManager),
false
) )
loadList.add(detailedAppInfo) loadList.add(detailedAppInfo)
} }

View file

@ -1,24 +1,19 @@
package de.jrpie.android.launcher.actions package de.jrpie.android.launcher.actions
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.LauncherApps
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.AudioManager import android.media.AudioManager
import android.os.Build import android.os.Build
import android.os.SystemClock import android.os.SystemClock
import android.os.UserManager
import android.provider.Settings
import android.view.KeyEvent import android.view.KeyEvent
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.AppCompatDrawableManager
import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.getPrivateSpaceUser import de.jrpie.android.launcher.apps.isPrivateSpaceSupported
import de.jrpie.android.launcher.isDefaultHomeScreen import de.jrpie.android.launcher.apps.togglePrivateSpaceLock
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.list.ListActivity import de.jrpie.android.launcher.ui.list.ListActivity
import de.jrpie.android.launcher.ui.settings.SettingsActivity import de.jrpie.android.launcher.ui.settings.SettingsActivity
@ -62,15 +57,26 @@ enum class LauncherAction(
"choose_from_favorites", "choose_from_favorites",
R.string.list_other_list_favorites, R.string.list_other_list_favorites,
R.drawable.baseline_favorite_24, R.drawable.baseline_favorite_24,
{ context -> openAppsList(context, true) }, { context -> openAppsList(context, favorite = true) },
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(
"toggle_private_space_lock", "toggle_private_space_lock",
R.string.list_other_toggle_private_space_lock, R.string.list_other_toggle_private_space_lock,
R.drawable.baseline_security_24, R.drawable.baseline_security_24,
::togglePrivateSpaceLock, ::togglePrivateSpaceLock,
available = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM } available = { _ -> isPrivateSpaceSupported() }
), ),
VOLUME_UP( VOLUME_UP(
"volume_up", "volume_up",
@ -107,7 +113,7 @@ enum class LauncherAction(
LOCK_SCREEN( LOCK_SCREEN(
"lock_screen", "lock_screen",
R.string.list_other_lock_screen, R.string.list_other_lock_screen,
R.drawable.baseline_lock_24px, R.drawable.baseline_lock_24,
{ c -> LauncherPreferences.actions().lockMethod().lockOrEnable(c) } { c -> LauncherPreferences.actions().lockMethod().lockOrEnable(c) }
), ),
TORCH( 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) { private fun expandSettingsPanel(context: Context) {
/* https://stackoverflow.com/a/31898506 */ /* https://stackoverflow.com/a/31898506 */
@ -283,7 +258,12 @@ private fun openSettings(context: Context) {
context.startActivity(Intent(context, SettingsActivity::class.java)) 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) val intent = Intent(context, ListActivity::class.java)
intent.putExtra("intention", ListActivity.ListActivityIntention.VIEW.toString()) intent.putExtra("intention", ListActivity.ListActivityIntention.VIEW.toString())
intent.putExtra( intent.putExtra(
@ -302,6 +282,16 @@ fun openAppsList(context: Context, favorite: Boolean = false, hidden: Boolean =
AppFilter.Companion.AppSetVisibility.HIDDEN 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) context.startActivity(intent)
} }

View file

@ -15,6 +15,7 @@ class AppFilter(
var query: String, var query: String,
var favoritesVisibility: AppSetVisibility = AppSetVisibility.VISIBLE, var favoritesVisibility: AppSetVisibility = AppSetVisibility.VISIBLE,
var hiddenVisibility: AppSetVisibility = AppSetVisibility.HIDDEN, var hiddenVisibility: AppSetVisibility = AppSetVisibility.HIDDEN,
var privateSpaceVisibility: AppSetVisibility = AppSetVisibility.VISIBLE
) { ) {
operator fun invoke(apps: List<DetailedAppInfo>): List<DetailedAppInfo> { operator fun invoke(apps: List<DetailedAppInfo>): List<DetailedAppInfo> {
@ -23,10 +24,12 @@ class AppFilter(
val hidden = LauncherPreferences.apps().hidden() ?: setOf() val hidden = LauncherPreferences.apps().hidden() ?: setOf()
val favorites = LauncherPreferences.apps().favorites() ?: setOf() val favorites = LauncherPreferences.apps().favorites() ?: setOf()
val private = apps.filter { it.isPrivateSpaceApp }.map { it.app }.toSet()
apps = apps.filter { info -> apps = apps.filter { info ->
favoritesVisibility.predicate(favorites, info) favoritesVisibility.predicate(favorites, info)
&& hiddenVisibility.predicate(hidden, info) && hiddenVisibility.predicate(hidden, info)
&& privateSpaceVisibility.predicate(private, info)
} }
if (LauncherPreferences.apps().hideBoundApps()) { if (LauncherPreferences.apps().hideBoundApps()) {

View file

@ -15,10 +15,11 @@ class DetailedAppInfo(
val app: AppInfo, val app: AppInfo,
val label: CharSequence, val label: CharSequence,
val icon: Drawable, val icon: Drawable,
val isPrivateSpaceApp: Boolean,
val isSystemApp: Boolean = false, val isSystemApp: Boolean = false,
) { ) {
constructor(activityInfo: LauncherActivityInfo) : this( constructor(activityInfo: LauncherActivityInfo, private: Boolean) : this(
AppInfo( AppInfo(
activityInfo.applicationInfo.packageName, activityInfo.applicationInfo.packageName,
activityInfo.name, activityInfo.name,
@ -26,6 +27,7 @@ class DetailedAppInfo(
), ),
activityInfo.label, activityInfo.label,
activityInfo.getBadgedIcon(0), activityInfo.getBadgedIcon(0),
private,
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0 activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0
) )
@ -51,7 +53,9 @@ class DetailedAppInfo(
companion object { companion object {
fun fromAppInfo(appInfo: AppInfo, context: Context): DetailedAppInfo? { 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))
}
} }
} }
} }

View file

@ -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()
}
}

View file

@ -30,6 +30,7 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
@Preference(name = "custom_names", type = HashMap.class, serializer = MapAppInfoStringPreferenceSerializer.class), @Preference(name = "custom_names", type = HashMap.class, serializer = MapAppInfoStringPreferenceSerializer.class),
@Preference(name = "hide_bound_apps", type = boolean.class, defaultValue = "false"), @Preference(name = "hide_bound_apps", type = boolean.class, defaultValue = "false"),
@Preference(name = "hide_paused_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 = { @PreferenceGroup(name = "list", prefix = "settings_list_", suffix = "_key", value = {
@Preference(name = "layout", type = ListLayout.class, defaultValue = "DEFAULT") @Preference(name = "layout", type = ListLayout.class, defaultValue = "DEFAULT")

View file

@ -16,10 +16,14 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_UNINSTALL import de.jrpie.android.launcher.REQUEST_UNINSTALL
import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.apps.AppFilter 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.databinding.ListBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.UIObject 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) // TODO: Better solution for this intercommunication functionality (used in list-fragments)
var intention = ListActivity.ListActivityIntention.VIEW var intention = ListActivity.ListActivityIntention.VIEW
var favoritesVisibility: AppFilter.Companion.AppSetVisibility = AppFilter.Companion.AppSetVisibility.VISIBLE 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 hiddenVisibility: AppFilter.Companion.AppSetVisibility = AppFilter.Companion.AppSetVisibility.HIDDEN
var forGesture: String? = null var forGesture: String? = null
@ -44,6 +50,29 @@ class ListActivity : AppCompatActivity(), UIObject {
private lateinit var binding: ListBinding 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) { enum class ListActivityIntention(val titleResource: Int) {
VIEW(R.string.list_title_view), /* view list of apps */ 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 */ 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") favoritesVisibility = bundle.getSerializable("favoritesVisibility")
as? AppFilter.Companion.AppSetVisibility ?: favoritesVisibility as? AppFilter.Companion.AppSetVisibility ?: favoritesVisibility
privateSpaceVisibility = bundle.getSerializable("privateSpaceVisibility")
as? AppFilter.Companion.AppSetVisibility ?: privateSpaceVisibility
hiddenVisibility = bundle.getSerializable("hiddenVisibility") hiddenVisibility = bundle.getSerializable("hiddenVisibility")
as? AppFilter.Companion.AppSetVisibility ?: favoritesVisibility as? AppFilter.Companion.AppSetVisibility ?: hiddenVisibility
if (intention != ListActivityIntention.VIEW) if (intention != ListActivityIntention.VIEW)
forGesture = bundle.getString("forGesture") forGesture = bundle.getString("forGesture")
@ -86,6 +117,31 @@ class ListActivity : AppCompatActivity(), UIObject {
LauncherAction.SETTINGS.launch(this@ListActivity) 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. // android:windowSoftInputMode="adjustResize" doesn't work in full screen.
// workaround from https://stackoverflow.com/a/57623505 // workaround from https://stackoverflow.com/a/57623505
@ -144,6 +200,8 @@ class ListActivity : AppCompatActivity(), UIObject {
if (intention == ListActivityIntention.VIEW) { if (intention == ListActivityIntention.VIEW) {
titleResource = if (hiddenVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) { titleResource = if (hiddenVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) {
R.string.list_title_hidden 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) { } else if (favoritesVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) {
R.string.list_title_favorite R.string.list_title_favorite
} else { } else {
@ -161,6 +219,12 @@ class ListActivity : AppCompatActivity(), UIObject {
override fun setOnClicks() { override fun setOnClicks() {
binding.listClose.setOnClickListener { finish() } binding.listClose.setOnClickListener { finish() }
binding.listLock.setOnClickListener {
togglePrivateSpaceLock(this)
if (privateSpaceVisibility == AppFilter.Companion.AppSetVisibility.EXCLUSIVE) {
finish()
}
}
} }
override fun adjustLayout() { override fun adjustLayout() {

View file

@ -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.forGesture
import de.jrpie.android.launcher.ui.list.hiddenVisibility import de.jrpie.android.launcher.ui.list.hiddenVisibility
import de.jrpie.android.launcher.ui.list.intention import de.jrpie.android.launcher.ui.list.intention
import de.jrpie.android.launcher.ui.list.privateSpaceVisibility
import de.jrpie.android.launcher.ui.openSoftKeyboard import de.jrpie.android.launcher.ui.openSoftKeyboard
@ -72,6 +73,7 @@ class ListFragmentApps : Fragment(), UIObject {
requireContext(), requireContext(),
"", "",
favoritesVisibility = favoritesVisibility, favoritesVisibility = favoritesVisibility,
privateSpaceVisibility = privateSpaceVisibility,
hiddenVisibility = hiddenVisibility hiddenVisibility = hiddenVisibility
), ),
layout = LauncherPreferences.list().layout() layout = LauncherPreferences.list().layout()

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z" />
</vector>

View file

@ -53,8 +53,8 @@
android:text="@string/list_title_pick" android:text="@string/list_title_pick"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textSize="30sp" android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toStartOf="@id/list_lock"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/list_settings"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
@ -72,6 +72,21 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
custom:type="solid" /> custom:type="solid" />
<ImageView
android:id="@+id/list_lock"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:includeFontPadding="true"
android:paddingLeft="0sp"
android:paddingRight="0sp"
android:src="@drawable/baseline_lock_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/list_close"
app:layout_constraintTop_toTopOf="parent"
custom:type="solid" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout

View file

@ -14,6 +14,7 @@
<string name="settings_apps_custom_names_key" translatable="false">apps.custom_names</string> <string name="settings_apps_custom_names_key" translatable="false">apps.custom_names</string>
<string name="settings_apps_hide_bound_apps_key" translatable="false">apps.hide_bound_apps</string> <string name="settings_apps_hide_bound_apps_key" translatable="false">apps.hide_bound_apps</string>
<string name="settings_apps_hide_paused_apps_key" translatable="false">apps.hide_paused_apps</string> <string name="settings_apps_hide_paused_apps_key" translatable="false">apps.hide_paused_apps</string>
<string name="settings_apps_hide_private_space_apps_key" translatable="false">apps.hide_private_space_apps</string>
<string name="settings_list_layout_key" translatable="false">list.layout</string> <string name="settings_list_layout_key" translatable="false">list.layout</string>
<string name="settings_general_choose_home_screen_key" translatable="false">general.select_launcher</string> <string name="settings_general_choose_home_screen_key" translatable="false">general.select_launcher</string>

View file

@ -150,6 +150,7 @@
<string name="settings_apps_hidden">Hidden apps</string> <string name="settings_apps_hidden">Hidden apps</string>
<string name="settings_apps_hide_bound_apps">Don\'t show apps that are bound to a gesture in the app list</string> <string name="settings_apps_hide_bound_apps">Don\'t show apps that are bound to a gesture in the app list</string>
<string name="settings_apps_hide_paused_apps">Hide paused apps</string> <string name="settings_apps_hide_paused_apps">Hide paused apps</string>
<string name="settings_apps_hide_private_space_apps">Hide private space from app list</string>
<string name="settings_list_layout">Layout of app list</string> <string name="settings_list_layout">Layout of app list</string>
<string name="settings_list_layout_item_default">Default</string> <string name="settings_list_layout_item_default">Default</string>
@ -197,6 +198,7 @@
<string name="list_title_view">All Apps</string> <string name="list_title_view">All Apps</string>
<string name="list_title_favorite">Favorite Apps</string> <string name="list_title_favorite">Favorite Apps</string>
<string name="list_title_hidden">Hidden Apps</string> <string name="list_title_hidden">Hidden Apps</string>
<string name="list_title_private_space">Private Space</string>
<string name="list_title_pick">Choose App</string> <string name="list_title_pick">Choose App</string>
<string name="list_tab_app">Apps</string> <string name="list_tab_app">Apps</string>
@ -219,6 +221,7 @@
<string name="list_other_settings">µLauncher Settings</string> <string name="list_other_settings">µLauncher Settings</string>
<string name="list_other_list">All Applications</string> <string name="list_other_list">All Applications</string>
<string name="list_other_list_favorites">Favorite Applications</string> <string name="list_other_list_favorites">Favorite Applications</string>
<string name="list_other_list_private_space">Private Space</string>
<string name="list_other_toggle_private_space_lock">Toggle Private Space Lock</string> <string name="list_other_toggle_private_space_lock">Toggle Private Space Lock</string>
<string name="list_other_volume_up">Music: Louder</string> <string name="list_other_volume_up">Music: Louder</string>
<string name="list_other_volume_down">Music: Quieter</string> <string name="list_other_volume_down">Music: Quieter</string>
@ -273,6 +276,8 @@
<string name="toast_private_space_unlocked">Private space unlocked</string> <string name="toast_private_space_unlocked">Private space unlocked</string>
<string name="toast_private_space_not_available">Private space is not available</string> <string name="toast_private_space_not_available">Private space is not available</string>
<string name="toast_private_space_default_home_screen">µLauncher needs to be the default home screen to access private space.</string> <string name="toast_private_space_default_home_screen">µLauncher needs to be the default home screen to access private space.</string>
<string name="tooltip_lock_private_space">Lock private space</string>
<string name="tooltip_unlock_private_space">Unlock private space</string>
<string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string> <string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string>
<string name="accessibility_service_name">µLauncher - lock screen</string> <string name="accessibility_service_name">µLauncher - lock screen</string>
<string name="accessibility_service_description"> <string name="accessibility_service_description">

View file

@ -151,6 +151,11 @@
android:title="@string/settings_apps_hide_paused_apps" android:title="@string/settings_apps_hide_paused_apps"
android:defaultValue="false" /> android:defaultValue="false" />
<SwitchPreference
android:key="@string/settings_apps_hide_private_space_apps_key"
android:title="@string/settings_apps_hide_private_space_apps"
android:defaultValue="false" />
<DropDownPreference <DropDownPreference
android:key="@string/settings_list_layout_key" android:key="@string/settings_list_layout_key"
android:title="@string/settings_list_layout" android:title="@string/settings_list_layout"