Skip to content

Commit 3a6aa2e

Browse files
committed
add support for pinned shortcuts
1 parent 4280886 commit 3a6aa2e

File tree

6 files changed

+95
-19
lines changed

6 files changed

+95
-19
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@
4242
android:configChanges="orientation|keyboardHidden|screenSize"
4343
android:exported="true"
4444
android:screenOrientation="portrait"
45-
android:theme="@style/LauncherTheme" />
45+
android:theme="@style/LauncherTheme">
46+
47+
<intent-filter>
48+
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
49+
</intent-filter>
50+
</activity>
4651

4752
<activity
4853
android:name=".activities.SettingsActivity"

app/src/main/kotlin/com/simplemobiletools/launcher/activities/MainActivity.kt

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import android.content.ComponentName
1111
import android.content.Context
1212
import android.content.Intent
1313
import android.content.pm.ActivityInfo
14+
import android.content.pm.LauncherApps
1415
import android.content.pm.PackageManager
1516
import android.content.res.Configuration
1617
import android.graphics.Bitmap
1718
import android.graphics.Color
19+
import android.graphics.Rect
1820
import android.net.Uri
1921
import android.os.Bundle
2022
import android.os.Handler
@@ -85,6 +87,65 @@ class MainActivity : SimpleActivity(), FlingListener {
8587
fragment.y = mScreenHeight.toFloat()
8688
fragment.beVisible()
8789
}
90+
91+
if (intent.action == LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT) {
92+
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
93+
val item = launcherApps.getPinItemRequest(intent)
94+
if (item.shortcutInfo == null) {
95+
return
96+
}
97+
98+
ensureBackgroundThread {
99+
val shortcutId = item.shortcutInfo?.id!!
100+
val label = item.shortcutInfo?.shortLabel?.toString() ?: item.shortcutInfo?.longLabel?.toString() ?: ""
101+
val icon = launcherApps.getShortcutIconDrawable(item.shortcutInfo!!, resources.displayMetrics.densityDpi)
102+
val rect = findFirstEmptyCell() ?: return@ensureBackgroundThread
103+
val gridItem = HomeScreenGridItem(
104+
null,
105+
rect.left,
106+
rect.top,
107+
rect.right,
108+
rect.bottom,
109+
item.shortcutInfo!!.`package`,
110+
label,
111+
ITEM_TYPE_SHORTCUT,
112+
"",
113+
-1,
114+
"",
115+
shortcutId,
116+
icon.toBitmap(),
117+
icon
118+
)
119+
120+
// delay showing the shortcut both to let the user see adding it in realtime and hackily avoid concurrent modification exception at HomeScreenGrid
121+
Thread.sleep(2000)
122+
item.accept()
123+
home_screen_grid.storeAndShowGridItem(gridItem)
124+
}
125+
}
126+
}
127+
128+
private fun findFirstEmptyCell(): Rect? {
129+
val gridItems = homeScreenGridItemsDB.getAllItems() as ArrayList<HomeScreenGridItem>
130+
val occupiedCells = ArrayList<Pair<Int, Int>>()
131+
gridItems.forEach { item ->
132+
for (xCell in item.left..item.right) {
133+
for (yCell in item.top..item.bottom) {
134+
occupiedCells.add(Pair(xCell, yCell))
135+
}
136+
}
137+
}
138+
139+
for (checkedYCell in 0 until COLUMN_COUNT) {
140+
for (checkedXCell in 0 until ROW_COUNT - 1) {
141+
val wantedCell = Pair(checkedXCell, checkedYCell)
142+
if (!occupiedCells.contains(wantedCell)) {
143+
return Rect(wantedCell.first, wantedCell.second, wantedCell.first, wantedCell.second)
144+
}
145+
}
146+
}
147+
148+
return null
88149
}
89150

90151
override fun onResume() {
@@ -330,7 +391,12 @@ class MainActivity : SimpleActivity(), FlingListener {
330391
if (clickedGridItem.type == ITEM_TYPE_ICON) {
331392
launchApp(clickedGridItem.packageName)
332393
} else if (clickedGridItem.type == ITEM_TYPE_SHORTCUT) {
333-
launchShortcutIntent(clickedGridItem)
394+
val id = clickedGridItem.shortcutId
395+
val packageName = clickedGridItem.packageName
396+
val userHandle = android.os.Process.myUserHandle()
397+
val shortcutBounds = home_screen_grid.getClickableRect(clickedGridItem)
398+
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
399+
launcherApps.startShortcut(packageName, id, shortcutBounds, null, userHandle)
334400
}
335401
}
336402
}
@@ -527,7 +593,7 @@ class MainActivity : SimpleActivity(), FlingListener {
527593
try {
528594
val defaultDialerPackage = (getSystemService(Context.TELECOM_SERVICE) as TelecomManager).defaultDialerPackage
529595
appLaunchers.firstOrNull { it.packageName == defaultDialerPackage }?.apply {
530-
val dialerIcon = HomeScreenGridItem(null, 0, ROW_COUNT - 1, 0, ROW_COUNT - 1, defaultDialerPackage, title, ITEM_TYPE_ICON, "", -1, "", null)
596+
val dialerIcon = HomeScreenGridItem(null, 0, ROW_COUNT - 1, 0, ROW_COUNT - 1, defaultDialerPackage, title, ITEM_TYPE_ICON, "", -1, "", "", null)
531597
homeScreenGridItems.add(dialerIcon)
532598
}
533599
} catch (e: Exception) {
@@ -537,7 +603,7 @@ class MainActivity : SimpleActivity(), FlingListener {
537603
val defaultSMSMessengerPackage = Telephony.Sms.getDefaultSmsPackage(this)
538604
appLaunchers.firstOrNull { it.packageName == defaultSMSMessengerPackage }?.apply {
539605
val SMSMessengerIcon =
540-
HomeScreenGridItem(null, 1, ROW_COUNT - 1, 1, ROW_COUNT - 1, defaultSMSMessengerPackage, title, ITEM_TYPE_ICON, "", -1, "", null)
606+
HomeScreenGridItem(null, 1, ROW_COUNT - 1, 1, ROW_COUNT - 1, defaultSMSMessengerPackage, title, ITEM_TYPE_ICON, "", -1, "", "", null)
541607
homeScreenGridItems.add(SMSMessengerIcon)
542608
}
543609
} catch (e: Exception) {
@@ -549,7 +615,7 @@ class MainActivity : SimpleActivity(), FlingListener {
549615
val defaultBrowserPackage = resolveInfo!!.activityInfo.packageName
550616
appLaunchers.firstOrNull { it.packageName == defaultBrowserPackage }?.apply {
551617
val browserIcon =
552-
HomeScreenGridItem(null, 2, ROW_COUNT - 1, 2, ROW_COUNT - 1, defaultBrowserPackage, title, ITEM_TYPE_ICON, "", -1, "", null)
618+
HomeScreenGridItem(null, 2, ROW_COUNT - 1, 2, ROW_COUNT - 1, defaultBrowserPackage, title, ITEM_TYPE_ICON, "", -1, "", "", null)
553619
homeScreenGridItems.add(browserIcon)
554620
}
555621
} catch (e: Exception) {
@@ -560,7 +626,7 @@ class MainActivity : SimpleActivity(), FlingListener {
560626
val storePackage = potentialStores.firstOrNull { isPackageInstalled(it) && appLaunchers.map { it.packageName }.contains(it) }
561627
if (storePackage != null) {
562628
appLaunchers.firstOrNull { it.packageName == storePackage }?.apply {
563-
val storeIcon = HomeScreenGridItem(null, 3, ROW_COUNT - 1, 3, ROW_COUNT - 1, storePackage, title, ITEM_TYPE_ICON, "", -1, "", null)
629+
val storeIcon = HomeScreenGridItem(null, 3, ROW_COUNT - 1, 3, ROW_COUNT - 1, storePackage, title, ITEM_TYPE_ICON, "", -1, "", "", null)
564630
homeScreenGridItems.add(storeIcon)
565631
}
566632
}
@@ -572,7 +638,7 @@ class MainActivity : SimpleActivity(), FlingListener {
572638
val resolveInfo = packageManager.resolveActivity(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY)
573639
val defaultCameraPackage = resolveInfo!!.activityInfo.packageName
574640
appLaunchers.firstOrNull { it.packageName == defaultCameraPackage }?.apply {
575-
val cameraIcon = HomeScreenGridItem(null, 4, ROW_COUNT - 1, 4, ROW_COUNT - 1, defaultCameraPackage, title, ITEM_TYPE_ICON, "", -1, "", null)
641+
val cameraIcon = HomeScreenGridItem(null, 4, ROW_COUNT - 1, 4, ROW_COUNT - 1, defaultCameraPackage, title, ITEM_TYPE_ICON, "", -1, "", "", null)
576642
homeScreenGridItems.add(cameraIcon)
577643
}
578644
} catch (e: Exception) {
@@ -581,7 +647,12 @@ class MainActivity : SimpleActivity(), FlingListener {
581647
homeScreenGridItemsDB.insertAll(homeScreenGridItems)
582648
}
583649

584-
fun handleWidgetBinding(appWidgetManager: AppWidgetManager, appWidgetId: Int, appWidgetInfo: AppWidgetProviderInfo, callback: (canBind: Boolean) -> Unit) {
650+
fun handleWidgetBinding(
651+
appWidgetManager: AppWidgetManager,
652+
appWidgetId: Int,
653+
appWidgetInfo: AppWidgetProviderInfo,
654+
callback: (canBind: Boolean) -> Unit
655+
) {
585656
mActionOnCanBindWidget = null
586657
val canCreateWidget = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, appWidgetInfo.provider)
587658
if (canCreateWidget) {

app/src/main/kotlin/com/simplemobiletools/launcher/fragments/AllAppsFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
141141

142142
override fun onAppLauncherLongPressed(x: Float, y: Float, appLauncher: AppLauncher) {
143143
val gridItem =
144-
HomeScreenGridItem(null, -1, -1, -1, -1, appLauncher.packageName, appLauncher.title, ITEM_TYPE_ICON, "", -1, "", null, appLauncher.drawable)
144+
HomeScreenGridItem(null, -1, -1, -1, -1, appLauncher.packageName, appLauncher.title, ITEM_TYPE_ICON, "", -1, "", "", null, appLauncher.drawable)
145145
activity?.showHomeIconMenu(x, y, gridItem, true)
146146
ignoreTouches = true
147147
}

app/src/main/kotlin/com/simplemobiletools/launcher/fragments/WidgetsFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class WidgetsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
241241
appWidget.className,
242242
-1,
243243
"",
244+
"",
244245
null,
245246
appWidget.widgetPreviewImage,
246247
appWidget.providerInfo,

app/src/main/kotlin/com/simplemobiletools/launcher/models/HomeScreenGridItem.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.simplemobiletools.launcher.models
22

33
import android.appwidget.AppWidgetProviderInfo
4-
import android.content.ComponentName
54
import android.content.pm.ActivityInfo
65
import android.graphics.Bitmap
76
import android.graphics.drawable.Drawable
87
import androidx.room.*
98
import com.simplemobiletools.launcher.helpers.ITEM_TYPE_ICON
109

11-
// grid cells are from 0-5 by default. Icons occupy 1 slot only, widgets can be bigger
10+
// grid cells are from 0-5 by default. Icons and shortcuts occupy 1 slot only, widgets can be bigger
1211
@Entity(tableName = "home_screen_grid_items", indices = [(Index(value = ["id"], unique = true))])
1312
data class HomeScreenGridItem(
1413
@PrimaryKey(autoGenerate = true) var id: Long?,
@@ -21,16 +20,17 @@ data class HomeScreenGridItem(
2120
@ColumnInfo(name = "type") var type: Int,
2221
@ColumnInfo(name = "class_name") var className: String,
2322
@ColumnInfo(name = "widget_id") var widgetId: Int,
24-
@ColumnInfo(name = "intent") var intent: String, // used at shortcuts on click
25-
@ColumnInfo(name = "icon") var icon: Bitmap? = null, // store only images of shortcuts, those cannot be retrieved anytime
23+
@ColumnInfo(name = "intent") var intent: String, // used at static and dynamic shortcuts on click
24+
@ColumnInfo(name = "shortcut_id") var shortcutId: String, // used at pinned shortcuts at startLauncher call
25+
@ColumnInfo(name = "icon") var icon: Bitmap? = null, // store images of pinned shortcuts, those cannot be retrieved after creating
2626

2727
@Ignore var drawable: Drawable? = null,
2828
@Ignore var providerInfo: AppWidgetProviderInfo? = null, // used at widgets
2929
@Ignore var activityInfo: ActivityInfo? = null, // used at shortcuts
3030
@Ignore var widthCells: Int = 1,
3131
@Ignore var heightCells: Int = 1
3232
) {
33-
constructor() : this(null, -1, -1, -1, -1, "", "", ITEM_TYPE_ICON, "", -1, "", null, null, null, null, 1, 1)
33+
constructor() : this(null, -1, -1, -1, -1, "", "", ITEM_TYPE_ICON, "", -1, "", "", null, null, null, null, 1, 1)
3434

3535
fun getWidthInCells() = if (right == -1 || left == -1) {
3636
widthCells
@@ -43,6 +43,4 @@ data class HomeScreenGridItem(
4343
} else {
4444
bottom - top + 1
4545
}
46-
47-
fun getComponentName() = ComponentName(activityInfo?.packageName ?: "", activityInfo?.name ?: "")
4846
}

app/src/main/kotlin/com/simplemobiletools/launcher/views/HomeScreenGrid.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
283283
"",
284284
-1,
285285
"",
286+
"",
286287
draggedItem!!.icon,
287288
draggedItem!!.drawable,
288289
draggedItem!!.providerInfo,
@@ -299,7 +300,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
299300
newHomeScreenGridItem.title = label
300301
newHomeScreenGridItem.icon = icon
301302
newHomeScreenGridItem.intent = intent
302-
newHomeScreenGridItem.drawable = BitmapDrawable(newHomeScreenGridItem.icon)
303+
newHomeScreenGridItem.drawable = BitmapDrawable(icon)
303304
storeAndShowGridItem(newHomeScreenGridItem)
304305
}
305306
}
@@ -318,7 +319,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
318319
}
319320
}
320321

321-
private fun storeAndShowGridItem(item: HomeScreenGridItem) {
322+
fun storeAndShowGridItem(item: HomeScreenGridItem) {
322323
val newId = context.homeScreenGridItemsDB.insert(item)
323324
item.id = newId
324325
gridItems.add(item)
@@ -642,7 +643,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
642643
}
643644

644645
// get the clickable area around the icon, it includes text too
645-
private fun getClickableRect(item: HomeScreenGridItem): Rect {
646+
fun getClickableRect(item: HomeScreenGridItem): Rect {
646647
if (cellXCoords.isEmpty()) {
647648
fillCellSizes()
648649
}

0 commit comments

Comments
 (0)