mirror of
https://github.com/jrpie/Launcher.git
synced 2025-02-22 22:11:27 +01:00
feature: work profile
This commit is contained in:
parent
7a60611ec5
commit
500062b29b
9 changed files with 100 additions and 29 deletions
|
@ -11,6 +11,7 @@ This is a fork of [finnmglas's app Launcher][original-repo].
|
|||
## Notable changes:
|
||||
|
||||
* Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center.
|
||||
* Compatible with [work profile](https://www.android.com/enterprise/work-profile/), so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used.
|
||||
|
||||
### Visual
|
||||
* This app uses the system wallpaper instead of a custom solution.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" />
|
||||
|
||||
|
||||
<queries>
|
||||
|
|
|
@ -67,6 +67,8 @@ const val PREF_STARTED_TIME = "firstStartup"
|
|||
|
||||
const val PREF_VERSION = "version"
|
||||
|
||||
const val INVALID_USER = -1
|
||||
|
||||
/* Objects used by multiple activities */
|
||||
val appsList: MutableList<AppInfo> = ArrayList()
|
||||
|
||||
|
@ -153,14 +155,15 @@ private fun getIntent(packageName: String, context: Context): Intent? {
|
|||
}
|
||||
|
||||
fun launch(
|
||||
data: String, activity: Activity,
|
||||
data: String, user: Int?,
|
||||
activity: Activity,
|
||||
animationIn: Int = android.R.anim.fade_in, animationOut: Int = android.R.anim.fade_out
|
||||
) {
|
||||
|
||||
if (LauncherAction.isOtherAction(data)) { // [type]:[info]
|
||||
LauncherAction.byId(data)?.let {it.launch(activity) }
|
||||
}
|
||||
else launchApp(data, activity) // app
|
||||
else launchApp(data, user, activity) // app
|
||||
|
||||
activity.overridePendingTransition(animationIn, animationOut)
|
||||
}
|
||||
|
@ -217,7 +220,20 @@ fun audioVolumeDown(activity: Activity) {
|
|||
|
||||
/* --- */
|
||||
|
||||
fun launchApp(packageName: String, context: Context) {
|
||||
fun launchApp(packageName: String, user: Int?, context: Context) {
|
||||
Log.i("Launcher", "Starting: " + packageName + " (user " +user.toString()+ ")")
|
||||
if (user != null) {
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||
userManager.userProfiles.firstOrNull { it.hashCode() == user }?.let {
|
||||
userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull()?.let {
|
||||
app -> launcherApps.startMainActivity(app.componentName, userHandle, null, null)
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val intent = getIntent(packageName, context)
|
||||
|
||||
if (intent != null) {
|
||||
|
@ -327,25 +343,57 @@ fun openAppsList(activity: Activity){
|
|||
activity.startActivity(intent)
|
||||
}
|
||||
|
||||
fun getAppIcon(context: Context, packageName: String, user: Int?): Drawable {
|
||||
if (user != null) {
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||
userManager.userProfiles.firstOrNull { it.hashCode() == user }?.let {
|
||||
userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull()?.let {
|
||||
app -> return app.getBadgedIcon(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return context.packageManager.getApplicationIcon(packageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* [loadApps] is used to speed up the [AppsRecyclerAdapter] loading time,
|
||||
* as it caches all the apps and allows for fast access to the data.
|
||||
*/
|
||||
fun loadApps(packageManager: PackageManager) {
|
||||
fun loadApps(packageManager: PackageManager, context: Context) {
|
||||
val loadList = mutableListOf<AppInfo>()
|
||||
|
||||
val i = Intent(Intent.ACTION_MAIN, null)
|
||||
i.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
val allApps = packageManager.queryIntentActivities(i, 0)
|
||||
for (ri in allApps) {
|
||||
val app = AppInfo()
|
||||
app.label = ri.loadLabel(packageManager)
|
||||
app.packageName = ri.activityInfo.packageName
|
||||
app.icon = ri.activityInfo.loadIcon(packageManager)
|
||||
loadList.add(app)
|
||||
}
|
||||
loadList.sortBy { it.label.toString() }
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||
|
||||
// TODO: shortcuts - launcherApps.getShortcuts()
|
||||
val users = userManager.userProfiles
|
||||
for(user in users) {
|
||||
for (activityInfo in launcherApps.getActivityList(null,user)) {
|
||||
val app = AppInfo()
|
||||
app.label = activityInfo.label
|
||||
app.packageName = activityInfo.applicationInfo.packageName
|
||||
app.icon = activityInfo.getBadgedIcon(0)
|
||||
app.user = user.hashCode()
|
||||
loadList.add(app)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fallback option
|
||||
if(loadList.isEmpty()){
|
||||
Log.i("Launcher", "using fallback option to load packages")
|
||||
val i = Intent(Intent.ACTION_MAIN, null)
|
||||
i.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
val allApps = packageManager.queryIntentActivities(i, 0)
|
||||
for (ri in allApps) {
|
||||
val app = AppInfo()
|
||||
app.label = ri.loadLabel(packageManager)
|
||||
app.packageName = ri.activityInfo.packageName
|
||||
app.icon = ri.activityInfo.loadIcon(packageManager)
|
||||
loadList.add(app)
|
||||
}
|
||||
}
|
||||
appsList.clear()
|
||||
appsList.addAll(loadList)
|
||||
}
|
||||
|
@ -404,9 +452,12 @@ fun setWindowFlags(window: Window) {
|
|||
// Used in Tutorial and Settings `ActivityOnResult`
|
||||
fun saveListActivityChoice(context: Context, data: Intent?) {
|
||||
val value = data?.getStringExtra("value")
|
||||
var user = data?.getIntExtra("user", INVALID_USER)
|
||||
user = user?.let{ if(it == INVALID_USER) null else it }
|
||||
|
||||
val forGesture = data?.getStringExtra("forGesture") ?: return
|
||||
|
||||
Gesture.byId(forGesture)?.setApp(context, value.toString())
|
||||
Gesture.byId(forGesture)?.setApp(context, value.toString(), user)
|
||||
|
||||
loadSettings(context)
|
||||
}
|
||||
|
|
|
@ -41,8 +41,12 @@ enum class Gesture (val id: String, private val labelResource: Int,
|
|||
TOP, BOTTOM, LEFT, RIGHT
|
||||
}
|
||||
|
||||
fun getApp(context: Context): String {
|
||||
return getPreferences(context).getString(this.id, "")!!
|
||||
fun getApp(context: Context): Pair<String, Int?> {
|
||||
val preferences = getPreferences(context)
|
||||
var packageName = preferences.getString(this.id, "")!!
|
||||
var u: Int? = preferences.getInt(this.id + "_user", INVALID_USER)
|
||||
u = if(u == INVALID_USER) null else u
|
||||
return Pair(packageName,u)
|
||||
}
|
||||
|
||||
fun removeApp(context: Context) {
|
||||
|
@ -51,10 +55,15 @@ enum class Gesture (val id: String, private val labelResource: Int,
|
|||
.apply()
|
||||
}
|
||||
|
||||
fun setApp(context: Context, app: String) {
|
||||
fun setApp(context: Context, app: String, user: Int?) {
|
||||
getPreferences(context).edit()
|
||||
.putString(this.id, app)
|
||||
.apply()
|
||||
|
||||
val u = user?: INVALID_USER
|
||||
getPreferences(context).edit()
|
||||
.putInt(this.id + "_user", u)
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun getLabel(context: Context): String {
|
||||
|
@ -132,7 +141,8 @@ enum class Gesture (val id: String, private val labelResource: Int,
|
|||
}
|
||||
|
||||
operator fun invoke(activity: Activity) {
|
||||
launch(this.getApp(activity), activity, this.animationIn, this.animationOut)
|
||||
val app = this.getApp(activity)
|
||||
launch(app.first, app.second, activity, this.animationIn, this.animationOut)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -87,7 +87,7 @@ class HomeActivity: UIObject, AppCompatActivity(),
|
|||
}
|
||||
|
||||
// Preload apps to speed up the Apps Recycler
|
||||
AsyncTask.execute { loadApps(packageManager) }
|
||||
AsyncTask.execute { loadApps(packageManager, applicationContext) }
|
||||
|
||||
// Initialise layout
|
||||
binding = HomeBinding.inflate(layoutInflater)
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.graphics.drawable.Drawable
|
|||
* Represents an app installed on the users device.
|
||||
*/
|
||||
class AppInfo {
|
||||
var user: Int? = null
|
||||
var label: CharSequence? = null
|
||||
var packageName: CharSequence? = null
|
||||
var icon: Drawable? = null
|
||||
|
|
|
@ -21,6 +21,7 @@ import de.jrpie.android.launcher.appsList
|
|||
import de.jrpie.android.launcher.getPreferences
|
||||
import de.jrpie.android.launcher.getSavedTheme
|
||||
import de.jrpie.android.launcher.launch
|
||||
import de.jrpie.android.launcher.launchApp
|
||||
import de.jrpie.android.launcher.list.ListActivity
|
||||
import de.jrpie.android.launcher.list.intendedChoosePause
|
||||
import de.jrpie.android.launcher.loadApps
|
||||
|
@ -54,9 +55,10 @@ class AppsRecyclerAdapter(val activity: Activity,
|
|||
val pos = adapterPosition
|
||||
val context: Context = v.context
|
||||
val appPackageName = appsListDisplayed[pos].packageName.toString()
|
||||
|
||||
val appUser = appsListDisplayed[pos].user
|
||||
when (intention){
|
||||
ListActivity.ListActivityIntention.VIEW -> {
|
||||
launchApp(appPackageName, appUser, activity)
|
||||
val launchIntent: Intent = context.packageManager
|
||||
.getLaunchIntentForPackage(appPackageName)!!
|
||||
context.startActivity(launchIntent)
|
||||
|
@ -64,6 +66,7 @@ class AppsRecyclerAdapter(val activity: Activity,
|
|||
ListActivity.ListActivityIntention.PICK -> {
|
||||
val returnIntent = Intent()
|
||||
returnIntent.putExtra("value", appPackageName)
|
||||
appUser?.let{ returnIntent.putExtra("user", it) }
|
||||
returnIntent.putExtra("forGesture", forGesture)
|
||||
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
|
||||
activity.finish()
|
||||
|
@ -152,9 +155,9 @@ class AppsRecyclerAdapter(val activity: Activity,
|
|||
init {
|
||||
// Load the apps
|
||||
if (appsList.size == 0)
|
||||
loadApps(activity.packageManager)
|
||||
loadApps(activity.packageManager, activity)
|
||||
else {
|
||||
AsyncTask.execute { loadApps(activity.packageManager) }
|
||||
AsyncTask.execute { loadApps(activity.packageManager, activity) }
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
|
@ -193,7 +196,8 @@ class AppsRecyclerAdapter(val activity: Activity,
|
|||
// modifiable at some later point.
|
||||
if (appsListDisplayed.size == 1 && intention == ListActivity.ListActivityIntention.VIEW
|
||||
&& getPreferences(activity).getBoolean(PREF_SEARCH_AUTO_LAUNCH, false)) {
|
||||
launch(appsListDisplayed[0].packageName.toString(), activity)
|
||||
val info = appsListDisplayed[0]
|
||||
launch(info.packageName.toString(), info.user, activity)
|
||||
|
||||
val inputMethodManager = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(View(activity).windowToken, 0)
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.ViewGroup
|
|||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import de.jrpie.android.launcher.INVALID_USER
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
|
||||
import de.jrpie.android.launcher.list.forGesture
|
||||
|
@ -56,10 +57,11 @@ class OtherRecyclerAdapter(val activity: Activity):
|
|||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
private fun returnChoiceIntent(forApp: String, value: String) {
|
||||
private fun returnChoiceIntent(forGesture: String, value: String) {
|
||||
val returnIntent = Intent()
|
||||
returnIntent.putExtra("value", value)
|
||||
returnIntent.putExtra("forGesture", forApp)
|
||||
returnIntent.putExtra("forGesture", forGesture)
|
||||
returnIntent.putExtra("user", INVALID_USER)
|
||||
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
|
||||
activity.finish()
|
||||
}
|
||||
|
|
|
@ -80,7 +80,8 @@ class ActionsRecyclerAdapter(val activity: Activity):
|
|||
viewHolder.img
|
||||
)
|
||||
fun updateViewHolder() {
|
||||
val content = gesture.getApp(activity)
|
||||
val app = gesture.getApp(activity)
|
||||
val content = app.first
|
||||
if (content == ""){
|
||||
viewHolder.img.visibility = View.INVISIBLE
|
||||
viewHolder.removeAction.visibility = View.GONE
|
||||
|
@ -93,7 +94,7 @@ class ActionsRecyclerAdapter(val activity: Activity):
|
|||
} else {
|
||||
// Set image icon (by packageName)
|
||||
try {
|
||||
viewHolder.img.setImageDrawable(activity.packageManager.getApplicationIcon(content))
|
||||
viewHolder.img.setImageDrawable(getAppIcon(activity, content, app.second))
|
||||
} catch (e : Exception) {
|
||||
// the button is shown, user asked to select an action
|
||||
viewHolder.img.visibility = View.INVISIBLE
|
||||
|
|
Loading…
Add table
Reference in a new issue