Playhi/FreezeYou

View on GitHub
app/src/main/java/cf/playhi/freezeyou/utils/LauncherShortcutUtils.kt

Summary

Maintainability
A
1 hr
Test Coverage
package cf.playhi.freezeyou.utils

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.Bitmap
import android.graphics.Matrix
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.os.Build
import cf.playhi.freezeyou.R
import cf.playhi.freezeyou.storage.key.DefaultSharedPreferenceStorageBooleanKeys.allowEditWhenCreateShortcut
import cf.playhi.freezeyou.ui.LauncherShortcutConfirmAndGenerateActivity
import cf.playhi.freezeyou.utils.ApplicationIconUtils.getBitmapFromDrawable
import cf.playhi.freezeyou.utils.ToastUtils.showToast

object LauncherShortcutUtils {

    /**
     * @param title Shortcut label
     * @param pkgName Package name
     * @param icon Shortcut icon, drawable
     * @param cls Dest class
     * @param id Unique string
     * @param context Context
     */
    @JvmStatic
    fun checkSettingsAndRequestCreateShortcut(
        title: String,
        pkgName: String,
        icon: Drawable,
        cls: Class<*>,
        id: String,
        context: Context
    ) {
        if (allowEditWhenCreateShortcut.getValue(context)) {
            context.startActivity(
                Intent(
                    context, LauncherShortcutConfirmAndGenerateActivity::class.java
                )
                    .putExtra("pkgName", pkgName)
                    .putExtra("name", title)
                    .putExtra("id", id)
                    .putExtra("class", cls)
            )
        } else {
            createShortCut(title, pkgName, icon, cls, id, context)
        }
    }

    /**
     * @param title Shortcut label
     * @param pkgName Package name
     * @param icon Shortcut icon, drawable
     * @param cls Dest class
     * @param id Unique string
     * @param context Context
     * @param target Target activity. If null, launch the application directly.
     * @param tasks Attached task(s)
     */
    @JvmStatic
    @JvmOverloads
    fun createShortCut(
        title: String,
        pkgName: String,
        icon: Drawable,
        cls: Class<*>,
        id: String,
        context: Context,
        target: String? = null,
        tasks: String? = null
    ) {
        requestCreateShortCut(
            title,
            Intent(context, cls)
                .setAction(Intent.ACTION_MAIN)
                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                .putExtra("pkgName", pkgName)
                .putExtra("target", target)
                .putExtra("tasks", tasks),
            icon, id, context, null
        )
    }

    /**
     * One of `icon` and `bm` cannot be null,
     * if both `icon` and `bm` is not null,
     * `bm` will be used as the shortcut icon.
     *
     * @param title Shortcut label
     * @param intent Intent which contains `pkgName`, `target` and `tasks`.
     * @param icon Shortcut icon, drawable
     * @param id Unique string
     * @param context Context
     * @param bm Shortcut icon, bitmap
     */
    @JvmStatic
    fun requestCreateShortCut(
        title: String,
        intent: Intent,
        icon: Drawable?,
        id: String,
        context: Context,
        bm: Bitmap?
    ) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            requestCreateShortCutOldApi(title, intent, icon, context, bm)
        } else {
            val mShortcutManager: ShortcutManager? = context.getSystemService(
                ShortcutManager::class.java
            )
            if (mShortcutManager != null) {
                if (mShortcutManager.isRequestPinShortcutSupported) {
                    val shortcutInfoBuilder = ShortcutInfo.Builder(context, id)
                        .setIcon(
                            Icon.createWithBitmap(
                                bm ?: getBitmapFromDrawable(icon)
                            )
                        )
                        .setIntent(intent)
                        .setShortLabel(title.ifEmpty { " " })
                        .setLongLabel(title.ifEmpty { " " })

                    val pinShortcutInfo = shortcutInfoBuilder.build()
                    // Create the PendingIntent object only if your app needs to be notified
                    // that the user allowed the shortcut to be pinned. Note that, if the
                    // pinning operation fails, your app isn't notified. We assume here that the
                    // app has implemented a method called createShortcutResultIntent() that
                    // returns a broadcast intent.
                    val pinnedShortcutCallbackIntent =
                        mShortcutManager.createShortcutResultIntent(pinShortcutInfo)

                    // Configure the intent so that your app's broadcast receiver gets
                    // the callback successfully.
                    val successCallback = PendingIntent.getBroadcast(
                        context, id.hashCode(),
                        pinnedShortcutCallbackIntent, PendingIntent.FLAG_IMMUTABLE
                    )
                    mShortcutManager.requestPinShortcut(
                        pinShortcutInfo,
                        successCallback.intentSender
                    )
                    showToast(context, R.string.requested)
                } else {
                    requestCreateShortCutOldApi(title, intent, icon, context, bm)
                }
            } else {
                requestCreateShortCutOldApi(title, intent, icon, context, bm)
            }
        }
    }

    /**
     * bm 和 icon 至少有一个不为 null,如均为非空则使用 bm
     *
     * @param title   Title 标题
     * @param intent  Intent
     * @param icon    Icon Drawable 图标
     * @param context Context
     * @param bm      Bitmap 图标
     */
    private fun requestCreateShortCutOldApi(
        title: String,
        intent: Intent,
        icon: Drawable?,
        context: Context,
        bm: Bitmap?
    ) {
        val addShortCut = Intent("com.android.launcher.action.INSTALL_SHORTCUT")

        @Suppress("DEPRECATION")
        addShortCut.putExtra(Intent.EXTRA_SHORTCUT_NAME, title)

        @Suppress("DEPRECATION")
        addShortCut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent)

        try {
            val bitmap: Bitmap = bm ?: getBitmapFromDrawable(icon)
            var size = context.resources.getDimension(android.R.dimen.app_icon_size)
            if (size < 1) {
                size = 72f
            }
            if (bitmap.height > size) {
                val matrix = Matrix()
                val scaleWidth = size / bitmap.width
                val scaleHeight = size / bitmap.height
                matrix.postScale(scaleWidth, scaleHeight)
                addShortCut.putExtra(
                    @Suppress("DEPRECATION")
                    Intent.EXTRA_SHORTCUT_ICON,
                    Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
                )
            } else {
                @Suppress("DEPRECATION")
                addShortCut.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap)
            }
            context.sendBroadcast(addShortCut)
            showToast(context, R.string.requested)
        } catch (e: Exception) {
            e.printStackTrace()
            showToast(context, context.getString(R.string.requestFailed) + e.message)
        }
    }
}