forked from suyu/suyu
Merge pull request #12747 from t895/homescreen-widget
android: Add to launcher button
This commit is contained in:
commit
8d708b0c79
7 changed files with 116 additions and 52 deletions
|
@ -3,9 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.adapters
|
package org.yuzu.yuzu_emu.adapters
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.drawable.LayerDrawable
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -15,10 +12,6 @@ import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -30,7 +23,6 @@ import kotlinx.coroutines.withContext
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
|
||||||
import org.yuzu.yuzu_emu.databinding.CardGameBinding
|
import org.yuzu.yuzu_emu.databinding.CardGameBinding
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
|
@ -89,36 +81,13 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||||
)
|
)
|
||||||
.apply()
|
.apply()
|
||||||
|
|
||||||
val openIntent =
|
|
||||||
Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
|
|
||||||
action = Intent.ACTION_VIEW
|
|
||||||
data = Uri.parse(game.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
activity.lifecycleScope.launch {
|
activity.lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val layerDrawable = ResourcesCompat.getDrawable(
|
|
||||||
YuzuApplication.appContext.resources,
|
|
||||||
R.drawable.shortcut,
|
|
||||||
null
|
|
||||||
) as LayerDrawable
|
|
||||||
layerDrawable.setDrawableByLayerId(
|
|
||||||
R.id.shortcut_foreground,
|
|
||||||
GameIconUtils.getGameIcon(activity, game)
|
|
||||||
.toDrawable(YuzuApplication.appContext.resources)
|
|
||||||
)
|
|
||||||
val inset = YuzuApplication.appContext.resources
|
|
||||||
.getDimensionPixelSize(R.dimen.icon_inset)
|
|
||||||
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
|
||||||
val shortcut =
|
val shortcut =
|
||||||
ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
|
ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
|
||||||
.setShortLabel(game.title)
|
.setShortLabel(game.title)
|
||||||
.setIcon(
|
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
||||||
IconCompat.createWithAdaptiveBitmap(
|
.setIntent(game.launchIntent)
|
||||||
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setIntent(openIntent)
|
|
||||||
.build()
|
.build()
|
||||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -84,6 +86,24 @@ class GamePropertiesFragment : Fragment() {
|
||||||
view.findNavController().popBackStack()
|
view.findNavController().popBackStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val shortcutManager = requireActivity().getSystemService(ShortcutManager::class.java)
|
||||||
|
binding.buttonShortcut.isEnabled = shortcutManager.isRequestPinShortcutSupported
|
||||||
|
binding.buttonShortcut.setOnClickListener {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val shortcut = ShortcutInfo.Builder(requireContext(), args.game.title)
|
||||||
|
.setShortLabel(args.game.title)
|
||||||
|
.setIcon(
|
||||||
|
GameIconUtils.getShortcutIcon(requireActivity(), args.game)
|
||||||
|
.toIcon(requireContext())
|
||||||
|
)
|
||||||
|
.setIntent(args.game.launchIntent)
|
||||||
|
.build()
|
||||||
|
shortcutManager.requestPinShortcut(shortcut, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
|
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
|
||||||
binding.title.text = args.game.title
|
binding.title.text = args.game.title
|
||||||
binding.title.postDelayed(
|
binding.title.postDelayed(
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.model
|
package org.yuzu.yuzu_emu.model
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
|
@ -11,6 +12,7 @@ import kotlinx.serialization.Serializable
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -61,6 +63,12 @@ class Game(
|
||||||
val addonDir: String
|
val addonDir: String
|
||||||
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
|
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
|
||||||
|
|
||||||
|
val launchIntent: Intent
|
||||||
|
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = Uri.parse(path)
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Game) {
|
if (other !is Game) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -5,7 +5,10 @@ package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
@ -85,4 +88,22 @@ object GameIconUtils {
|
||||||
return imageLoader.execute(request)
|
return imageLoader.execute(request)
|
||||||
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
|
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getShortcutIcon(lifecycleOwner: LifecycleOwner, game: Game): IconCompat {
|
||||||
|
val layerDrawable = ResourcesCompat.getDrawable(
|
||||||
|
YuzuApplication.appContext.resources,
|
||||||
|
R.drawable.shortcut,
|
||||||
|
null
|
||||||
|
) as LayerDrawable
|
||||||
|
layerDrawable.setDrawableByLayerId(
|
||||||
|
R.id.shortcut_foreground,
|
||||||
|
getGameIcon(lifecycleOwner, game).toDrawable(YuzuApplication.appContext.resources)
|
||||||
|
)
|
||||||
|
val inset = YuzuApplication.appContext.resources
|
||||||
|
.getDimensionPixelSize(R.dimen.icon_inset)
|
||||||
|
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
|
||||||
|
return IconCompat.createWithAdaptiveBitmap(
|
||||||
|
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
9
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_shortcut.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M280,920q-33,0 -56.5,-23.5T200,840v-720q0,-33 23.5,-56.5T280,40h400q33,0 56.5,23.5T760,120v160h-80v-40L280,240v480h400v-40h80v160q0,33 -23.5,56.5T680,920L280,920ZM686,520L480,520v120h-80v-120q0,-33 23.5,-56.5T480,440h206l-62,-64 56,-56 160,160 -160,160 -56,-56 62,-64Z" />
|
||||||
|
</vector>
|
|
@ -43,16 +43,35 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_back"
|
android:id="@+id/button_back"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="?attr/materialIconButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
app:icon="@drawable/ic_back"
|
app:icon="@drawable/ic_back"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnSurface" />
|
app:iconTint="?attr/colorOnSurface"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_shortcut"
|
||||||
|
style="?attr/materialIconButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:icon="@drawable/ic_shortcut"
|
||||||
|
app:iconSize="24dp"
|
||||||
|
app:iconTint="?attr/colorOnSurface"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
style="?attr/materialCardViewElevatedStyle"
|
style="?attr/materialCardViewElevatedStyle"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -22,16 +21,35 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center_horizontal">
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_back"
|
android:id="@+id/button_back"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="?attr/materialIconButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
app:icon="@drawable/ic_back"
|
app:icon="@drawable/ic_back"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnSurface" />
|
app:iconTint="?attr/colorOnSurface"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_shortcut"
|
||||||
|
style="?attr/materialIconButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:icon="@drawable/ic_shortcut"
|
||||||
|
app:iconSize="24dp"
|
||||||
|
app:iconTint="?attr/colorOnSurface"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
style="?attr/materialCardViewElevatedStyle"
|
style="?attr/materialCardViewElevatedStyle"
|
||||||
|
@ -45,7 +63,7 @@
|
||||||
android:id="@+id/image_game_screen"
|
android:id="@+id/image_game_screen"
|
||||||
android:layout_width="175dp"
|
android:layout_width="175dp"
|
||||||
android:layout_height="175dp"
|
android:layout_height="175dp"
|
||||||
tools:src="@drawable/default_icon"/>
|
tools:src="@drawable/default_icon" />
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue