chore: refactored code

This commit is contained in:
Josia Pietsch 2024-09-11 21:07:18 +02:00
parent ac2aa49ca1
commit 6e28fbfea5
Signed by: jrpie
GPG key ID: E70B571D66986A2D
43 changed files with 1367 additions and 746 deletions

View file

@ -19,7 +19,7 @@
android:theme="@style/launcherBaseTheme"> android:theme="@style/launcherBaseTheme">
<activity <activity
android:name=".HomeActivity" android:name=".ui.HomeActivity"
android:exported="true" android:exported="true"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:clearTaskOnLaunch="true" android:clearTaskOnLaunch="true"
@ -33,15 +33,15 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".tutorial.TutorialActivity" android:name="de.jrpie.android.launcher.ui.tutorial.TutorialActivity"
android:configChanges="orientation|screenSize" > android:configChanges="orientation|screenSize" >
</activity> </activity>
<activity <activity
android:name=".list.ListActivity" android:name="de.jrpie.android.launcher.ui.list.ListActivity"
android:windowSoftInputMode="adjustResize" > android:windowSoftInputMode="adjustResize" >
</activity> </activity>
<activity <activity
android:name=".settings.SettingsActivity" android:name="de.jrpie.android.launcher.ui.settings.SettingsActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:exported="true" > android:exported="true" >
<intent-filter> <intent-filter>

View file

@ -1,6 +1,5 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher
import android.content.Context
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences

View file

@ -1,7 +1,6 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.app.Service import android.app.Service
import android.app.role.RoleManager import android.app.role.RoleManager
import android.content.Context import android.content.Context
@ -10,42 +9,27 @@ import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.ColorMatrix import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter import android.graphics.ColorMatrixColorFilter
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.media.AudioManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.SystemClock
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.provider.Settings import android.provider.Settings
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.Window
import android.view.WindowManager
import android.view.animation.AlphaAnimation import android.view.animation.AlphaAnimation
import android.view.animation.Animation import android.view.animation.Animation
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import android.widget.Switch import de.jrpie.android.launcher.actions.Action
import android.widget.Toast import de.jrpie.android.launcher.actions.AppInfo
import androidx.annotation.RequiresApi import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.list.ListActivity import de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter
import de.jrpie.android.launcher.list.apps.AppInfo import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
import de.jrpie.android.launcher.list.apps.AppsRecyclerAdapter
import de.jrpie.android.launcher.list.other.LauncherAction
import de.jrpie.android.launcher.settings.SettingsActivity
import de.jrpie.android.launcher.tutorial.TutorialActivity
const val INVALID_USER = -1 const val INVALID_USER = -1
@ -87,10 +71,14 @@ fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
if (checkDefault if (checkDefault
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& context is Activity) { && context is Activity
) {
val roleManager = context.getSystemService(RoleManager::class.java) val roleManager = context.getSystemService(RoleManager::class.java)
if (!roleManager.isRoleHeld(RoleManager.ROLE_HOME)) { if (!roleManager.isRoleHeld(RoleManager.ROLE_HOME)) {
context.startActivityForResult(roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME), REQUEST_SET_DEFAULT_HOME) context.startActivityForResult(
roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME),
REQUEST_SET_DEFAULT_HOME
)
} }
return return
} }
@ -108,170 +96,48 @@ fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
context.startActivity(intent) context.startActivity(intent)
} }
/* Activity related */
fun isInstalled(uri: String, context: Context): Boolean { fun getIntent(packageName: String, context: Context): Intent? {
if (uri.startsWith("launcher:")) return true // All internal actions
try {
context.packageManager.getPackageInfo(uri, PackageManager.GET_ACTIVITIES)
return true
} catch (_: PackageManager.NameNotFoundException) { }
return false
}
private fun getIntent(packageName: String, context: Context): Intent? {
val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName) val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName)
intent?.addCategory(Intent.CATEGORY_LAUNCHER) intent?.addCategory(Intent.CATEGORY_LAUNCHER)
return intent return intent
} }
fun launch(
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, user, activity) // app
activity.overridePendingTransition(animationIn, animationOut)
}
/* Media player actions */
fun audioNextTrack(activity: Activity) {
val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis()
val downEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(downEvent)
val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent)
}
fun audioPreviousTrack(activity: Activity) {
val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis()
val downEvent =
KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0)
mAudioManager.dispatchMediaKeyEvent(downEvent)
val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent)
}
fun audioVolumeUp(activity: Activity) {
val audioManager =
activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE,
AudioManager.FLAG_SHOW_UI
)
}
fun audioVolumeDown(activity: Activity) {
val audioManager =
activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_LOWER,
AudioManager.FLAG_SHOW_UI
)
}
fun expandNotificationsPanel(context: Context) {
/* https://stackoverflow.com/a/15582509 */
try {
@Suppress("SpellCheckingInspection")
val statusBarService: Any? = context.getSystemService("statusbar")
val statusBarManager = Class.forName("android.app.StatusBarManager")
val showStatusBar = statusBarManager.getMethod("expandNotificationsPanel")
showStatusBar.invoke(statusBarService)
} catch (e: Exception) {
Toast.makeText(context, context.getString(R.string.alert_cant_expand_notifications_panel), Toast.LENGTH_LONG).show()
}
}
/* --- */ /* --- */
fun getUserFromId(user: Int?, context: Context): UserHandle? { fun getUserFromId(user: Int?, context: Context): UserHandle? {
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
return userManager.userProfiles.firstOrNull { it.hashCode() == user } return userManager.userProfiles.firstOrNull { it.hashCode() == user }
} }
fun getLauncherActivityInfo(packageName: String, user: Int?, context: Context): LauncherActivityInfo? {
fun getLauncherActivityInfo(
packageName: String,
user: Int?,
context: Context
): LauncherActivityInfo? {
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
return getUserFromId(user,context)?.let { return getUserFromId(user, context)?.let { userHandle ->
userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull() launcherApps.getActivityList(packageName, userHandle).firstOrNull()
} }
} }
fun uninstallApp(packageName: String, user: Int?, activity: Activity) {
fun uninstallApp(appInfo: AppInfo, activity: Activity) {
val packageName = appInfo.packageName.toString()
val user = appInfo.user
Log.i("Launcher", "uninstalling $packageName ($user)") Log.i("Launcher", "uninstalling $packageName ($user)")
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE) val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:$packageName") intent.data = Uri.parse("package:$packageName")
getUserFromId(user, activity)?.let { getUserFromId(user, activity)?.let { user ->
user -> intent.putExtra(Intent.EXTRA_USER, user) intent.putExtra(Intent.EXTRA_USER, user)
} }
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true) intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
activity.startActivityForResult(intent, activity.startActivityForResult(
intent,
REQUEST_UNINSTALL REQUEST_UNINSTALL
) )
} }
fun launchApp(packageName: String, user: Int?, context: Context, rect: Rect? = null) {
if (user != null && user != INVALID_USER) {
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
getLauncherActivityInfo(packageName,user,context)?.let {
app -> launcherApps.startMainActivity(app.componentName, app.user, rect, null)
return
}
}
val intent = getIntent(packageName, context)
if (intent != null) {
context.startActivity(intent)
} else {
if (isInstalled(packageName, context)){
AlertDialog.Builder(
context,
R.style.AlertDialogCustom
)
.setTitle(context.getString(R.string.alert_cant_open_title))
.setMessage(context.getString(R.string.alert_cant_open_message))
.setPositiveButton(android.R.string.ok
) { _, _ ->
openAppSettings(
packageName,
user,
context
)
}
.setNegativeButton(android.R.string.cancel, null)
.setIcon(android.R.drawable.ic_dialog_info)
.show()
} else {
Toast.makeText(
context,
context.getString(R.string.toast_cant_open_message),
Toast.LENGTH_SHORT
).show()
}
}
}
fun openNewTabWindow(urls: String, context: Context) { fun openNewTabWindow(urls: String, context: Context) {
val uris = Uri.parse(urls) val uris = Uri.parse(urls)
val intents = Intent(Intent.ACTION_VIEW, uris) val intents = Intent(Intent.ACTION_VIEW, uris)
@ -281,39 +147,22 @@ fun openNewTabWindow(urls: String, context: Context) {
context.startActivity(intents) context.startActivity(intents)
} }
fun openAppSettings(
fun openAppSettings(packageName: String, user: Int?, context: Context, sourceBounds: Rect? = null, opts: Bundle? = null) { appInfo: AppInfo,
context: Context,
sourceBounds: Rect? = null,
opts: Bundle? = null
) {
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
getLauncherActivityInfo(packageName, user, context)?.let { getLauncherActivityInfo(appInfo.packageName.toString(), appInfo.user, context)?.let { app ->
app -> launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts) launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts)
} }
} }
fun openSettings(activity: Activity) { fun openTutorial(context: Context) {
activity.startActivity(Intent(activity, SettingsActivity::class.java)) context.startActivity(Intent(context, TutorialActivity::class.java))
} }
fun openTutorial(activity: Activity){
activity.startActivity(Intent(activity, TutorialActivity::class.java))
}
fun openAppsList(activity: Activity){
val intent = Intent(activity, ListActivity::class.java)
intent.putExtra("intention", ListActivity.ListActivityIntention.VIEW.toString())
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
getUserFromId(user,context)?.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, * [loadApps] is used to speed up the [AppsRecyclerAdapter] loading time,
@ -334,7 +183,8 @@ fun loadApps(packageManager: PackageManager, context: Context) {
app.packageName = activityInfo.applicationInfo.packageName app.packageName = activityInfo.applicationInfo.packageName
app.icon = activityInfo.getBadgedIcon(0) app.icon = activityInfo.getBadgedIcon(0)
app.user = user.hashCode() app.user = user.hashCode()
app.isSystemApp = activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0 app.isSystemApp =
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0
loadList.add(app) loadList.add(app)
} }
} }
@ -361,14 +211,9 @@ fun loadApps(packageManager: PackageManager, context: Context) {
// Used in Tutorial and Settings `ActivityOnResult` // Used in Tutorial and Settings `ActivityOnResult`
fun saveListActivityChoice(context: Context, data: Intent?) { fun saveListActivityChoice(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 val forGesture = data?.getStringExtra("forGesture") ?: return
Gesture.byId(forGesture)?.let { Action.setActionForGesture(it, Action.fromIntent(data)) }
Gesture.byId(forGesture)?.setApp(context, value.toString(), user)
} }
// Taken from https://stackoverflow.com/a/50743764/12787264 // Taken from https://stackoverflow.com/a/50743764/12787264

View file

@ -1,155 +0,0 @@
package de.jrpie.android.launcher
import android.app.Activity
import android.content.Context
import de.jrpie.android.launcher.preferences.LauncherPreferences
/**
* @param id internal id to serialize the action. Used as a key in shared preferences.
* @param defaultsResource res id of array of default actions for the gesture.
* @param labelResource res id of the name of the gesture.
* @param animationIn res id of transition animation (in) when using the gesture to launch an app.
* @param animationOut res id of transition animation (out) when using the gesture to launch an app.
*/
enum class Gesture (val id: String, private val labelResource: Int,
private val defaultsResource: Int,
private val animationIn: Int = android.R.anim.fade_in,
private val animationOut: Int = android.R.anim.fade_out){
VOLUME_UP("action.volume_up", R.string.settings_gesture_vol_up, R.array.default_volume_up, 0,0),
VOLUME_DOWN("action.volume_down", R.string.settings_gesture_vol_down, R.array.default_volume_down,0,0),
TIME("action.time", R.string.settings_gesture_time, R.array.default_time),
DATE("action.date", R.string.settings_gesture_date, R.array.default_date),
LONG_CLICK("action.long_click", R.string.settings_gesture_long_click, R.array.default_long_click, 0,0),
DOUBLE_CLICK("action.double_click", R.string.settings_gesture_double_click, R.array.default_double_click,0,0),
SWIPE_UP("action.up", R.string.settings_gesture_up, R.array.default_up, R.anim.bottom_up),
SWIPE_UP_LEFT_EDGE("action.up_left", R.string.settings_gesture_up_left_edge, R.array.default_up_left, R.anim.bottom_up),
SWIPE_UP_RIGHT_EDGE("action.up_right", R.string.settings_gesture_up_right_edge, R.array.default_up_right, R.anim.bottom_up),
SWIPE_UP_DOUBLE( "action.double_up", R.string.settings_gesture_double_up, R.array.default_double_up, R.anim.bottom_up),
SWIPE_DOWN("action.down", R.string.settings_gesture_down, R.array.default_down, R.anim.top_down),
SWIPE_DOWN_LEFT_EDGE("action.down_left", R.string.settings_gesture_down_left_edge, R.array.default_down_left, R.anim.top_down),
SWIPE_DOWN_RIGHT_EDGE("action.down_right", R.string.settings_gesture_down_right_edge, R.array.default_down_right, R.anim.top_down),
SWIPE_DOWN_DOUBLE("action.double_down", R.string.settings_gesture_double_down, R.array.default_double_down, R.anim.top_down),
SWIPE_LEFT("action.left", R.string.settings_gesture_left, R.array.default_left, R.anim.right_left),
SWIPE_LEFT_TOP_EDGE("action.left_top", R.string.settings_gesture_left_top_edge, R.array.default_left_top, R.anim.right_left),
SWIPE_LEFT_BOTTOM_EDGE("action.left_bottom", R.string.settings_gesture_left_bottom_edge, R.array.default_left_bottom, R.anim.right_left),
SWIPE_LEFT_DOUBLE("action.double_left", R.string.settings_gesture_double_left, R.array.default_double_left, R.anim.right_left),
SWIPE_RIGHT("action.right", R.string.settings_gesture_right, R.array.default_right, R.anim.left_right),
SWIPE_RIGHT_TOP_EDGE("action.right_top", R.string.settings_gesture_right_top_edge, R.array.default_right_top, R.anim.left_right),
SWIPE_RIGHT_BOTTOM_EDGE("action.right_bottom", R.string.settings_gesture_right_bottom_edge, R.array.default_right_bottom, R.anim.left_right),
SWIPE_RIGHT_DOUBLE("action.double_right", R.string.settings_gesture_double_right, R.array.default_double_right, R.anim.left_right);
enum class Edge{
TOP, BOTTOM, LEFT, RIGHT
}
fun getApp(context: Context): Pair<String, Int?> {
val preferences = LauncherPreferences.getSharedPreferences()
var packageName = preferences.getString(this.id + ".app", "")!!
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) {
LauncherPreferences.getSharedPreferences().edit()
.putString(this.id + ".app", "") // clear it
.apply()
}
fun setApp(context: Context, app: String, user: Int?) {
LauncherPreferences.getSharedPreferences().edit()
.putString(this.id + ".app", app)
.apply()
val u = user?: INVALID_USER
LauncherPreferences.getSharedPreferences().edit()
.putInt(this.id + ".user", u)
.apply()
}
fun getLabel(context: Context): String {
return context.resources.getString(this.labelResource)
}
fun pickDefaultApp(context: Context) : String {
return context.resources
.getStringArray(this.defaultsResource)
.firstOrNull { isInstalled(it, context) }
?: ""
}
fun getDoubleVariant(): Gesture {
return when(this) {
SWIPE_UP -> SWIPE_UP_DOUBLE
SWIPE_DOWN -> SWIPE_DOWN_DOUBLE
SWIPE_LEFT -> SWIPE_LEFT_DOUBLE
SWIPE_RIGHT -> SWIPE_RIGHT_DOUBLE
else -> this
}
}
fun getEdgeVariant(edge: Edge): Gesture {
return when(edge) {
Edge.TOP ->
when(this) {
SWIPE_LEFT -> SWIPE_LEFT_TOP_EDGE
SWIPE_RIGHT -> SWIPE_RIGHT_TOP_EDGE
else -> this
}
Edge.BOTTOM ->
when(this) {
SWIPE_LEFT -> SWIPE_LEFT_BOTTOM_EDGE
SWIPE_RIGHT -> SWIPE_RIGHT_BOTTOM_EDGE
else -> this
}
Edge.LEFT ->
when(this) {
SWIPE_UP -> SWIPE_UP_LEFT_EDGE
SWIPE_DOWN -> SWIPE_DOWN_LEFT_EDGE
else -> this
}
Edge.RIGHT ->
when(this) {
SWIPE_UP -> SWIPE_UP_RIGHT_EDGE
SWIPE_DOWN -> SWIPE_DOWN_RIGHT_EDGE
else -> this
}
}
}
fun isDoubleVariant(): Boolean {
return when(this){
SWIPE_UP_DOUBLE,
SWIPE_DOWN_DOUBLE,
SWIPE_LEFT_DOUBLE,
SWIPE_RIGHT_DOUBLE -> true
else -> false
}
}
fun isEdgeVariant(): Boolean {
return when(this){
SWIPE_UP_RIGHT_EDGE,
SWIPE_UP_LEFT_EDGE,
SWIPE_DOWN_LEFT_EDGE,
SWIPE_DOWN_RIGHT_EDGE,
SWIPE_LEFT_TOP_EDGE,
SWIPE_LEFT_BOTTOM_EDGE,
SWIPE_RIGHT_TOP_EDGE,
SWIPE_RIGHT_BOTTOM_EDGE -> true
else -> false
}
}
operator fun invoke(activity: Activity) {
val app = this.getApp(activity)
launch(app.first, app.second, activity, this.animationIn, this.animationOut)
}
companion object {
fun byId(id: String): Gesture? {
return Gesture.values().firstOrNull {it.id == id }
}
}
}

View file

@ -0,0 +1,100 @@
package de.jrpie.android.launcher.actions
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences.Editor
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.widget.Toast
import de.jrpie.android.launcher.INVALID_USER
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.preferences.LauncherPreferences
interface Action {
fun invoke(context: Context, rect: Rect? = null): Boolean
fun bindToGesture(prefEditor: Editor, id: String)
fun label(context: Context): String
fun getIcon(context: Context): Drawable?
fun isAvailable(context: Context): Boolean
fun writeToIntent(intent: Intent)
companion object {
private fun fromId(id: String, user: Int?): Action? {
if (id.isEmpty()) {
return null
}
if (LauncherAction.isOtherAction(id)) {
return LauncherAction.byId(id)
}
return AppAction(AppInfo(id, user))
}
fun forGesture(gesture: Gesture): Action? {
val id = gesture.id
val preferences = LauncherPreferences.getSharedPreferences()
var actionId = preferences.getString("$id.app", "")!!
var u: Int? = preferences.getInt("$id.user", INVALID_USER)
u = if (u == INVALID_USER) null else u
return fromId(actionId, u)
}
fun resetToDefaultActions(context: Context) {
val editor = LauncherPreferences.getSharedPreferences().edit()
Gesture.values().forEach { gesture ->
context.resources
.getStringArray(gesture.defaultsResource)
.map { fromId(it, null) }
.firstOrNull { it?.isAvailable(context) ?: false }
?.bindToGesture(editor, gesture.id)
}
editor.apply()
}
fun setActionForGesture(gesture: Gesture, action: Action?) {
if (action == null) {
clearActionForGesture(gesture)
return
}
val editor = LauncherPreferences.getSharedPreferences().edit()
action.bindToGesture(editor, gesture.id)
editor.apply()
}
fun clearActionForGesture(gesture: Gesture) {
LauncherPreferences.getSharedPreferences().edit()
.putString(gesture.id + ".app", "")
.putInt(gesture.id + ".user", INVALID_USER)
.apply()
}
fun launch(
action: Action?,
context: Context,
animationIn: Int = android.R.anim.fade_in,
animationOut: Int = android.R.anim.fade_out
) {
if (action != null && action.invoke(context)) {
if (context is Activity) {
context.overridePendingTransition(animationIn, animationOut)
}
} else {
Toast.makeText(
context,
context.getString(R.string.toast_cant_open_message),
Toast.LENGTH_SHORT
).show()
}
}
fun fromIntent(data: Intent): Action? {
val value = data.getStringExtra("action_id") ?: return null
var user = data.getIntExtra("user", INVALID_USER)
return fromId(value, user)
}
}
}

View file

@ -0,0 +1,85 @@
package de.jrpie.android.launcher.actions
import android.app.AlertDialog
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.LauncherApps
import android.graphics.Rect
import android.graphics.drawable.Drawable
import de.jrpie.android.launcher.INVALID_USER
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.getIntent
import de.jrpie.android.launcher.getLauncherActivityInfo
import de.jrpie.android.launcher.openAppSettings
class AppAction(private var appInfo: AppInfo) : Action {
override fun invoke(context: Context, rect: Rect?): Boolean {
val packageName = appInfo.packageName.toString()
val user = appInfo.user
if (user != null && user != INVALID_USER) {
val launcherApps =
context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
getLauncherActivityInfo(packageName, user, context)?.let { app ->
launcherApps.startMainActivity(app.componentName, app.user, rect, null)
return true
}
}
val intent = getIntent(packageName, context)
if (intent != null) {
context.startActivity(intent)
return true
}
if (AppInfo(packageName).isInstalled(context)) {
AlertDialog.Builder(
context,
R.style.AlertDialogCustom
)
.setTitle(context.getString(R.string.alert_cant_open_title))
.setMessage(context.getString(R.string.alert_cant_open_message))
.setPositiveButton(android.R.string.ok) { _, _ ->
openAppSettings(appInfo, context)
}
.setNegativeButton(android.R.string.cancel, null)
.setIcon(android.R.drawable.ic_dialog_info)
.show()
return true
}
return false
}
override fun label(context: Context): String {
return appInfo.label.toString()
}
override fun getIcon(context: Context): Drawable? {
var icon: Drawable? = null
try {
icon = appInfo.getAppIcon(context)
} catch (e: Exception) {
// probably the app was uninstalled
}
return icon
}
override fun isAvailable(context: Context): Boolean {
return appInfo.isInstalled(context)
}
override fun bindToGesture(editor: SharedPreferences.Editor, id: String) {
val u = appInfo.user ?: INVALID_USER
editor
.putString("$id.app", appInfo.packageName.toString())
.putInt("$id.user", u)
}
override fun writeToIntent(intent: Intent) {
intent.putExtra("action_id", appInfo.packageName)
appInfo.user?.let { intent.putExtra("user", it) }
}
}

View file

@ -0,0 +1,49 @@
package de.jrpie.android.launcher.actions
import android.app.Service
import android.content.Context
import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import de.jrpie.android.launcher.INVALID_USER
import de.jrpie.android.launcher.getUserFromId
/**
* Stores information used to create [AppsRecyclerAdapter] rows.
*
* Represents an app installed on the users device.
*/
class AppInfo(var packageName: CharSequence? = null, var user: Int? = null) {
var label: CharSequence? = null
var icon: Drawable? = null
var isSystemApp: Boolean = false
fun getAppIcon(context: Context): Drawable {
if (user != null && user != INVALID_USER) {
val launcherApps =
context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
getUserFromId(user, context)?.let { userHandle ->
launcherApps.getActivityList(packageName.toString(), userHandle).firstOrNull()
?.let { app ->
return app.getBadgedIcon(0)
}
}
}
return context.packageManager.getApplicationIcon(packageName.toString())
}
fun isInstalled(context: Context): Boolean {
/* TODO: this should also check the user */
try {
context.packageManager.getPackageInfo(
packageName.toString(),
PackageManager.GET_ACTIVITIES
)
return true
} catch (_: PackageManager.NameNotFoundException) {
}
return false
}
}

View file

@ -0,0 +1,222 @@
package de.jrpie.android.launcher.actions
import android.content.Context
import de.jrpie.android.launcher.R
/**
* @param id internal id to serialize the action. Used as a key in shared preferences.
* @param defaultsResource res id of array of default actions for the gesture.
* @param labelResource res id of the name of the gesture.
* @param animationIn res id of transition animation (in) when using the gesture to launch an app.
* @param animationOut res id of transition animation (out) when using the gesture to launch an app.
*/
enum class Gesture(
val id: String, private val labelResource: Int,
internal val defaultsResource: Int,
private val animationIn: Int = android.R.anim.fade_in,
private val animationOut: Int = android.R.anim.fade_out
) {
VOLUME_UP(
"action.volume_up",
R.string.settings_gesture_vol_up,
R.array.default_volume_up,
0,
0
),
VOLUME_DOWN(
"action.volume_down",
R.string.settings_gesture_vol_down,
R.array.default_volume_down, 0, 0
),
TIME("action.time", R.string.settings_gesture_time, R.array.default_time),
DATE("action.date", R.string.settings_gesture_date, R.array.default_date),
LONG_CLICK(
"action.long_click",
R.string.settings_gesture_long_click,
R.array.default_long_click, 0, 0
),
DOUBLE_CLICK(
"action.double_click",
R.string.settings_gesture_double_click,
R.array.default_double_click, 0, 0
),
SWIPE_UP("action.up", R.string.settings_gesture_up, R.array.default_up, R.anim.bottom_up),
SWIPE_UP_LEFT_EDGE(
"action.up_left",
R.string.settings_gesture_up_left_edge,
R.array.default_up_left,
R.anim.bottom_up
),
SWIPE_UP_RIGHT_EDGE(
"action.up_right",
R.string.settings_gesture_up_right_edge,
R.array.default_up_right,
R.anim.bottom_up
),
SWIPE_UP_DOUBLE(
"action.double_up",
R.string.settings_gesture_double_up,
R.array.default_double_up,
R.anim.bottom_up
),
SWIPE_DOWN(
"action.down",
R.string.settings_gesture_down,
R.array.default_down,
R.anim.top_down
),
SWIPE_DOWN_LEFT_EDGE(
"action.down_left",
R.string.settings_gesture_down_left_edge,
R.array.default_down_left,
R.anim.top_down
),
SWIPE_DOWN_RIGHT_EDGE(
"action.down_right",
R.string.settings_gesture_down_right_edge,
R.array.default_down_right,
R.anim.top_down
),
SWIPE_DOWN_DOUBLE(
"action.double_down",
R.string.settings_gesture_double_down,
R.array.default_double_down,
R.anim.top_down
),
SWIPE_LEFT(
"action.left",
R.string.settings_gesture_left,
R.array.default_left,
R.anim.right_left
),
SWIPE_LEFT_TOP_EDGE(
"action.left_top",
R.string.settings_gesture_left_top_edge,
R.array.default_left_top,
R.anim.right_left
),
SWIPE_LEFT_BOTTOM_EDGE(
"action.left_bottom",
R.string.settings_gesture_left_bottom_edge,
R.array.default_left_bottom,
R.anim.right_left
),
SWIPE_LEFT_DOUBLE(
"action.double_left",
R.string.settings_gesture_double_left,
R.array.default_double_left,
R.anim.right_left
),
SWIPE_RIGHT(
"action.right",
R.string.settings_gesture_right,
R.array.default_right,
R.anim.left_right
),
SWIPE_RIGHT_TOP_EDGE(
"action.right_top",
R.string.settings_gesture_right_top_edge,
R.array.default_right_top,
R.anim.left_right
),
SWIPE_RIGHT_BOTTOM_EDGE(
"action.right_bottom",
R.string.settings_gesture_right_bottom_edge,
R.array.default_right_bottom,
R.anim.left_right
),
SWIPE_RIGHT_DOUBLE(
"action.double_right",
R.string.settings_gesture_double_right,
R.array.default_double_right,
R.anim.left_right
);
enum class Edge {
TOP, BOTTOM, LEFT, RIGHT
}
fun getLabel(context: Context): String {
return context.resources.getString(this.labelResource)
}
fun getDoubleVariant(): Gesture {
return when (this) {
SWIPE_UP -> SWIPE_UP_DOUBLE
SWIPE_DOWN -> SWIPE_DOWN_DOUBLE
SWIPE_LEFT -> SWIPE_LEFT_DOUBLE
SWIPE_RIGHT -> SWIPE_RIGHT_DOUBLE
else -> this
}
}
fun getEdgeVariant(edge: Edge): Gesture {
return when (edge) {
Edge.TOP ->
when (this) {
SWIPE_LEFT -> SWIPE_LEFT_TOP_EDGE
SWIPE_RIGHT -> SWIPE_RIGHT_TOP_EDGE
else -> this
}
Edge.BOTTOM ->
when (this) {
SWIPE_LEFT -> SWIPE_LEFT_BOTTOM_EDGE
SWIPE_RIGHT -> SWIPE_RIGHT_BOTTOM_EDGE
else -> this
}
Edge.LEFT ->
when (this) {
SWIPE_UP -> SWIPE_UP_LEFT_EDGE
SWIPE_DOWN -> SWIPE_DOWN_LEFT_EDGE
else -> this
}
Edge.RIGHT ->
when (this) {
SWIPE_UP -> SWIPE_UP_RIGHT_EDGE
SWIPE_DOWN -> SWIPE_DOWN_RIGHT_EDGE
else -> this
}
}
}
fun isDoubleVariant(): Boolean {
return when (this) {
SWIPE_UP_DOUBLE,
SWIPE_DOWN_DOUBLE,
SWIPE_LEFT_DOUBLE,
SWIPE_RIGHT_DOUBLE -> true
else -> false
}
}
fun isEdgeVariant(): Boolean {
return when (this) {
SWIPE_UP_RIGHT_EDGE,
SWIPE_UP_LEFT_EDGE,
SWIPE_DOWN_LEFT_EDGE,
SWIPE_DOWN_RIGHT_EDGE,
SWIPE_LEFT_TOP_EDGE,
SWIPE_LEFT_BOTTOM_EDGE,
SWIPE_RIGHT_TOP_EDGE,
SWIPE_RIGHT_BOTTOM_EDGE -> true
else -> false
}
}
operator fun invoke(context: Context) {
val action = Action.forGesture(this)
Action.launch(action, context, this.animationIn, this.animationOut)
}
companion object {
fun byId(id: String): Gesture? {
return Gesture.values().firstOrNull { it.id == id }
}
}
}

View file

@ -0,0 +1,185 @@
package de.jrpie.android.launcher.actions
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences.Editor
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.media.AudioManager
import android.os.SystemClock
import android.view.KeyEvent
import android.widget.Toast
import de.jrpie.android.launcher.INVALID_USER
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.ui.list.ListActivity
import de.jrpie.android.launcher.ui.settings.SettingsActivity
enum class LauncherAction(
val id: String,
val label: Int,
val icon: Int,
val launch: (Context) -> Unit
) : Action {
SETTINGS(
"launcher:settings",
R.string.list_other_settings,
R.drawable.baseline_settings_24,
::openSettings
),
CHOOSE(
"launcher:choose",
R.string.list_other_list,
R.drawable.baseline_menu_24,
::openAppsList
),
VOLUME_UP(
"launcher:volumeUp",
R.string.list_other_volume_up,
R.drawable.baseline_volume_up_24, ::audioVolumeUp
),
VOLUME_DOWN(
"launcher:volumeDown",
R.string.list_other_volume_down,
R.drawable.baseline_volume_down_24, ::audioVolumeDown
),
TRACK_NEXT(
"launcher:nextTrack",
R.string.list_other_track_next,
R.drawable.baseline_skip_next_24, ::audioNextTrack
),
TRACK_PREV(
"launcher:previousTrack",
R.string.list_other_track_previous,
R.drawable.baseline_skip_previous_24, ::audioPreviousTrack
),
EXPAND_NOTIFICATIONS_PANEL(
"launcher:expandNotificationsPanel",
R.string.list_other_expand_notifications_panel,
R.drawable.baseline_notifications_24,
::expandNotificationsPanel
),
NOP("launcher:nop", R.string.list_other_nop, R.drawable.baseline_not_interested_24, {});
override fun invoke(context: Context, rect: Rect?): Boolean {
launch(context)
return true
}
override fun label(context: Context): String {
return context.getString(label)
}
override fun getIcon(context: Context): Drawable? {
return context.getDrawable(icon)
}
override fun bindToGesture(editor: Editor, id: String) {
editor
.putString("$id.app", this.id)
.putInt("$id.user", INVALID_USER)
}
override fun writeToIntent(intent: Intent) {
intent.putExtra("action_id", id)
}
override fun isAvailable(context: Context): Boolean {
return true
}
companion object {
fun byId(id: String): LauncherAction? {
return LauncherAction.values().singleOrNull { it.id == id }
}
fun isOtherAction(id: String): Boolean {
return id.startsWith("launcher")
}
}
}
/* Media player actions */
private fun audioNextTrack(context: Context) {
val mAudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis()
val downEvent =
KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(downEvent)
val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent)
}
private fun audioPreviousTrack(context: Context) {
val mAudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis()
val downEvent =
KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0)
mAudioManager.dispatchMediaKeyEvent(downEvent)
val upEvent =
KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent)
}
private fun audioVolumeUp(context: Context) {
val audioManager =
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE,
AudioManager.FLAG_SHOW_UI
)
}
private fun audioVolumeDown(context: Context) {
val audioManager =
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.adjustStreamVolume(
AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_LOWER,
AudioManager.FLAG_SHOW_UI
)
}
/* End media player actions */
private fun expandNotificationsPanel(context: Context) {
/* https://stackoverflow.com/a/15582509 */
try {
@Suppress("SpellCheckingInspection")
val statusBarService: Any? = context.getSystemService("statusbar")
val statusBarManager = Class.forName("android.app.StatusBarManager")
val showStatusBar = statusBarManager.getMethod("expandNotificationsPanel")
showStatusBar.invoke(statusBarService)
} catch (e: Exception) {
Toast.makeText(
context,
context.getString(R.string.alert_cant_expand_notifications_panel),
Toast.LENGTH_LONG
).show()
}
}
private fun openSettings(context: Context) {
context.startActivity(Intent(context, SettingsActivity::class.java))
}
private fun openAppsList(context: Context) {
val intent = Intent(context, ListActivity::class.java)
intent.putExtra("intention", ListActivity.ListActivityIntention.VIEW.toString())
context.startActivity(intent)
}

View file

@ -1,16 +0,0 @@
package de.jrpie.android.launcher.list.apps
import android.graphics.drawable.Drawable
/**
* Stores information used to create [AppsRecyclerAdapter] rows.
*
* 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
var isSystemApp: Boolean = false
}

View file

@ -1,43 +0,0 @@
package de.jrpie.android.launcher.list.other
import android.app.Activity
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.audioNextTrack
import de.jrpie.android.launcher.audioPreviousTrack
import de.jrpie.android.launcher.audioVolumeDown
import de.jrpie.android.launcher.audioVolumeUp
import de.jrpie.android.launcher.expandNotificationsPanel
import de.jrpie.android.launcher.openAppsList
import de.jrpie.android.launcher.openSettings
enum class LauncherAction(val id: String, val label: Int, val icon: Int, val launch: (Activity) -> Unit) {
SETTINGS("launcher:settings", R.string.list_other_settings, R.drawable.baseline_settings_24, ::openSettings),
CHOOSE("launcher:choose", R.string.list_other_list, R.drawable.baseline_menu_24, ::openAppsList),
VOLUME_UP("launcher:volumeUp",
R.string.list_other_volume_up,
R.drawable.baseline_volume_up_24, ::audioVolumeUp),
VOLUME_DOWN("launcher:volumeDown",
R.string.list_other_volume_down,
R.drawable.baseline_volume_down_24, ::audioVolumeDown),
TRACK_NEXT("launcher:nextTrack",
R.string.list_other_track_next,
R.drawable.baseline_skip_next_24, ::audioNextTrack),
TRACK_PREV("launcher:previousTrack",
R.string.list_other_track_previous,
R.drawable.baseline_skip_previous_24, ::audioPreviousTrack),
EXPAND_NOTIFICATIONS_PANEL("launcher:expandNotificationsPanel",
R.string.list_other_expand_notifications_panel,
R.drawable.baseline_notifications_24,
::expandNotificationsPanel),
NOP("launcher:nop", R.string.list_other_nop, R.drawable.baseline_not_interested_24, {});
companion object {
fun byId(id: String): LauncherAction? {
return LauncherAction.values().singleOrNull { it.id == id }
}
fun isOtherAction(id: String): Boolean {
return id.startsWith("launcher")
}
}
}

View file

@ -3,8 +3,7 @@ package de.jrpie.android.launcher.preferences
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log import android.util.Log
import android.widget.Toast import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.Gesture
import de.jrpie.android.launcher.preferences.theme.Background import de.jrpie.android.launcher.preferences.theme.Background
import de.jrpie.android.launcher.preferences.theme.ColorTheme import de.jrpie.android.launcher.preferences.theme.ColorTheme
@ -17,15 +16,35 @@ const val UNKNOWN_PREFERENCE_VERSION = -1
private const val TAG = "Launcher - Preferences" private const val TAG = "Launcher - Preferences"
private fun migrateStringPreference(oldPrefs: SharedPreferences, newPreferences: SharedPreferences.Editor, oldKey: String, newKey: String, default: String) { private fun migrateStringPreference(
oldPrefs: SharedPreferences,
newPreferences: SharedPreferences.Editor,
oldKey: String,
newKey: String,
default: String
) {
val s = oldPrefs.getString(oldKey, default) val s = oldPrefs.getString(oldKey, default)
newPreferences.putString(newKey, s) newPreferences.putString(newKey, s)
} }
private fun migrateIntPreference(oldPrefs: SharedPreferences, newPreferences: SharedPreferences.Editor, oldKey: String, newKey: String, default: Int) {
private fun migrateIntPreference(
oldPrefs: SharedPreferences,
newPreferences: SharedPreferences.Editor,
oldKey: String,
newKey: String,
default: Int
) {
val s = oldPrefs.getInt(oldKey, default) val s = oldPrefs.getInt(oldKey, default)
newPreferences.putInt(newKey, s) newPreferences.putInt(newKey, s)
} }
private fun migrateBooleanPreference(oldPrefs: SharedPreferences, newPreferences: SharedPreferences.Editor, oldKey: String, newKey: String, default: Boolean) {
private fun migrateBooleanPreference(
oldPrefs: SharedPreferences,
newPreferences: SharedPreferences.Editor,
oldKey: String,
newKey: String,
default: Boolean
) {
val s = oldPrefs.getBoolean(oldKey, default) val s = oldPrefs.getBoolean(oldKey, default)
newPreferences.putBoolean(newKey, s) newPreferences.putBoolean(newKey, s)
} }
@ -33,9 +52,14 @@ private fun migrateBooleanPreference(oldPrefs: SharedPreferences, newPreferences
fun migratePreferencesToNewVersion(context: Context) { fun migratePreferencesToNewVersion(context: Context) {
when (LauncherPreferences.internal().versionCode()) { when (LauncherPreferences.internal().versionCode()) {
// Check versions, make sure transitions between versions go well // Check versions, make sure transitions between versions go well
PREFERENCE_VERSION -> { /* the version installed and used previously are the same */ } PREFERENCE_VERSION -> { /* the version installed and used previously are the same */
}
UNKNOWN_PREFERENCE_VERSION -> { /* still using the old preferences file */ UNKNOWN_PREFERENCE_VERSION -> { /* still using the old preferences file */
Log.i(TAG, "Unknown preference version, trying to restore preferences from old version.") Log.i(
TAG,
"Unknown preference version, trying to restore preferences from old version."
)
val oldPrefs = context.getSharedPreferences( val oldPrefs = context.getSharedPreferences(
@ -48,62 +72,314 @@ fun migratePreferencesToNewVersion(context: Context) {
} }
val newPrefs = LauncherPreferences.getSharedPreferences().edit() val newPrefs = LauncherPreferences.getSharedPreferences().edit()
migrateBooleanPreference(oldPrefs, newPrefs, "startedBefore", "internal.started_before", false) migrateBooleanPreference(
oldPrefs,
newPrefs,
"startedBefore",
"internal.started_before",
false
)
migrateStringPreference(oldPrefs, newPrefs, "action_volumeUpApp", "action.volume_up.app", "") migrateStringPreference(
migrateIntPreference(oldPrefs, newPrefs, "action_volumeUpApp_user", "action.volume_up.user", -1) oldPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_volumeDownApp", "action.volume_down.app", "") newPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_volumeDownApp_user", "action.volume_down.user", -1) "action_volumeUpApp",
"action.volume_up.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_volumeUpApp_user",
"action.volume_up.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_volumeDownApp",
"action.volume_down.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_volumeDownApp_user",
"action.volume_down.user",
-1
)
migrateStringPreference(oldPrefs, newPrefs, "action_timeApp", "action.time.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_timeApp", "action.time.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_timeApp_user", "action.time.user", -1) migrateIntPreference(oldPrefs, newPrefs, "action_timeApp_user", "action.time.user", -1)
migrateStringPreference(oldPrefs, newPrefs, "action_dateApp", "action.date.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_dateApp", "action.date.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_dateApp_user", "action.date.user", -1) migrateIntPreference(oldPrefs, newPrefs, "action_dateApp_user", "action.date.user", -1)
migrateStringPreference(oldPrefs, newPrefs, "action_longClickApp", "action.long_click.app", "") migrateStringPreference(
migrateIntPreference(oldPrefs, newPrefs, "action_longClickApp_user", "action.long_click.user", -1) oldPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_doubleClickApp", "action.double_click.app", "") newPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_doubleClickApp_user", "action.double_click.user", -1) "action_longClickApp",
"action.long_click.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_longClickApp_user",
"action.long_click.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_doubleClickApp",
"action.double_click.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_doubleClickApp_user",
"action.double_click.user",
-1
)
migrateStringPreference(oldPrefs, newPrefs, "action_upApp", "action.up.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_upApp", "action.up.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_upApp_user", "action.up.user", -1) migrateIntPreference(oldPrefs, newPrefs, "action_upApp_user", "action.up.user", -1)
migrateStringPreference(oldPrefs, newPrefs, "action_up_leftApp", "action.up_left.app", "") migrateStringPreference(
migrateIntPreference(oldPrefs, newPrefs, "action_up_leftApp_user", "action.up_left.user", -1) oldPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_up_rightApp", "action.up_right.app", "") newPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_up_rightApp_user", "action.up_right.user", -1) "action_up_leftApp",
migrateStringPreference(oldPrefs, newPrefs, "action_doubleUpApp", "action.double_up.app", "") "action.up_left.app",
migrateIntPreference(oldPrefs, newPrefs, "action_doubleUpApp_user", "action.double_up.user", -1) ""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_up_leftApp_user",
"action.up_left.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_up_rightApp",
"action.up_right.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_up_rightApp_user",
"action.up_right.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_doubleUpApp",
"action.double_up.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_doubleUpApp_user",
"action.double_up.user",
-1
)
migrateStringPreference(oldPrefs, newPrefs, "action_downApp", "action.down.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_downApp", "action.down.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_downApp_user", "action.down.user", -1) migrateIntPreference(oldPrefs, newPrefs, "action_downApp_user", "action.down.user", -1)
migrateStringPreference(oldPrefs, newPrefs, "action_down_leftApp", "action.down_left.app", "") migrateStringPreference(
migrateIntPreference(oldPrefs, newPrefs, "action_down_leftApp_user", "action.down_left.user", -1) oldPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_down_rightApp", "action.down_right.app", "") newPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_down_rightApp_user", "action.down_right.user", -1) "action_down_leftApp",
migrateStringPreference(oldPrefs, newPrefs, "action_doubleDownApp", "action.double_down.app", "") "action.down_left.app",
migrateIntPreference(oldPrefs, newPrefs, "action_doubleDownApp_user", "action.double_down.user", -1) ""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_down_leftApp_user",
"action.down_left.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_down_rightApp",
"action.down_right.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_down_rightApp_user",
"action.down_right.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_doubleDownApp",
"action.double_down.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_doubleDownApp_user",
"action.double_down.user",
-1
)
migrateStringPreference(oldPrefs, newPrefs, "action_leftApp", "action.left.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_leftApp", "action.left.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_leftApp_user", "action.left.user", -1) migrateIntPreference(oldPrefs, newPrefs, "action_leftApp_user", "action.left.user", -1)
migrateStringPreference(oldPrefs, newPrefs, "action_left_topApp", "action.left_top.app", "") migrateStringPreference(
migrateIntPreference(oldPrefs, newPrefs, "action_left_topApp_user", "action.left_top.user", -1) oldPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_left_bottomApp", "action.left_bottom.app", "") newPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_left_bottomApp_user", "action.left_bottom.user", -1) "action_left_topApp",
migrateStringPreference(oldPrefs, newPrefs, "action_doubleLeftApp", "action.double_left.app", "") "action.left_top.app",
migrateIntPreference(oldPrefs, newPrefs, "action_doubleLeftApp_user", "action.double_left.user", -1) ""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_left_topApp_user",
"action.left_top.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_left_bottomApp",
"action.left_bottom.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_left_bottomApp_user",
"action.left_bottom.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_doubleLeftApp",
"action.double_left.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_doubleLeftApp_user",
"action.double_left.user",
-1
)
migrateStringPreference(oldPrefs, newPrefs, "action_rightApp", "action.right.app", "") migrateStringPreference(oldPrefs, newPrefs, "action_rightApp", "action.right.app", "")
migrateIntPreference(oldPrefs, newPrefs, "action_rightApp_user", "action.right.user", -1) migrateIntPreference(
migrateStringPreference(oldPrefs, newPrefs, "action_right_topApp", "action.right_top.app", "") oldPrefs,
migrateIntPreference(oldPrefs, newPrefs, "action_right_topApp_user", "action.right_top.user", -1) newPrefs,
migrateStringPreference(oldPrefs, newPrefs, "action_right_bottomApp", "action.right_bottom.app", "") "action_rightApp_user",
migrateIntPreference(oldPrefs, newPrefs, "action_right_bottomApp_user", "action.right_bottom.user", -1) "action.right.user",
migrateStringPreference(oldPrefs, newPrefs, "action_doubleRightApp", "action.double_right.app", "") -1
migrateIntPreference(oldPrefs, newPrefs, "action_doubleRightApp_user", "action.double_right.user", -1) )
migrateStringPreference(
oldPrefs,
newPrefs,
"action_right_topApp",
"action.right_top.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_right_topApp_user",
"action.right_top.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_right_bottomApp",
"action.right_bottom.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_right_bottomApp_user",
"action.right_bottom.user",
-1
)
migrateStringPreference(
oldPrefs,
newPrefs,
"action_doubleRightApp",
"action.double_right.app",
""
)
migrateIntPreference(
oldPrefs,
newPrefs,
"action_doubleRightApp_user",
"action.double_right.user",
-1
)
migrateBooleanPreference(oldPrefs, newPrefs, "timeVisible", "clock.time_visible", true) migrateBooleanPreference(oldPrefs, newPrefs, "timeVisible", "clock.time_visible", true)
migrateBooleanPreference(oldPrefs, newPrefs, "dateVisible", "clock.date_visible", true) migrateBooleanPreference(oldPrefs, newPrefs, "dateVisible", "clock.date_visible", true)
migrateBooleanPreference(oldPrefs, newPrefs, "dateLocalized", "clock.date_localized", false) migrateBooleanPreference(
migrateBooleanPreference(oldPrefs, newPrefs, "dateTimeFlip", "clock.date_time_flip", false) oldPrefs,
migrateBooleanPreference(oldPrefs, newPrefs, "disableTimeout", "display.disable_timeout", false) newPrefs,
migrateBooleanPreference(oldPrefs, newPrefs, "useFullScreen", "display.use_full_screen", true) "dateLocalized",
migrateBooleanPreference(oldPrefs, newPrefs, "enableDoubleActions", "enabled_gestures.double_actions", true) "clock.date_localized",
migrateBooleanPreference(oldPrefs, newPrefs, "enableEdgeActions", "enabled_gestures.edge_actions", true) false
migrateBooleanPreference(oldPrefs, newPrefs, "searchAutoLaunch", "functionality.search_auto_launch", true) )
migrateBooleanPreference(oldPrefs, newPrefs, "searchAutoKeyboard", "functionality.search_auto_keyboard", true) migrateBooleanPreference(
oldPrefs,
newPrefs,
"dateTimeFlip",
"clock.date_time_flip",
false
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"disableTimeout",
"display.disable_timeout",
false
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"useFullScreen",
"display.use_full_screen",
true
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"enableDoubleActions",
"enabled_gestures.double_actions",
true
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"enableEdgeActions",
"enabled_gestures.edge_actions",
true
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"searchAutoLaunch",
"functionality.search_auto_launch",
true
)
migrateBooleanPreference(
oldPrefs,
newPrefs,
"searchAutoKeyboard",
"functionality.search_auto_keyboard",
true
)
newPrefs.apply() newPrefs.apply()
@ -113,6 +389,7 @@ fun migratePreferencesToNewVersion(context: Context) {
LauncherPreferences.theme().monochromeIcons(false) LauncherPreferences.theme().monochromeIcons(false)
LauncherPreferences.theme().background(Background.BLUR) LauncherPreferences.theme().background(Background.BLUR)
} }
"dark" -> { "dark" -> {
LauncherPreferences.theme().colorTheme(ColorTheme.DARK) LauncherPreferences.theme().colorTheme(ColorTheme.DARK)
LauncherPreferences.theme().monochromeIcons(true) LauncherPreferences.theme().monochromeIcons(true)
@ -127,6 +404,7 @@ fun migratePreferencesToNewVersion(context: Context) {
// show the new tutorial // show the new tutorial
// context.startActivity(Intent(context, TutorialActivity::class.java)) // context.startActivity(Intent(context, TutorialActivity::class.java))
} }
else -> {} else -> {}
} }
} }
@ -135,8 +413,6 @@ fun resetPreferences(context: Context) {
Log.i(TAG, "resetting preferences") Log.i(TAG, "resetting preferences")
LauncherPreferences.clear() LauncherPreferences.clear()
LauncherPreferences.internal().versionCode(PREFERENCE_VERSION) LauncherPreferences.internal().versionCode(PREFERENCE_VERSION)
val editor = LauncherPreferences.getSharedPreferences().edit()
Gesture.values().forEach { editor.putString(it.id + ".app", it.pickDefaultApp(context)) } Action.resetToDefaultActions(context)
Gesture.values().forEach { editor.putInt(it.id + ".user", -1) }
editor.apply()
} }

View file

@ -1,29 +1,32 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher.ui
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Resources import android.content.res.Resources
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.GestureDetector import android.view.GestureDetector
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import de.jrpie.android.launcher.R
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.databinding.HomeBinding
import de.jrpie.android.launcher.list.other.LauncherAction import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.openTutorial
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.tutorial.TutorialActivity 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.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.fixedRateTimer
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import android.util.DisplayMetrics
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
import de.jrpie.android.launcher.preferences.resetPreferences
/** /**
@ -46,7 +49,8 @@ class HomeActivity: UIObject, AppCompatActivity(),
private var sharedPreferencesListener = private var sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
if (prefKey?.startsWith("clock.") == true || if (prefKey?.startsWith("clock.") == true ||
prefKey?.startsWith("display.") == true) { prefKey?.startsWith("display.") == true
) {
recreate() recreate()
} }
} }
@ -70,7 +74,7 @@ class HomeActivity: UIObject, AppCompatActivity(),
resetPreferences(this) resetPreferences(this)
LauncherPreferences.internal().started(true) LauncherPreferences.internal().started(true)
startActivity(Intent(this, TutorialActivity::class.java)) openTutorial(this)
} }
// Preload apps to speed up the Apps Recycler // Preload apps to speed up the Apps Recycler
@ -90,7 +94,8 @@ class HomeActivity: UIObject, AppCompatActivity(),
super<UIObject>.onStart() super<UIObject>.onStart()
LauncherPreferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
} }
private fun updateClock() { private fun updateClock() {
@ -162,7 +167,8 @@ class HomeActivity: UIObject, AppCompatActivity(),
} }
override fun onDestroy() { override fun onDestroy() {
LauncherPreferences.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
super.onDestroy() super.onDestroy()
} }
@ -180,7 +186,6 @@ class HomeActivity: UIObject, AppCompatActivity(),
if (e1 == null) return false if (e1 == null) return false
val displayMetrics: DisplayMetrics? = DisplayMetrics() val displayMetrics: DisplayMetrics? = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics) windowManager.defaultDisplay.getMetrics(displayMetrics)
@ -257,7 +262,11 @@ class HomeActivity: UIObject, AppCompatActivity(),
} }
} }
return if (mDetector.onTouchEvent(event)) { false } else { super.onTouchEvent(event) } return if (mDetector.onTouchEvent(event)) {
false
} else {
super.onTouchEvent(event)
}
} }
override fun setOnClicks() { override fun setOnClicks() {
@ -281,11 +290,22 @@ class HomeActivity: UIObject, AppCompatActivity(),
/* TODO: Remove those. For now they are necessary /* TODO: Remove those. For now they are necessary
* because this inherits from GestureDetector.OnGestureListener */ * because this inherits from GestureDetector.OnGestureListener */
override fun onDoubleTapEvent(event: MotionEvent): Boolean { return false } override fun onDoubleTapEvent(event: MotionEvent): Boolean {
override fun onDown(event: MotionEvent): Boolean { return false } return false
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, dX: Float, dY: Float): Boolean { return false } }
override fun onDown(event: MotionEvent): Boolean {
return false
}
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, dX: Float, dY: Float): Boolean {
return false
}
override fun onShowPress(event: MotionEvent) {} override fun onShowPress(event: MotionEvent) {}
override fun onSingleTapUp(event: MotionEvent): Boolean { return false } override fun onSingleTapUp(event: MotionEvent): Boolean {
return false
}
override fun isHomeScreen(): Boolean { override fun isHomeScreen(): Boolean {
return true return true

View file

@ -1,9 +1,8 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher.ui
import android.app.Activity import android.app.Activity
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.res.Resources import android.content.res.Resources
import android.os.Build
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
@ -51,6 +50,7 @@ interface UIObject {
setOnClicks() setOnClicks()
adjustLayout() adjustLayout()
} }
fun modifyTheme(theme: Resources.Theme): Resources.Theme { fun modifyTheme(theme: Resources.Theme): Resources.Theme {
LauncherPreferences.theme().colorTheme().applyToTheme(theme) LauncherPreferences.theme().colorTheme().applyToTheme(theme)
LauncherPreferences.theme().background().applyToTheme(theme) LauncherPreferences.theme().background().applyToTheme(theme)

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.list package de.jrpie.android.launcher.ui.list
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
@ -17,12 +17,12 @@ import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
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.UIObject import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.databinding.ListBinding import de.jrpie.android.launcher.databinding.ListBinding
import de.jrpie.android.launcher.list.apps.ListFragmentApps
import de.jrpie.android.launcher.list.other.LauncherAction
import de.jrpie.android.launcher.list.other.ListFragmentOther
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.list.apps.ListFragmentApps
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)
@ -44,6 +44,7 @@ class ListActivity : AppCompatActivity(), UIObject {
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 */
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -66,7 +67,8 @@ class ListActivity : AppCompatActivity(), UIObject {
binding.listContainer.context.resources.displayMetrics.heightPixels binding.listContainer.context.resources.displayMetrics.heightPixels
val diff = height - r.bottom val diff = height - r.bottom
if (diff != 0 && if (diff != 0 &&
LauncherPreferences.display().fullScreen()) { LauncherPreferences.display().fullScreen()
) {
if (binding.listContainer.paddingBottom !== diff) { if (binding.listContainer.paddingBottom !== diff) {
binding.listContainer.setPadding(0, 0, 0, diff) binding.listContainer.setPadding(0, 0, 0, diff)
} }
@ -146,8 +148,8 @@ private val TAB_TITLES = arrayOf(
* The [ListSectionsPagerAdapter] returns the fragment, * The [ListSectionsPagerAdapter] returns the fragment,
* which corresponds to the selected tab in [ListActivity]. * which corresponds to the selected tab in [ListActivity].
*/ */
class ListSectionsPagerAdapter(private val context: Context, fm: FragmentManager) class ListSectionsPagerAdapter(private val context: Context, fm: FragmentManager) :
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
return when (position) { return when (position) {

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.list.apps package de.jrpie.android.launcher.ui.list.apps
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
@ -14,14 +14,14 @@ import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.actions.AppAction
import de.jrpie.android.launcher.actions.AppInfo
import de.jrpie.android.launcher.appsList import de.jrpie.android.launcher.appsList
import de.jrpie.android.launcher.launch
import de.jrpie.android.launcher.launchApp
import de.jrpie.android.launcher.list.ListActivity
import de.jrpie.android.launcher.loadApps import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.openAppSettings import de.jrpie.android.launcher.openAppSettings
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.transformGrayscale import de.jrpie.android.launcher.transformGrayscale
import de.jrpie.android.launcher.ui.list.ListActivity
import de.jrpie.android.launcher.uninstallApp import de.jrpie.android.launcher.uninstallApp
import java.util.* import java.util.*
import kotlin.text.Regex.Companion.escapeReplacement import kotlin.text.Regex.Companion.escapeReplacement
@ -34,10 +34,12 @@ import kotlin.text.Regex.Companion.escapeReplacement
* @param intention - why the list is displayed ("view", "pick") * @param intention - why the list is displayed ("view", "pick")
* @param forGesture - the action which an app is chosen for (when the intention is "pick") * @param forGesture - the action which an app is chosen for (when the intention is "pick")
*/ */
class AppsRecyclerAdapter(val activity: Activity, class AppsRecyclerAdapter(
val activity: Activity,
private val intention: ListActivity.ListActivityIntention private val intention: ListActivity.ListActivityIntention
= ListActivity.ListActivityIntention.VIEW, = ListActivity.ListActivityIntention.VIEW,
private val forGesture: String? = ""): private val forGesture: String? = ""
) :
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() { RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
private val appsListDisplayed: MutableList<AppInfo> private val appsListDisplayed: MutableList<AppInfo>
@ -53,7 +55,9 @@ class AppsRecyclerAdapter(val activity: Activity,
selectItem(adapterPosition, rect) selectItem(adapterPosition, rect)
} }
init { itemView.setOnClickListener(this) } init {
itemView.setOnClickListener(this)
}
} }
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
@ -72,8 +76,22 @@ class AppsRecyclerAdapter(val activity: Activity,
// decide when to show the options popup menu about // decide when to show the options popup menu about
if (intention == ListActivity.ListActivityIntention.VIEW) { if (intention == ListActivity.ListActivityIntention.VIEW) {
viewHolder.textView.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser, isSystemApp) } viewHolder.textView.setOnLongClickListener {
viewHolder.img.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser, isSystemApp) } showOptionsPopup(
viewHolder,
appPackageName,
appUser,
isSystemApp
)
}
viewHolder.img.setOnLongClickListener {
showOptionsPopup(
viewHolder,
appPackageName,
appUser,
isSystemApp
)
}
// ensure onClicks are actually caught // ensure onClicks are actually caught
viewHolder.textView.setOnClickListener { viewHolder.onClick(viewHolder.textView) } viewHolder.textView.setOnClickListener { viewHolder.onClick(viewHolder.textView) }
viewHolder.img.setOnClickListener { viewHolder.onClick(viewHolder.img) } viewHolder.img.setOnClickListener { viewHolder.onClick(viewHolder.img) }
@ -81,7 +99,12 @@ class AppsRecyclerAdapter(val activity: Activity,
} }
@Suppress("SameReturnValue") @Suppress("SameReturnValue")
private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String, user: Int?, isSystemApp: Boolean): Boolean { private fun showOptionsPopup(
viewHolder: ViewHolder,
appPackageName: String,
user: Int?,
isSystemApp: Boolean
): Boolean {
//create the popup menu //create the popup menu
val popup = PopupMenu(activity, viewHolder.img) val popup = PopupMenu(activity, viewHolder.img)
@ -94,13 +117,15 @@ class AppsRecyclerAdapter(val activity: Activity,
popup.setOnMenuItemClickListener { popup.setOnMenuItemClickListener {
when (it.itemId) { when (it.itemId) {
R.id.app_menu_delete -> { R.id.app_menu_delete -> {
uninstallApp(appPackageName, user, activity) uninstallApp(AppInfo(appPackageName, user), activity)
true true
} }
R.id.app_menu_info -> { R.id.app_menu_info -> {
openAppSettings(appPackageName, user, activity) openAppSettings(AppInfo(appPackageName, user), activity)
true true
} }
else -> false else -> false
} }
} }
@ -109,7 +134,9 @@ class AppsRecyclerAdapter(val activity: Activity,
return true return true
} }
override fun getItemCount(): Int { return appsListDisplayed.size } override fun getItemCount(): Int {
return appsListDisplayed.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
@ -134,16 +161,15 @@ class AppsRecyclerAdapter(val activity: Activity,
if (pos >= appsListDisplayed.size) { if (pos >= appsListDisplayed.size) {
return return
} }
val appPackageName = appsListDisplayed[pos].packageName.toString() val appInfo = appsListDisplayed[pos]
val appUser = appsListDisplayed[pos].user
when (intention) { when (intention) {
ListActivity.ListActivityIntention.VIEW -> { ListActivity.ListActivityIntention.VIEW -> {
launchApp(appPackageName, appUser, activity, rect) AppAction(appInfo).invoke(activity, rect)
} }
ListActivity.ListActivityIntention.PICK -> { ListActivity.ListActivityIntention.PICK -> {
val returnIntent = Intent() val returnIntent = Intent()
returnIntent.putExtra("value", appPackageName) AppAction(appInfo).writeToIntent(returnIntent)
appUser?.let{ returnIntent.putExtra("user", it) }
returnIntent.putExtra("forGesture", forGesture) returnIntent.putExtra("forGesture", forGesture)
activity.setResult(REQUEST_CHOOSE_APP, returnIntent) activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
activity.finish() activity.finish()
@ -187,11 +213,13 @@ class AppsRecyclerAdapter(val activity: Activity,
} }
if (appsListDisplayed.size == 1 && intention == ListActivity.ListActivityIntention.VIEW if (appsListDisplayed.size == 1 && intention == ListActivity.ListActivityIntention.VIEW
&& LauncherPreferences.functionality().searchAutoLaunch()) { && LauncherPreferences.functionality().searchAutoLaunch()
) {
val info = appsListDisplayed[0] val info = appsListDisplayed[0]
launch(info.packageName.toString(), info.user, activity) AppAction(info).invoke(activity)
val inputMethodManager = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager val inputMethodManager =
activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(View(activity).windowToken, 0) inputMethodManager.hideSoftInputFromWindow(View(activity).windowToken, 0)
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.list.apps package de.jrpie.android.launcher.ui.list.apps
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,13 +6,13 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.databinding.ListAppsBinding import de.jrpie.android.launcher.databinding.ListAppsBinding
import de.jrpie.android.launcher.list.ListActivity
import de.jrpie.android.launcher.list.forGesture
import de.jrpie.android.launcher.list.intention
import de.jrpie.android.launcher.openSoftKeyboard import de.jrpie.android.launcher.openSoftKeyboard
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.list.ListActivity
import de.jrpie.android.launcher.ui.list.forGesture
import de.jrpie.android.launcher.ui.list.intention
/** /**
@ -66,7 +66,8 @@ class ListFragmentApps : Fragment(), UIObject {
}) })
if (intention == ListActivity.ListActivityIntention.VIEW if (intention == ListActivity.ListActivityIntention.VIEW
&& LauncherPreferences.functionality().searchAutoOpenKeyboard()){ && LauncherPreferences.functionality().searchAutoOpenKeyboard()
) {
openSoftKeyboard(requireContext(), binding.listAppsSearchview) openSoftKeyboard(requireContext(), binding.listAppsSearchview)
} }
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.list.other package de.jrpie.android.launcher.ui.list.other
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,7 +6,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.databinding.ListOtherBinding import de.jrpie.android.launcher.databinding.ListOtherBinding
/** /**

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.list.other package de.jrpie.android.launcher.ui.list.other
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
@ -8,10 +8,10 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.INVALID_USER
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.list.forGesture import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.ui.list.forGesture
/** /**
* The [OtherRecyclerAdapter] will only be displayed in the ListActivity, * The [OtherRecyclerAdapter] will only be displayed in the ListActivity,
@ -35,10 +35,12 @@ class OtherRecyclerAdapter(val activity: Activity):
val pos = adapterPosition val pos = adapterPosition
val content = othersList[pos] val content = othersList[pos]
forGesture?.let { returnChoiceIntent(it, content.id) } forGesture?.let { returnChoiceIntent(it, content) }
} }
init { itemView.setOnClickListener(this) } init {
itemView.setOnClickListener(this)
}
} }
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
@ -49,7 +51,9 @@ class OtherRecyclerAdapter(val activity: Activity):
viewHolder.iconView.setImageResource(icon) viewHolder.iconView.setImageResource(icon)
} }
override fun getItemCount(): Int { return othersList.size } override fun getItemCount(): Int {
return othersList.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
@ -57,11 +61,10 @@ class OtherRecyclerAdapter(val activity: Activity):
return ViewHolder(view) return ViewHolder(view)
} }
private fun returnChoiceIntent(forGesture: String, value: String) { private fun returnChoiceIntent(forGesture: String, action: LauncherAction) {
val returnIntent = Intent() val returnIntent = Intent()
returnIntent.putExtra("value", value)
returnIntent.putExtra("forGesture", forGesture) returnIntent.putExtra("forGesture", forGesture)
returnIntent.putExtra("user", INVALID_USER) action.writeToIntent(returnIntent)
activity.setResult(REQUEST_CHOOSE_APP, returnIntent) activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
activity.finish() activity.finish()
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.settings package de.jrpie.android.launcher.ui.settings
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -7,17 +7,20 @@ import android.content.res.Resources
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.ViewPager
import de.jrpie.android.launcher.*
import com.google.android.material.tabs.TabLayout
import de.jrpie.android.launcher.databinding.SettingsBinding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.databinding.SettingsBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.settings.actions.SettingsFragmentActions import de.jrpie.android.launcher.saveListActivityChoice
import de.jrpie.android.launcher.settings.launcher.SettingsFragmentLauncher import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.settings.meta.SettingsFragmentMeta import de.jrpie.android.launcher.ui.settings.actions.SettingsFragmentActions
import de.jrpie.android.launcher.ui.settings.launcher.SettingsFragmentLauncher
import de.jrpie.android.launcher.ui.settings.meta.SettingsFragmentMeta
/** /**
* The [SettingsActivity] is a tabbed activity: * The [SettingsActivity] is a tabbed activity:
@ -33,7 +36,8 @@ class SettingsActivity: AppCompatActivity(), UIObject {
private var sharedPreferencesListener = private var sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
if (prefKey?.startsWith("theme.") == true || if (prefKey?.startsWith("theme.") == true ||
prefKey?.startsWith("display.") == true) { prefKey?.startsWith("display.") == true
) {
recreate() recreate()
} }
} }
@ -58,11 +62,13 @@ class SettingsActivity: AppCompatActivity(), UIObject {
override fun onStart() { override fun onStart() {
super<AppCompatActivity>.onStart() super<AppCompatActivity>.onStart()
super<UIObject>.onStart() super<UIObject>.onStart()
LauncherPreferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
} }
override fun onPause() { override fun onPause() {
LauncherPreferences.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
super.onPause() super.onPause()
} }
@ -81,7 +87,7 @@ class SettingsActivity: AppCompatActivity(), UIObject {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) { when (requestCode) {
REQUEST_CHOOSE_APP -> saveListActivityChoice(this, data) REQUEST_CHOOSE_APP -> saveListActivityChoice(data)
else -> super.onActivityResult(requestCode, resultCode, data) else -> super.onActivityResult(requestCode, resultCode, data)
} }
} }
@ -93,8 +99,8 @@ private val TAB_TITLES = arrayOf(
R.string.settings_tab_meta R.string.settings_tab_meta
) )
class SettingsSectionsPagerAdapter(private val context: Context, fm: FragmentManager) class SettingsSectionsPagerAdapter(private val context: Context, fm: FragmentManager) :
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
return when (position) { return when (position) {
@ -109,5 +115,7 @@ class SettingsSectionsPagerAdapter(private val context: Context, fm: FragmentMan
return context.resources.getString(TAB_TITLES[position]) return context.resources.getString(TAB_TITLES[position])
} }
override fun getCount(): Int { return 3 } override fun getCount(): Int {
return 3
}
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.settings.actions package de.jrpie.android.launcher.ui.settings.actions
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
@ -9,9 +9,9 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.databinding.SettingsActionsBinding import de.jrpie.android.launcher.databinding.SettingsActionsBinding
import de.jrpie.android.launcher.list.ListActivity import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.list.ListActivity
/** /**
@ -55,7 +55,11 @@ SettingsFragmentActions : Fragment(), UIObject {
intent.addCategory(Intent.CATEGORY_APP_MARKET) intent.addCategory(Intent.CATEGORY_APP_MARKET)
startActivity(intent) startActivity(intent)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Toast.makeText(context, getString(R.string.settings_apps_toast_store_not_found), Toast.LENGTH_SHORT).show() Toast.makeText(
context,
getString(R.string.settings_apps_toast_store_not_found),
Toast.LENGTH_SHORT
).show()
} }
} }
} }

View file

@ -1,24 +1,27 @@
package de.jrpie.android.launcher.settings.actions package de.jrpie.android.launcher.ui.settings.actions
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import de.jrpie.android.launcher.*
import de.jrpie.android.launcher.list.ListActivity
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.widget.Button import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.list.other.LauncherAction import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.databinding.SettingsActionsRecyclerBinding import de.jrpie.android.launcher.databinding.SettingsActionsRecyclerBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import java.lang.Exception import de.jrpie.android.launcher.transformGrayscale
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.list.ListActivity
/** /**
* The [SettingsFragmentActionsRecycler] is a fragment containing the [ActionsRecyclerAdapter], * The [SettingsFragmentActionsRecycler] is a fragment containing the [ActionsRecyclerAdapter],
@ -56,13 +59,15 @@ class SettingsFragmentActionsRecycler : Fragment(), UIObject {
layoutManager = actionViewManager layoutManager = actionViewManager
adapter = actionViewAdapter adapter = actionViewAdapter
} }
LauncherPreferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
super<UIObject>.onStart() super<UIObject>.onStart()
} }
override fun onDestroy() { override fun onDestroy() {
LauncherPreferences.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
super.onDestroy() super.onDestroy()
} }
@ -82,36 +87,26 @@ class ActionsRecyclerAdapter(val activity: Activity):
override fun onClick(v: View) {} override fun onClick(v: View) {}
init { itemView.setOnClickListener(this) } init {
itemView.setOnClickListener(this)
}
} }
private fun updateViewHolder(gesture: Gesture, viewHolder: ViewHolder) { private fun updateViewHolder(gesture: Gesture, viewHolder: ViewHolder) {
val app = gesture.getApp(activity) val action = Action.forGesture(gesture)
val content = app.first val drawable = action?.getIcon(activity)
if (action == null || drawable == null) {
viewHolder.img.visibility = View.INVISIBLE
viewHolder.removeAction.visibility = View.GONE
viewHolder.chooseButton.visibility = View.VISIBLE
return
}
viewHolder.img.visibility = View.VISIBLE viewHolder.img.visibility = View.VISIBLE
viewHolder.removeAction.visibility = View.VISIBLE viewHolder.removeAction.visibility = View.VISIBLE
viewHolder.chooseButton.visibility = View.INVISIBLE viewHolder.chooseButton.visibility = View.INVISIBLE
if (content.isEmpty()){ viewHolder.img.setImageDrawable(drawable)
viewHolder.img.visibility = View.INVISIBLE
viewHolder.removeAction.visibility = View.GONE
viewHolder.chooseButton.visibility = View.VISIBLE
}
else if (LauncherAction.isOtherAction(content)) {
LauncherAction.byId(content)?.let {
viewHolder.img.setImageResource(it.icon)
}
} else {
// Set image icon (by packageName)
try {
viewHolder.img.setImageDrawable(getAppIcon(activity, content, app.second))
} catch (e : Exception) {
// Probably the app was uninstalled
// the button is shown, user asked to select an action
viewHolder.img.visibility = View.INVISIBLE
viewHolder.removeAction.visibility = View.GONE
viewHolder.chooseButton.visibility = View.VISIBLE
}
}
} }
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
@ -122,10 +117,12 @@ class ActionsRecyclerAdapter(val activity: Activity):
updateViewHolder(gesture, viewHolder) updateViewHolder(gesture, viewHolder)
viewHolder.img.setOnClickListener { chooseApp(gesture) } viewHolder.img.setOnClickListener { chooseApp(gesture) }
viewHolder.chooseButton.setOnClickListener { chooseApp(gesture) } viewHolder.chooseButton.setOnClickListener { chooseApp(gesture) }
viewHolder.removeAction.setOnClickListener{ gesture.removeApp(activity) } viewHolder.removeAction.setOnClickListener { Action.clearActionForGesture(gesture) }
} }
override fun getItemCount(): Int { return gesturesList.size } override fun getItemCount(): Int {
return gesturesList.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
@ -138,7 +135,8 @@ class ActionsRecyclerAdapter(val activity: Activity):
val edgeActions = LauncherPreferences.enabled_gestures().edgeSwipe() val edgeActions = LauncherPreferences.enabled_gestures().edgeSwipe()
gesturesList = Gesture.values().filter { gesturesList = Gesture.values().filter {
(doubleActions || !it.isDoubleVariant()) (doubleActions || !it.isDoubleVariant())
&& (edgeActions || !it.isEdgeVariant())} as ArrayList<Gesture> && (edgeActions || !it.isEdgeVariant())
} as ArrayList<Gesture>
} }
fun updateActions() { fun updateActions() {
@ -147,7 +145,8 @@ class ActionsRecyclerAdapter(val activity: Activity):
this.gesturesList.clear() this.gesturesList.clear()
gesturesList.addAll(Gesture.values().filter { gesturesList.addAll(Gesture.values().filter {
(doubleActions || !it.isDoubleVariant()) (doubleActions || !it.isDoubleVariant())
&& (edgeActions || !it.isEdgeVariant())}) && (edgeActions || !it.isEdgeVariant())
})
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -157,7 +156,8 @@ class ActionsRecyclerAdapter(val activity: Activity):
val intent = Intent(activity, ListActivity::class.java) val intent = Intent(activity, ListActivity::class.java)
intent.putExtra("intention", ListActivity.ListActivityIntention.PICK.toString()) intent.putExtra("intention", ListActivity.ListActivityIntention.PICK.toString())
intent.putExtra("forGesture", gesture.id) // for which action we choose the app intent.putExtra("forGesture", gesture.id) // for which action we choose the app
activity.startActivityForResult(intent, activity.startActivityForResult(
intent,
REQUEST_CHOOSE_APP REQUEST_CHOOSE_APP
) )
} }

View file

@ -1,12 +1,11 @@
package de.jrpie.android.launcher.settings.launcher package de.jrpie.android.launcher.ui.settings.launcher
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.setDefaultHomeScreen import de.jrpie.android.launcher.setDefaultHomeScreen
@ -35,11 +34,13 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
LauncherPreferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
} }
override fun onPause() { override fun onPause() {
LauncherPreferences.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) LauncherPreferences.getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
super.onPause() super.onPause()
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.settings.meta package de.jrpie.android.launcher.ui.settings.meta
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent import android.content.Intent
@ -9,11 +9,11 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.openNewTabWindow
import de.jrpie.android.launcher.tutorial.TutorialActivity
import de.jrpie.android.launcher.databinding.SettingsMetaBinding import de.jrpie.android.launcher.databinding.SettingsMetaBinding
import de.jrpie.android.launcher.openNewTabWindow
import de.jrpie.android.launcher.preferences.resetPreferences import de.jrpie.android.launcher.preferences.resetPreferences
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
/** /**
* The [SettingsFragmentMeta] is a used as a tab in the SettingsActivity. * The [SettingsFragmentMeta] is a used as a tab in the SettingsActivity.
@ -65,7 +65,8 @@ class SettingsFragmentMeta : Fragment(), UIObject {
AlertDialog.Builder(this.requireContext(), R.style.AlertDialogCustom) AlertDialog.Builder(this.requireContext(), R.style.AlertDialogCustom)
.setTitle(getString(R.string.settings_meta_reset)) .setTitle(getString(R.string.settings_meta_reset))
.setMessage(getString(R.string.settings_meta_reset_confirm)) .setMessage(getString(R.string.settings_meta_reset_confirm))
.setPositiveButton(android.R.string.ok .setPositiveButton(
android.R.string.ok
) { _, _ -> ) { _, _ ->
resetPreferences(this.requireContext()) resetPreferences(this.requireContext())
requireActivity().finish() requireActivity().finish()
@ -85,7 +86,6 @@ class SettingsFragmentMeta : Fragment(), UIObject {
} }
// contact developer // contact developer
binding.settingsMetaButtonContact.setOnClickListener { binding.settingsMetaButtonContact.setOnClickListener {
openNewTabWindow( openNewTabWindow(

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.tutorial package de.jrpie.android.launcher.ui.tutorial
import android.content.Intent import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
@ -9,16 +9,16 @@ 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.preferences.LauncherPreferences
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.UIObject import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.saveListActivityChoice import de.jrpie.android.launcher.saveListActivityChoice
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentConcept import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentFinish import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentConcept
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentSetup import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentFinish
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentStart import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentSetup
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentUsage import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentStart
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentUsage
/** /**
* The [TutorialActivity] is displayed automatically on new installations. * The [TutorialActivity] is displayed automatically on new installations.
@ -54,7 +54,7 @@ class TutorialActivity: AppCompatActivity(), UIObject {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) { when (requestCode) {
REQUEST_CHOOSE_APP -> saveListActivityChoice(this,data) REQUEST_CHOOSE_APP -> saveListActivityChoice(data)
else -> super.onActivityResult(requestCode, resultCode, data) else -> super.onActivityResult(requestCode, resultCode, data)
} }
} }
@ -73,8 +73,8 @@ class TutorialActivity: AppCompatActivity(), UIObject {
* *
* Tabs: (Start | Concept | Usage | Setup | Finish) * Tabs: (Start | Concept | Usage | Setup | Finish)
*/ */
class TutorialSectionsPagerAdapter(fm: FragmentManager) class TutorialSectionsPagerAdapter(fm: FragmentManager) :
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
return when (position) { return when (position) {
@ -88,6 +88,11 @@ class TutorialSectionsPagerAdapter(fm: FragmentManager)
} }
/* We don't use titles here, as we have the dots */ /* We don't use titles here, as we have the dots */
override fun getPageTitle(position: Int): CharSequence { return "" } override fun getPageTitle(position: Int): CharSequence {
override fun getCount(): Int { return 5 } return ""
}
override fun getCount(): Int {
return 5
}
} }

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,8 +6,9 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.BuildConfig import de.jrpie.android.launcher.BuildConfig
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.databinding.TutorialConceptBinding import de.jrpie.android.launcher.databinding.TutorialConceptBinding
import de.jrpie.android.launcher.ui.UIObject
/** /**
* The [TutorialFragmentConcept] is a used as a tab in the TutorialActivity. * The [TutorialFragmentConcept] is a used as a tab in the TutorialActivity.
* *

View file

@ -1,14 +1,15 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import de.jrpie.android.launcher.* import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.BuildConfig.VERSION_CODE import de.jrpie.android.launcher.BuildConfig.VERSION_CODE
import de.jrpie.android.launcher.databinding.TutorialFinishBinding import de.jrpie.android.launcher.databinding.TutorialFinishBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.setDefaultHomeScreen
import de.jrpie.android.launcher.ui.UIObject
/** /**
* The [TutorialFragmentFinish] is a used as a tab in the TutorialActivity. * The [TutorialFragmentFinish] is a used as a tab in the TutorialActivity.

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject import de.jrpie.android.launcher.ui.UIObject
/** /**
* The [TutorialFragmentSetup] is a used as a tab in the TutorialActivity. * The [TutorialFragmentSetup] is a used as a tab in the TutorialActivity.

View file

@ -1,12 +1,13 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import de.jrpie.android.launcher.* import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.blink
import de.jrpie.android.launcher.databinding.TutorialStartBinding import de.jrpie.android.launcher.databinding.TutorialStartBinding
import de.jrpie.android.launcher.ui.UIObject
/** /**
* The [TutorialFragmentStart] is a used as a tab in the TutorialActivity. * The [TutorialFragmentStart] is a used as a tab in the TutorialActivity.

View file

@ -1,4 +1,4 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject import de.jrpie.android.launcher.ui.UIObject
/** /**
* The [TutorialFragmentUsage] is a used as a tab in the TutorialActivity. * The [TutorialFragmentUsage] is a used as a tab in the TutorialActivity.

View file

@ -7,7 +7,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:longClickable="false" android:longClickable="false"
tools:context=".HomeActivity"> tools:context=".ui.HomeActivity">
<TextView <TextView
android:id="@+id/home_upper_view" android:id="@+id/home_upper_view"

View file

@ -8,7 +8,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context=".list.ListActivity"> tools:context=".ui.list.ListActivity">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/list_appbar" android:id="@+id/list_appbar"

View file

@ -7,7 +7,7 @@
android:id="@+id/settings_container" android:id="@+id/settings_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".settings.SettingsActivity"> tools:context=".ui.settings.SettingsActivity">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/settings_appbar" android:id="@+id/settings_appbar"

View file

@ -10,7 +10,7 @@
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_actions_rview_fragment" android:id="@+id/settings_actions_rview_fragment"
android:name="de.jrpie.android.launcher.settings.actions.SettingsFragmentActionsRecycler" android:name="de.jrpie.android.launcher.ui.settings.actions.SettingsFragmentActionsRecycler"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"

View file

@ -11,7 +11,7 @@
android:paddingLeft="32sp" android:paddingLeft="32sp"
android:paddingTop="16sp" android:paddingTop="16sp"
android:paddingRight="32sp" android:paddingRight="32sp"
tools:context=".settings.meta.SettingsFragmentMeta"> tools:context=".ui.settings.meta.SettingsFragmentMeta">
<Button <Button
android:id="@+id/settings_meta_button_view_tutorial" android:id="@+id/settings_meta_button_view_tutorial"

View file

@ -7,7 +7,7 @@
android:id="@+id/tutorial_container" android:id="@+id/tutorial_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".tutorial.TutorialActivity"> tools:context=".ui.tutorial.TutorialActivity">
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager

View file

@ -8,7 +8,7 @@
android:paddingRight="32sp" android:paddingRight="32sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".tutorial.tabs.TutorialFragmentConcept"> tools:context=".ui.tutorial.tabs.TutorialFragmentConcept">
<TextView <TextView
android:id="@+id/tutorial_concept_title" android:id="@+id/tutorial_concept_title"

View file

@ -9,7 +9,7 @@
android:paddingRight="32sp" android:paddingRight="32sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".tutorial.tabs.TutorialFragmentFinish"> tools:context=".ui.tutorial.tabs.TutorialFragmentFinish">
<TextView <TextView
android:id="@+id/tutorial_finish_title" android:id="@+id/tutorial_finish_title"

View file

@ -8,7 +8,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingLeft="32sp" android:paddingLeft="32sp"
android:paddingRight="32sp" android:paddingRight="32sp"
tools:context=".tutorial.tabs.TutorialFragmentSetup"> tools:context=".ui.tutorial.tabs.TutorialFragmentSetup">
<TextView <TextView
android:id="@+id/tutorial_setup_title" android:id="@+id/tutorial_setup_title"
@ -35,7 +35,7 @@
<fragment <fragment
android:id="@+id/tutorial_setup_actions_rview_fragment" android:id="@+id/tutorial_setup_actions_rview_fragment"
android:name="de.jrpie.android.launcher.settings.actions.SettingsFragmentActionsRecycler" android:name="de.jrpie.android.launcher.ui.settings.actions.SettingsFragmentActionsRecycler"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"

View file

@ -8,7 +8,7 @@
android:paddingRight="32sp" android:paddingRight="32sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".tutorial.tabs.TutorialFragmentStart"> tools:context=".ui.tutorial.tabs.TutorialFragmentStart">
<TextView <TextView
android:id="@+id/tutorial_start_text" android:id="@+id/tutorial_start_text"

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingLeft="32sp" android:paddingLeft="32sp"
android:paddingRight="32sp" android:paddingRight="32sp"
tools:context=".tutorial.tabs.TutorialFragmentUsage"> tools:context=".ui.tutorial.tabs.TutorialFragmentUsage">
<TextView <TextView
android:id="@+id/tutorial_usage_title" android:id="@+id/tutorial_usage_title"

View file

@ -7,7 +7,7 @@
<string name="alert_cant_open_title">Can\'t open app</string> <string name="alert_cant_open_title">Can\'t open app</string>
<string name="alert_cant_open_message">Want to change its settings?</string> <string name="alert_cant_open_message">Want to change its settings?</string>
<string name="toast_cant_open_message">Open settings to choose an app for this action</string> <string name="toast_cant_open_message">Open settings to choose an action for this gesture</string>
<!-- <!--
- -