mirror of
https://github.com/jrpie/Launcher.git
synced 2025-02-22 14:01:28 +01:00
basic support for private space (#98)
* add an action to toggle private space lock * hide apps from private space if private space is locked
This commit is contained in:
parent
679c90130d
commit
785e024ddb
12 changed files with 159 additions and 28 deletions
|
@ -1,5 +1,9 @@
|
|||
package de.jrpie.android.launcher
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.ShortcutInfo
|
||||
|
@ -7,6 +11,7 @@ import android.os.AsyncTask
|
|||
import android.os.Build
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.UserHandle
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.preference.PreferenceManager
|
||||
import de.jrpie.android.launcher.actions.TorchManager
|
||||
|
@ -19,6 +24,14 @@ import de.jrpie.android.launcher.preferences.resetPreferences
|
|||
class Application : android.app.Application() {
|
||||
val apps = MutableLiveData<List<DetailedAppInfo>>()
|
||||
|
||||
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
// TODO: only update specific apps
|
||||
// use Intent.EXTRA_USER
|
||||
loadApps()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: only update specific apps
|
||||
private val launcherAppsCallback = object : LauncherApps.Callback() {
|
||||
override fun onPackageRemoved(p0: String?, p1: UserHandle?) {
|
||||
|
@ -107,6 +120,21 @@ class Application : android.app.Application() {
|
|||
val launcherApps = getSystemService(LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
launcherApps.registerCallback(launcherAppsCallback)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.N) {
|
||||
val filter = IntentFilter().also {
|
||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
it.addAction(Intent.ACTION_PROFILE_AVAILABLE)
|
||||
it.addAction(Intent.ACTION_PROFILE_UNAVAILABLE)
|
||||
} else {
|
||||
it.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
|
||||
it.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
|
||||
}
|
||||
}
|
||||
ContextCompat.registerReceiver(this, profileAvailabilityBroadcastReceiver, filter,
|
||||
ContextCompat.RECEIVER_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
loadApps()
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ 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.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
||||
|
||||
|
||||
|
@ -30,31 +31,36 @@ const val REQUEST_SET_DEFAULT_HOME = 42
|
|||
|
||||
const val LOG_TAG = "Launcher"
|
||||
|
||||
fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
|
||||
|
||||
if (checkDefault
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||
&& context is Activity
|
||||
) {
|
||||
fun isDefaultHomeScreen(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val roleManager = context.getSystemService(RoleManager::class.java)
|
||||
if (!roleManager.isRoleHeld(RoleManager.ROLE_HOME)) {
|
||||
context.startActivityForResult(
|
||||
roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME),
|
||||
REQUEST_SET_DEFAULT_HOME
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (checkDefault) {
|
||||
return roleManager.isRoleHeld(RoleManager.ROLE_HOME)
|
||||
} else {
|
||||
val testIntent = Intent(Intent.ACTION_MAIN)
|
||||
testIntent.addCategory(Intent.CATEGORY_HOME)
|
||||
val defaultHome = testIntent.resolveActivity(context.packageManager)?.packageName
|
||||
if (defaultHome == context.packageName) {
|
||||
// Launcher is already the default home app
|
||||
return
|
||||
}
|
||||
return defaultHome == context.packageName
|
||||
}
|
||||
}
|
||||
|
||||
fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
|
||||
if (checkDefault && isDefaultHomeScreen(context)) {
|
||||
// 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.
|
||||
) {
|
||||
val roleManager = context.getSystemService(RoleManager::class.java)
|
||||
context.startActivityForResult(
|
||||
roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME),
|
||||
REQUEST_SET_DEFAULT_HOME
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val intent = Intent(Settings.ACTION_HOME_SETTINGS)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
@ -94,6 +100,21 @@ fun getApps(packageManager: PackageManager, context: Context): MutableList<Detai
|
|||
// TODO: shortcuts - launcherApps.getShortcuts()
|
||||
val users = userManager.userProfiles
|
||||
for (user in users) {
|
||||
// don't load apps from a user profile that has quiet mode enabled
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (userManager.isQuietModeEnabled(user)) {
|
||||
// hide paused apps
|
||||
if (LauncherPreferences.apps().hidePausedApps()) {
|
||||
continue
|
||||
}
|
||||
// hide apps from private space
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM &&
|
||||
launcherApps.getLauncherUserInfo(user)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE
|
||||
) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
launcherApps.getActivityList(null, user).forEach {
|
||||
loadList.add(DetailedAppInfo(it))
|
||||
}
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.LauncherApps
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import android.os.UserManager
|
||||
import android.provider.Settings
|
||||
import android.view.KeyEvent
|
||||
import android.widget.Toast
|
||||
import de.jrpie.android.launcher.Application
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.apps.AppFilter
|
||||
import de.jrpie.android.launcher.isDefaultHomeScreen
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||
import de.jrpie.android.launcher.ui.settings.SettingsActivity
|
||||
|
@ -33,7 +38,8 @@ enum class LauncherAction(
|
|||
val id: String,
|
||||
val label: Int,
|
||||
val icon: Int,
|
||||
val launch: (Context) -> Unit
|
||||
val launch: (Context) -> Unit,
|
||||
val available: (Context) -> Boolean = { true }
|
||||
) : Action {
|
||||
SETTINGS(
|
||||
"settings",
|
||||
|
@ -53,6 +59,13 @@ enum class LauncherAction(
|
|||
R.drawable.baseline_favorite_24,
|
||||
{ context -> openAppsList(context, true) }
|
||||
),
|
||||
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 }
|
||||
),
|
||||
VOLUME_UP(
|
||||
"volume_up",
|
||||
R.string.list_other_volume_up,
|
||||
|
@ -207,6 +220,46 @@ 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 launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val privateSpaceUser = userManager.userProfiles.firstOrNull { u ->
|
||||
launcherApps.getLauncherUserInfo(u)?.userType == UserManager.USER_TYPE_PROFILE_PRIVATE
|
||||
}
|
||||
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)
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.toast_private_space_unlocked),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
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 */
|
||||
try {
|
||||
|
@ -260,6 +313,7 @@ private class LauncherActionSerializer : KSerializer<LauncherAction> {
|
|||
) {
|
||||
element("value", String.serializer().descriptor)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): LauncherAction {
|
||||
val s = decoder.decodeStructure(descriptor) {
|
||||
decodeElementIndex(descriptor)
|
||||
|
|
|
@ -5,8 +5,8 @@ import java.util.Set;
|
|||
|
||||
import de.jrpie.android.launcher.R;
|
||||
import de.jrpie.android.launcher.actions.lock.LockMethod;
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetAppInfoPreferenceSerializer;
|
||||
import de.jrpie.android.launcher.preferences.serialization.MapAppInfoStringPreferenceSerializer;
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetAppInfoPreferenceSerializer;
|
||||
import de.jrpie.android.launcher.preferences.theme.Background;
|
||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme;
|
||||
import de.jrpie.android.launcher.preferences.theme.Font;
|
||||
|
@ -29,6 +29,7 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
|
|||
@Preference(name = "hidden", type = Set.class, serializer = SetAppInfoPreferenceSerializer.class),
|
||||
@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"),
|
||||
}),
|
||||
@PreferenceGroup(name = "list", prefix = "settings_list_", suffix = "_key", value = {
|
||||
@Preference(name = "layout", type = ListLayout.class, defaultValue = "DEFAULT")
|
||||
|
|
|
@ -2,8 +2,8 @@ package de.jrpie.android.launcher.preferences.theme
|
|||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import de.jrpie.android.launcher.R
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import de.jrpie.android.launcher.R
|
||||
|
||||
@Suppress("unused")
|
||||
enum class ColorTheme(
|
||||
|
|
|
@ -3,7 +3,6 @@ package de.jrpie.android.launcher.ui
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
|
@ -20,10 +19,7 @@ import de.jrpie.android.launcher.actions.Action
|
|||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
import de.jrpie.android.launcher.databinding.HomeBinding
|
||||
import de.jrpie.android.launcher.openTutorial
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
|
||||
import de.jrpie.android.launcher.preferences.resetPreferences
|
||||
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
|
|
@ -23,7 +23,8 @@ import de.jrpie.android.launcher.ui.list.forGesture
|
|||
class OtherRecyclerAdapter(val activity: Activity) :
|
||||
RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() {
|
||||
|
||||
private val othersList: Array<LauncherAction> = LauncherAction.values()
|
||||
private val othersList: Array<LauncherAction> =
|
||||
LauncherAction.entries.filter { it.isAvailable(activity) }.toTypedArray()
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
|
||||
View.OnClickListener {
|
||||
|
|
|
@ -40,6 +40,11 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() {
|
|||
)
|
||||
val lightTheme = LauncherPreferences.theme().colorTheme() == ColorTheme.LIGHT
|
||||
background?.isVisible = !lightTheme
|
||||
|
||||
val hidePausedApps = findPreference<androidx.preference.Preference>(
|
||||
LauncherPreferences.apps().keys().hidePausedApps()
|
||||
)
|
||||
hidePausedApps?.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
12
app/src/main/res/drawable/baseline_security_24.xml
Normal file
12
app/src/main/res/drawable/baseline_security_24.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp">
|
||||
|
||||
<path
|
||||
android:fillColor="?android:textColor"
|
||||
android:pathData="M12,1L3,5v6c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12L21,5l-9,-4zM12,11.99h7c-0.53,4.12 -3.28,7.79 -7,8.94L12,12L5,12L5,6.3l7,-3.11v8.8z" />
|
||||
|
||||
</vector>
|
|
@ -13,6 +13,7 @@
|
|||
<string name="settings_apps_hidden_key" translatable="false">apps.hidden</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_paused_apps_key" translatable="false">apps.hide_paused_apps</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>
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@
|
|||
<string name="settings_launcher_section_apps">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_paused_apps">Hide paused apps</string>
|
||||
<string name="settings_list_layout">Layout of app list</string>
|
||||
|
||||
<string name="settings_list_layout_item_default">Default</string>
|
||||
|
@ -207,6 +208,7 @@
|
|||
<string name="list_other_settings">µLauncher Settings</string>
|
||||
<string name="list_other_list">All Applications</string>
|
||||
<string name="list_other_list_favorites">Favorite Applications</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_down">Music: Quieter</string>
|
||||
<string name="list_other_track_next">Music: Next</string>
|
||||
|
@ -245,6 +247,7 @@
|
|||
<string name="ic_menu_alt">More options</string>
|
||||
<string name="alert_cant_expand_status_bar_panel">Error: Can\'t expand status bar. This action is using functionality that is not part of the published Android API. Unfortunately, it does not seem to work on your device.</string>
|
||||
<string name="alert_requires_android_m">This functionality requires Android 6.0 or later.</string>
|
||||
<string name="alert_requires_android_v">This functionality requires Android 15.0 or later.</string>
|
||||
<string name="snackbar_app_hidden">App hidden. You can make it visible again in settings.</string>
|
||||
<string name="undo">Undo</string>
|
||||
<string name="list_other_expand_settings_panel">Quick Settings</string>
|
||||
|
@ -255,6 +258,10 @@
|
|||
<string name="alert_torch_access_exception">Error: Can\'t access torch.</string>
|
||||
<string name="alert_lock_screen_failed">Error: Failed to lock screen. (If you just upgraded the app, try to disable and re-enable the accessibility service in phone settings)</string>
|
||||
<string name="toast_accessibility_service_not_enabled">μLauncher\'s accessibility service is not enabled. Please enable it in settings</string>
|
||||
<string name="toast_private_space_locked">Private space locked</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_default_home_screen">µLauncher needs to be the default home screen to access 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="accessibility_service_name">µLauncher - lock screen</string>
|
||||
<string name="accessibility_service_description">
|
||||
|
|
|
@ -145,6 +145,11 @@
|
|||
android:title="@string/settings_apps_hide_bound_apps"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="@string/settings_apps_hide_paused_apps_key"
|
||||
android:title="@string/settings_apps_hide_paused_apps"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<DropDownPreference
|
||||
android:key="@string/settings_list_layout_key"
|
||||
android:title="@string/settings_list_layout"
|
||||
|
|
Loading…
Add table
Reference in a new issue