mirror of
https://github.com/jrpie/Launcher.git
synced 2025-02-22 22:11:27 +01:00
basic support for pinned shortcuts (see #45)
TODO: Show pinned shortcuts in app list
This commit is contained in:
parent
befa3afc5d
commit
3aee137a3c
30 changed files with 509 additions and 26 deletions
|
@ -95,6 +95,7 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
implementation 'androidx.activity:activity:1.8.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||||
implementation 'androidx.core:core-ktx:1.15.0'
|
implementation 'androidx.core:core-ktx:1.15.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||||
|
|
|
@ -19,6 +19,16 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/launcherBaseTheme"
|
android:theme="@style/launcherBaseTheme"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
<activity
|
||||||
|
android:name=".ui.PinShortcutActivity"
|
||||||
|
android:autoRemoveFromRecents="true"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
|
||||||
|
<action android:name="android.content.pm.action.CONFIRM_PIN_APPWIDGET" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.HomeActivity"
|
android:name=".ui.HomeActivity"
|
||||||
android:clearTaskOnLaunch="true"
|
android:clearTaskOnLaunch="true"
|
||||||
|
|
|
@ -137,6 +137,9 @@ class Application : android.app.Application() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
|
||||||
|
removeUnusedShortcuts(this)
|
||||||
|
}
|
||||||
loadApps()
|
loadApps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.LauncherApps
|
import android.content.pm.LauncherApps
|
||||||
|
import android.content.pm.LauncherApps.ShortcutQuery
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -18,8 +20,11 @@ import android.os.UserManager
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import de.jrpie.android.launcher.actions.Action
|
import de.jrpie.android.launcher.actions.Action
|
||||||
import de.jrpie.android.launcher.actions.Gesture
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
|
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
||||||
import de.jrpie.android.launcher.apps.AppInfo
|
import de.jrpie.android.launcher.apps.AppInfo
|
||||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||||
import de.jrpie.android.launcher.apps.getPrivateSpaceUser
|
import de.jrpie.android.launcher.apps.getPrivateSpaceUser
|
||||||
|
@ -81,6 +86,34 @@ fun getUserFromId(userId: Int?, context: Context): UserHandle {
|
||||||
return profiles.firstOrNull { it.hashCode() == userId } ?: profiles[0]
|
return profiles.firstOrNull { it.hashCode() == userId } ?: profiles[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
|
fun removeUnusedShortcuts(context: Context) {
|
||||||
|
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
fun getShortcuts(profile: UserHandle): List<ShortcutInfo>? {
|
||||||
|
return launcherApps.getShortcuts(
|
||||||
|
ShortcutQuery().apply {
|
||||||
|
setQueryFlags(ShortcutQuery.FLAG_MATCH_PINNED)
|
||||||
|
},
|
||||||
|
profile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||||
|
val boundActions: Set<PinnedShortcutInfo> =
|
||||||
|
Gesture.entries.mapNotNull { Action.forGesture(it) as? ShortcutAction }.map { it.shortcut }
|
||||||
|
.toSet()
|
||||||
|
try {
|
||||||
|
userManager.userProfiles.filter { !userManager.isQuietModeEnabled(it) }.forEach { profile ->
|
||||||
|
getShortcuts(profile)?.groupBy { it.`package` }?.forEach { (p, shortcuts) ->
|
||||||
|
launcherApps.pinShortcuts(p,
|
||||||
|
shortcuts.filter { boundActions.contains(PinnedShortcutInfo(it)) }
|
||||||
|
.map { it.id }.toList(),
|
||||||
|
profile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_: SecurityException) { }
|
||||||
|
}
|
||||||
|
|
||||||
fun openInBrowser(url: String, context: Context) {
|
fun openInBrowser(url: String, context: Context) {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package de.jrpie.android.launcher.actions
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.LauncherApps
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
|
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("action:shortcut")
|
||||||
|
class ShortcutAction(val shortcut: PinnedShortcutInfo) : Action {
|
||||||
|
|
||||||
|
override fun invoke(context: Context, rect: Rect?): Boolean {
|
||||||
|
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||||
|
// TODO
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
shortcut.getShortcutInfo(context)?.let {
|
||||||
|
launcherApps.startShortcut(it, rect, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle null
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun label(context: Context): String {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
return shortcut.getShortcutInfo(context)?.longLabel?.toString() ?: "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(context: Context): Drawable? {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
return shortcut.getShortcutInfo(context)?.let { launcherApps.getShortcutBadgedIconDrawable(it, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isAvailable(context: Context): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return shortcut.getShortcutInfo(context) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canReachSettings(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package de.jrpie.android.launcher.actions.shortcuts
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.LauncherApps
|
||||||
|
import android.content.pm.LauncherApps.ShortcutQuery
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import de.jrpie.android.launcher.getUserFromId
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
|
@Serializable
|
||||||
|
class PinnedShortcutInfo(
|
||||||
|
val id: String,
|
||||||
|
val packageName: String,
|
||||||
|
val activityName: String,
|
||||||
|
val user: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
constructor(info: ShortcutInfo) : this(info.id, info.`package`, info.activity?.className ?: "", info.userHandle.hashCode())
|
||||||
|
|
||||||
|
fun getShortcutInfo(context: Context): ShortcutInfo? {
|
||||||
|
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
|
||||||
|
return launcherApps.getShortcuts(
|
||||||
|
ShortcutQuery().apply {
|
||||||
|
setQueryFlags(ShortcutQuery.FLAG_MATCH_PINNED)
|
||||||
|
setPackage(packageName)
|
||||||
|
setActivity(ComponentName(packageName, activityName))
|
||||||
|
setShortcutIds(listOf(id))
|
||||||
|
},
|
||||||
|
getUserFromId(user, context)
|
||||||
|
)?.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return (other as? PinnedShortcutInfo)?.let {
|
||||||
|
packageName == this.packageName &&
|
||||||
|
activityName == this.activityName &&
|
||||||
|
id == this.id &&
|
||||||
|
user == this.user
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = id.hashCode()
|
||||||
|
result = 31 * result + packageName.hashCode()
|
||||||
|
result = 31 * result + activityName.hashCode()
|
||||||
|
result = 31 * result + user
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "PinnedShortcutInfo { package=$packageName, activity=$activityName, user=$user, id=$id}"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
package de.jrpie.android.launcher.ui
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.LauncherApps
|
||||||
|
import android.content.pm.LauncherApps.PinItemRequest
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import de.jrpie.android.launcher.R
|
||||||
|
import de.jrpie.android.launcher.actions.Action
|
||||||
|
import de.jrpie.android.launcher.actions.Gesture
|
||||||
|
import de.jrpie.android.launcher.actions.ShortcutAction
|
||||||
|
import de.jrpie.android.launcher.actions.shortcuts.PinnedShortcutInfo
|
||||||
|
import de.jrpie.android.launcher.databinding.ActivityPinShortcutBinding
|
||||||
|
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||||
|
|
||||||
|
class PinShortcutActivity : AppCompatActivity(), UIObject {
|
||||||
|
private lateinit var binding: ActivityPinShortcutBinding
|
||||||
|
|
||||||
|
private var isBound = false
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super<AppCompatActivity>.onCreate(savedInstanceState)
|
||||||
|
super<UIObject>.onCreate()
|
||||||
|
enableEdgeToEdge()
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
binding = ActivityPinShortcutBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
val launcherApps = getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||||
|
|
||||||
|
val request = launcherApps.getPinItemRequest(intent)
|
||||||
|
if (request == null || request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.pinShortcutLabel.text = request.shortcutInfo!!.shortLabel ?: "?"
|
||||||
|
binding.pinShortcutLabel.setCompoundDrawables(
|
||||||
|
launcherApps.getShortcutBadgedIconDrawable(request.shortcutInfo, 0).also {
|
||||||
|
val size = (40 * resources.displayMetrics.density).toInt()
|
||||||
|
it.setBounds(0,0, size, size)
|
||||||
|
}, null, null, null)
|
||||||
|
|
||||||
|
binding.pinShortcutButtonBind.setOnClickListener {
|
||||||
|
AlertDialog.Builder(this, R.style.AlertDialogCustom)
|
||||||
|
.setTitle(getString(R.string.pin_shortcut_button_bind))
|
||||||
|
.setView(R.layout.dialog_select_gesture)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.create().also { it.show() }.let { dialog ->
|
||||||
|
val viewManager = LinearLayoutManager(dialog.context)
|
||||||
|
val viewAdapter = GestureRecyclerAdapter (dialog.context) { gesture ->
|
||||||
|
if (!isBound) {
|
||||||
|
isBound = true
|
||||||
|
request.accept()
|
||||||
|
}
|
||||||
|
val editor = LauncherPreferences.getSharedPreferences().edit()
|
||||||
|
ShortcutAction(PinnedShortcutInfo(request.shortcutInfo!!)).bindToGesture(editor, gesture.id)
|
||||||
|
editor.apply()
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
dialog.findViewById<RecyclerView>(R.id.dialog_select_gesture_recycler).apply {
|
||||||
|
setHasFixedSize(true)
|
||||||
|
layoutManager = viewManager
|
||||||
|
adapter = viewAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.pinShortcutClose.setOnClickListener { finish() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super<AppCompatActivity>.onStart()
|
||||||
|
super<UIObject>.onStart()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTheme(): Resources.Theme {
|
||||||
|
return modifyTheme(super.getTheme())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class GestureRecyclerAdapter(val context: Context, val onClick: (Gesture) -> Unit): RecyclerView.Adapter<GestureRecyclerAdapter.ViewHolder>() {
|
||||||
|
val gestures = Gesture.entries.filter { it.isEnabled() }.toList()
|
||||||
|
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val label = itemView.findViewById<TextView>(R.id.dialog_select_gesture_row_name)
|
||||||
|
val description = itemView.findViewById<TextView>(R.id.dialog_select_gesture_row_description)
|
||||||
|
val icon = itemView.findViewById<ImageView>(R.id.dialog_select_gesture_row_icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
val view: View = inflater.inflate(R.layout.dialog_select_gesture_row, parent, false)
|
||||||
|
return ViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val gesture = gestures[position]
|
||||||
|
holder.label.text = gesture.getLabel(context)
|
||||||
|
holder.description.text = gesture.getDescription(context)
|
||||||
|
holder.icon.setImageDrawable(
|
||||||
|
Action.forGesture(gesture)?.getIcon(context)
|
||||||
|
)
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
onClick(gesture)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return gestures.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?android:textColor"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="960"
|
android:viewportWidth="960"
|
||||||
android:viewportHeight="960"
|
android:viewportHeight="960">
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="?android:textColor"
|
android:fillColor="?android:textColor"
|
||||||
android:pathData="M240,880Q207,880 183.5,856.5Q160,833 160,800L160,400Q160,367 183.5,343.5Q207,320 240,320L280,320L280,240Q280,157 338.5,98.5Q397,40 480,40Q563,40 621.5,98.5Q680,157 680,240L680,320L720,320Q753,320 776.5,343.5Q800,367 800,400L800,800Q800,833 776.5,856.5Q753,880 720,880L240,880ZM240,800L720,800Q720,800 720,800Q720,800 720,800L720,400Q720,400 720,400Q720,400 720,400L240,400Q240,400 240,400Q240,400 240,400L240,800Q240,800 240,800Q240,800 240,800ZM480,680Q513,680 536.5,656.5Q560,633 560,600Q560,567 536.5,543.5Q513,520 480,520Q447,520 423.5,543.5Q400,567 400,600Q400,633 423.5,656.5Q447,680 480,680ZM360,320L600,320L600,240Q600,190 565,155Q530,120 480,120Q430,120 395,155Q360,190 360,240L360,320ZM240,800Q240,800 240,800Q240,800 240,800L240,400Q240,400 240,400Q240,400 240,400L240,400Q240,400 240,400Q240,400 240,400L240,800Q240,800 240,800Q240,800 240,800Z"/>
|
android:pathData="M240,880Q207,880 183.5,856.5Q160,833 160,800L160,400Q160,367 183.5,343.5Q207,320 240,320L280,320L280,240Q280,157 338.5,98.5Q397,40 480,40Q563,40 621.5,98.5Q680,157 680,240L680,320L720,320Q753,320 776.5,343.5Q800,367 800,400L800,800Q800,833 776.5,856.5Q753,880 720,880L240,880ZM240,800L720,800Q720,800 720,800Q720,800 720,800L720,400Q720,400 720,400Q720,400 720,400L240,400Q240,400 240,400Q240,400 240,400L240,800Q240,800 240,800Q240,800 240,800ZM480,680Q513,680 536.5,656.5Q560,633 560,600Q560,567 536.5,543.5Q513,520 480,520Q447,520 423.5,543.5Q400,567 400,600Q400,633 423.5,656.5Q447,680 480,680ZM360,320L600,320L600,240Q600,190 565,155Q530,120 480,120Q430,120 395,155Q360,190 360,240L360,320ZM240,800Q240,800 240,800Q240,800 240,800L240,400Q240,400 240,400Q240,400 240,400L240,400Q240,400 240,400Q240,400 240,400L240,800Q240,800 240,800Q240,800 240,800Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?android:textColor" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
<path android:fillColor="?android:textColor" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
<path
|
||||||
|
android:fillColor="?android:textColor"
|
||||||
|
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z" />
|
||||||
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
|
||||||
<path android:fillColor="?android:textColor" android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
<path
|
||||||
|
android:fillColor="?android:textColor"
|
||||||
|
android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
|
||||||
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:width="24dp">
|
android:width="24dp">
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:autoMirrored="true"
|
android:autoMirrored="true"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:autoMirrored="true"
|
android:autoMirrored="true"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
|
110
app/src/main/res/layout/activity_pin_shortcut.xml
Normal file
110
app/src/main/res/layout/activity_pin_shortcut.xml
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/list_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context=".ui.PinShortcutActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/pin_shortcut_appbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@null"
|
||||||
|
|
||||||
|
android:gravity="center"
|
||||||
|
app:elevation="0dp"
|
||||||
|
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/list_heading"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minHeight="?actionBarSize"
|
||||||
|
android:padding="@dimen/appbar_padding"
|
||||||
|
android:text="@string/pin_shortcut_title"
|
||||||
|
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
|
||||||
|
android:textSize="30sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/pin_shortcut_close"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/pin_shortcut_close"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:includeFontPadding="true"
|
||||||
|
android:paddingLeft="16sp"
|
||||||
|
android:paddingRight="16sp"
|
||||||
|
android:src="@drawable/baseline_close_24"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/pin_shortcut_appbar">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pin_shortcut_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="50dp"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="40dp"
|
||||||
|
tools:drawableLeft="@drawable/baseline_settings_24"
|
||||||
|
tools:text="Shortcut name" />
|
||||||
|
<!--
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="10dp" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/pin_shortcut_switch_visible"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:textColor"
|
||||||
|
android:text="@string/pin_shortcut_switch_visible" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="10dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/pin_shortcut_button_bind"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pin_shortcut_button_bind" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
27
app/src/main/res/layout/dialog_select_gesture.xml
Normal file
27
app/src/main/res/layout/dialog_select_gesture.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/dialog_select_gesture"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/dialog_select_gesture_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fadeScrollbars="false"
|
||||||
|
app:fastScrollEnabled="true"
|
||||||
|
app:fastScrollHorizontalThumbDrawable="@drawable/fast_scroll_thumb_drawable"
|
||||||
|
app:fastScrollHorizontalTrackDrawable="@drawable/fast_scroll_track_drawable"
|
||||||
|
app:fastScrollVerticalThumbDrawable="@drawable/fast_scroll_thumb_drawable"
|
||||||
|
app:fastScrollVerticalTrackDrawable="@drawable/fast_scroll_track_drawable" >
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
53
app/src/main/res/layout/dialog_select_gesture_row.xml
Normal file
53
app/src/main/res/layout/dialog_select_gesture_row.xml
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/dialog_select_gesture_row_container"
|
||||||
|
style="@style/AlertDialogCustom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="5dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:gravity="start"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/dialog_select_gesture_row_icon"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dialog_select_gesture_row_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
android:gravity="start"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="Action label" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dialog_select_gesture_row_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:visibility="visible"
|
||||||
|
tools:text="A verbose description of how to perform the action" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dialog_select_gesture_row_icon"
|
||||||
|
android:layout_width="@dimen/app_icon_side"
|
||||||
|
android:layout_height="@dimen/app_icon_side"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:srcCompat="@drawable/baseline_flashlight_on_24"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -250,6 +250,11 @@
|
||||||
<string name="list_other_lock_screen">Lock Screen</string>
|
<string name="list_other_lock_screen">Lock Screen</string>
|
||||||
<string name="list_other_torch">Toggle Torch</string>
|
<string name="list_other_torch">Toggle Torch</string>
|
||||||
|
|
||||||
|
<!-- Pin shortcuts -->
|
||||||
|
<string name="pin_shortcut_title">Add Shortcut</string>
|
||||||
|
<string name="pin_shortcut_button_bind">Bind to gesture</string>
|
||||||
|
<string name="pin_shortcut_switch_visible">Show in app list</string>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
-
|
-
|
||||||
- Tutorial
|
- Tutorial
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '2.0.0'
|
ext.kotlin_version = '2.0.0'
|
||||||
ext.android_plugin_version = '8.8.0'
|
ext.android_plugin_version = '8.8.1'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -10,7 +10,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.8.0'
|
classpath 'com.android.tools.build:gradle:8.8.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "com.android.tools.build:gradle:$android_plugin_version"
|
classpath "com.android.tools.build:gradle:$android_plugin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||||
|
|
Loading…
Add table
Reference in a new issue