<|start_filename|>saf-kotlin-ext/src/main/java/com/safframework/ext/Context+Extension.kt<|end_filename|>
package com.safframework.ext

import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.ColorRes
import androidx.annotation.DimenRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import java.io.File

/**
 * Created by <NAME> on 2017/6/30.
 */

/**
 * screen width in pixels
 */
inline val Context.screenWidth
    get() = resources.displayMetrics.widthPixels

/**
 * screen height in pixels
 */
inline val Context.screenHeight
    get() = resources.displayMetrics.heightPixels

inline val Context.isNetworkAvailable: Boolean
    @SuppressLint("MissingPermission")
    get() {
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetworkInfo = connectivityManager.activeNetworkInfo
        return activeNetworkInfo?.isConnectedOrConnecting ?: false
    }

/**
 * returns dip(dp) dimension value in pixels
 * @param value dp
 */
fun Context.dp2px(value: Int): Int = (value * resources.displayMetrics.density).toInt()

fun Context.dp2px(value: Float): Int = (value * resources.displayMetrics.density).toInt()

/**
 * return sp dimension value in pixels
 * @param value sp
 */
fun Context.sp2px(value: Int): Int = (value * resources.displayMetrics.scaledDensity).toInt()

fun Context.sp2px(value: Float): Int = (value * resources.displayMetrics.scaledDensity).toInt()

/**
 * converts [px] value into dip or sp
 * @param px
 */
fun Context.px2dp(px: Int): Float = px.toFloat() / resources.displayMetrics.density

fun Context.px2sp(px: Int): Float = px.toFloat() / resources.displayMetrics.scaledDensity

/**
 * return dimen resource value in pixels
 * @param resource dimen resource
 */
fun Context.dimen2px(@DimenRes resource: Int): Int = resources.getDimensionPixelSize(resource)


fun Context.string(@StringRes id: Int): String = getString(id)

fun Context.color(@ColorRes id: Int): Int = resources.getColor(id)

fun Context.inflateLayout(@LayoutRes layoutId: Int, parent: ViewGroup? = null, attachToRoot: Boolean = false): View
        = LayoutInflater.from(this).inflate(layoutId, parent, attachToRoot)

/**
 * 获取当前app的版本号
 */
fun Context.getAppVersion(): String {

    val appContext = applicationContext
    val manager = appContext.getPackageManager()
    try {
        val info = manager.getPackageInfo(appContext.getPackageName(), 0)

        if (info != null)
            return info.versionName

    } catch (e: PackageManager.NameNotFoundException) {
        e.printStackTrace()
    }

    return ""
}

fun Context.getAppVersionCode(): Int {

    val appContext = applicationContext
    val manager = appContext.getPackageManager()
    try {
        val info = manager.getPackageInfo(appContext.getPackageName(), 0)

        if (info != null)
            return info.versionCode

    } catch (e: PackageManager.NameNotFoundException) {
        e.printStackTrace()
    }

    return 0
}

/**
 * 获取应用的包名
 *
 * @param context context
 * @return package name
 */
fun Context.getPackageName(): String = packageName

data class AppInfo(
        val apkPath: String,
        val packageName: String,
        val versionName: String,
        val versionCode: Long,
        val appName: String,
        val icon: Drawable
)

fun Context.getAppInfo(apkPath: String): AppInfo {
    val packageInfo = packageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_META_DATA) as PackageInfo
    packageInfo.applicationInfo.sourceDir = apkPath
    packageInfo.applicationInfo.publicSourceDir = apkPath

    val packageName = packageInfo.packageName
    val appName = packageManager.getApplicationLabel(packageInfo.applicationInfo).toString()
    val versionName = packageInfo.versionName
    val versionCode = packageInfo.versionCode
    val icon = packageManager.getApplicationIcon(packageInfo.applicationInfo)
    return AppInfo(apkPath, packageName, versionName, versionCode.toLong(), appName, icon)
}

fun Context.getAppInfos(apkFolderPath: String): List<AppInfo> {
    val appInfoList = ArrayList<AppInfo>()
    for (file in File(apkFolderPath).listFiles())
        appInfoList.add(getAppInfo(file.path))
    return appInfoList
}

<|start_filename|>saf-kotlin-utils/src/main/java/com/safframework/utils/NetUtils.kt<|end_filename|>
package com.safframework.utils

import android.content.Context
import android.net.wifi.WifiManager
import java.net.Inet4Address
import java.net.InetAddress
import java.net.NetworkInterface
import java.util.*

/**
 *
 * @FileName:
 *          com.safframework.utils.NetUtils
 * @author: <NAME>
 * @date: 2020-11-19 15:02
 * @version: V1.0 <描述当前版本功能>
 */

/**
 * 获取内网IP地址
 */
val localIPAddress: String by lazy {

    val en: Enumeration<NetworkInterface> = NetworkInterface.getNetworkInterfaces()
    while (en.hasMoreElements()) {
        val intf: NetworkInterface = en.nextElement()
        val enumIpAddr: Enumeration<InetAddress> = intf.inetAddresses
        while (enumIpAddr.hasMoreElements()) {
            val inetAddress: InetAddress = enumIpAddr.nextElement()
            if (!inetAddress.isLoopbackAddress && inetAddress is Inet4Address) {
                return@lazy inetAddress.hostAddress.toString()
            }
        }
    }
    "null"
}

/**
 * 获取局域网的网关地址
 */
fun getGatewayIP(context: Context):String {

    val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

    val info = wifiManager.dhcpInfo
    val gateway = info.gateway

    return intToIp(gateway)
}

/**
 * int值转换为ip
 * @param addr
 * @return
 */
private fun intToIp(addr: Int): String {
    var addr = addr
    return (addr and 0xFF).toString() + "." +
            (8.let { addr = addr ushr it; addr } and 0xFF) + "." +
            (8.let { addr = addr ushr it; addr } and 0xFF) + "." +
            (8.let { addr = addr ushr it; addr } and 0xFF)
}

<|start_filename|>saf-kotlin-ext/src/main/java/com/safframework/ext/Number+Extension.kt<|end_filename|>
package com.safframework.ext

import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat

/**
 * @Author zhiqiang
 * @Date 2019-06-19
 * @Description
 */


/**
 * 默认保留小数点后10位
 */
const val DEFAULT_DECIMAL_NUMBER = 2
/**
 * 默认分隔符为千分位
 */
const val DEFAULT_SEPARATE_NUMBER = 3


/**
 * @param addComma 是否需要添加逗号，默认不加
 * @param modeFloor 是否使用去尾法，默认true 1.5->1   2.8->2
 * @param decimalNum 小数点后位数
 */
fun Number.formatNumber(
        addComma: Boolean = false,
        modeFloor: Boolean = true,
        decimalNum: Int? = DEFAULT_DECIMAL_NUMBER
): String {
    var decimal = decimalNum
    if (decimal == null) {
        decimal = DEFAULT_DECIMAL_NUMBER
    }
    val decimalFormat = DecimalFormat()
    decimalFormat.maximumFractionDigits = decimal
    decimalFormat.groupingSize = if (addComma) DEFAULT_SEPARATE_NUMBER else 0
    if (modeFloor) decimalFormat.roundingMode = RoundingMode.FLOOR
    return decimalFormat.format(this)
}

/**
 * @param addComma 是否需要添加逗号，默认不加
 * @param modeFloor 是否使用去尾法，默认true 1.5->1   2.8->2
 * @param decimalNum 小数点后位数
 */
fun String.formatNumber(
        addComma: Boolean = false, modeFloor: Boolean = true,
        decimalNum: Int? = DEFAULT_DECIMAL_NUMBER
): String =
        this.toBigDecimalWithNull().formatNumber(addComma, modeFloor, decimalNum)

fun String?.toBigDecimalWithNull(default: BigDecimal = BigDecimal.ZERO) = isNullOrBlank().not().then({
    try {
        this!!.toBigDecimal()
    } catch (e: NumberFormatException) {
        default
    }
}, default)

fun String?.toIntWithNull(default: Int = 0) = isNullOrBlank().not().then({
    try {
        this!!.toInt()
    } catch (e: NumberFormatException) {
        default
    }
}, default)

fun String?.toFloatWithNull(default: Float = 0F) = isNullOrBlank().not().then({
    try {
        this!!.toFloat()
    } catch (e: NumberFormatException) {
        default
    }
}, default)

fun String?.toDoubleWithNull(default: Double = 0.toDouble()) = isNullOrBlank().not().then({
    try {
        this!!.toDouble()
    } catch (e: NumberFormatException) {
        default
    }
}, default)

<|start_filename|>app/src/main/java/com/safframework/app/MainActivity.kt<|end_filename|>
package com.safframework.app

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.safframework.log.L
import com.safframework.utils.getDeviceUsableMemory
import com.safframework.utils.getSDKVersion

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        L.i("可用内存：" + getDeviceUsableMemory(this))
        L.i("sdk版本：" + getSDKVersion())
    }
}


<|start_filename|>saf-kotlin-ext/src/main/java/com/safframework/ext/SystemService+Extension.kt<|end_filename|>
package com.safframework.ext

import android.accounts.AccountManager
import android.annotation.TargetApi
import android.app.*
import android.app.admin.DevicePolicyManager
import android.app.job.JobScheduler
import android.appwidget.AppWidgetManager
import android.bluetooth.BluetoothManager
import android.content.ClipboardManager
import android.content.Context
import android.content.RestrictionsManager
import android.content.pm.LauncherApps
import android.hardware.ConsumerIrManager
import android.hardware.SensorManager
import android.hardware.camera2.CameraManager
import android.hardware.display.DisplayManager
import android.hardware.input.InputManager
import android.hardware.usb.UsbManager
import android.location.LocationManager
import android.media.AudioManager
import android.media.MediaRouter
import android.media.projection.MediaProjectionManager
import android.media.session.MediaSessionManager
import android.media.tv.TvInputManager
import android.net.ConnectivityManager
import android.net.nsd.NsdManager
import android.net.wifi.WifiManager
import android.net.wifi.p2p.WifiP2pManager
import android.nfc.NfcManager
import android.os.*
import android.os.storage.StorageManager
import android.print.PrintManager
import android.service.wallpaper.WallpaperService
import android.telecom.TelecomManager
import android.telephony.TelephonyManager
import android.view.LayoutInflater
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.CaptioningManager
import android.view.inputmethod.InputMethodManager
import android.view.textservice.TextServicesManager
import androidx.annotation.RequiresApi

/**
 * Created by <NAME> on 2017/6/30.
 */

val Context.accessibilityManager: AccessibilityManager?
    get() =
    getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager

val Context.accountManager: AccountManager?
    get() =
    getSystemService(Context.ACCOUNT_SERVICE) as AccountManager

val Context.activityManager: ActivityManager
    get() =
    getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.alarmManager: AlarmManager
    get() =
    getSystemService(Context.ALARM_SERVICE) as AlarmManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.appWidgetManager(): AppWidgetManager? =
        getSystemService(Context.APPWIDGET_SERVICE) as AppWidgetManager

@TargetApi(Build.VERSION_CODES.KITKAT)
fun Context.appOpsManager(): AppOpsManager? =
        getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

val Context.audioManager: AudioManager
    get() =
    getSystemService(Context.AUDIO_SERVICE) as AudioManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.batteryManager(): BatteryManager? =
        getSystemService(Context.BATTERY_SERVICE) as BatteryManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
fun Context.bluetoothAdapter(): BluetoothManager? =
        getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.cameraManager(): CameraManager? =
        getSystemService(Context.CAMERA_SERVICE) as CameraManager

@TargetApi(Build.VERSION_CODES.KITKAT)
fun Context.captioningManager(): CaptioningManager? =
        getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager

val Context.clipboardManager: ClipboardManager
    get() =
    getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

val Context.connectivityManager: ConnectivityManager
    get() =
    getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

@TargetApi(Build.VERSION_CODES.KITKAT)
fun Context.consumerIrManager(): ConsumerIrManager? =
        getSystemService(Context.CONSUMER_IR_SERVICE) as ConsumerIrManager

val Context.devicePolicyManager: DevicePolicyManager?
    get() =
    getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
fun Context.displayManager(): DisplayManager? =
        getSystemService(Context.DISPLAY_SERVICE) as DisplayManager

val Context.downloadManager: DownloadManager?
    get() =
    getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

val Context.dropBoxManager: DropBoxManager?
    get() =
    getSystemService(Context.DROPBOX_SERVICE) as DropBoxManager

val Context.inputMethodManager: InputMethodManager?
    get() =
    getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
fun Context.inputManager(): InputManager? =
        getSystemService(Context.INPUT_SERVICE) as InputManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.jobScheduler(): JobScheduler? =
        getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

val Context.keyguardManager: KeyguardManager
    get() =
    getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.launcherApps(): LauncherApps? =
        getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps

val Context.layoutInflater: LayoutInflater
    get() =
    getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

val Context.locationManager: LocationManager
    get() =
    getSystemService(Context.LOCATION_SERVICE) as LocationManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.mediaProjectionManager(): MediaProjectionManager? =
        getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
fun Context.mediaRouter(): MediaRouter? =
        getSystemService(Context.MEDIA_ROUTER_SERVICE) as MediaRouter

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.mediaSessionManager(): MediaSessionManager? =
        getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager

val Context.nfcManager: NfcManager?
    get() =
    getSystemService(Context.NFC_SERVICE) as NfcManager

val Context.notificationManager: NotificationManager
    get() =
    getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
fun Context.nsdManager(): NsdManager? =
        getSystemService(Context.NSD_SERVICE) as NsdManager

val Context.powerManager: PowerManager
    get() =
    getSystemService(Context.POWER_SERVICE) as PowerManager

@TargetApi(Build.VERSION_CODES.KITKAT)
fun Context.printManager(): PrintManager? =
        getSystemService(Context.PRINT_SERVICE) as PrintManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.restrictionsManager(): RestrictionsManager? =
        getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

val Context.searchManager: SearchManager
    get() =
    getSystemService(Context.SEARCH_SERVICE) as SearchManager

val Context.sensorManager: SensorManager
    get() =
    getSystemService(Context.SENSOR_SERVICE) as SensorManager

val Context.storageManager: StorageManager?
    get() =
    getSystemService(Context.STORAGE_SERVICE) as StorageManager

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.telecomManager(): TelecomManager? =
        getSystemService(Context.TELECOM_SERVICE) as TelecomManager

val Context.telephonyManager: TelephonyManager
    get() =
    getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

val Context.textServicesManager: TextServicesManager?
    get() =
    getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE) as TextServicesManager

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun Context.tvInputManager(): TvInputManager? =
        getSystemService(Context.TV_INPUT_SERVICE) as TvInputManager

val Context.uiModeManager: UiModeManager?
    get() =
    getSystemService(Context.UI_MODE_SERVICE) as UiModeManager

val Context.usbManager: UsbManager?
    get() =
    getSystemService(Context.USB_SERVICE) as UsbManager

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
fun Context.userManager(): UserManager? =
        getSystemService(Context.USER_SERVICE) as UserManager

val Context.vibrator: Vibrator
    get() =
    getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

val Context.wallpaperService: WallpaperService
    get() =
    getSystemService(Context.WALLPAPER_SERVICE) as WallpaperService

val Context.wifiP2pManager: WifiP2pManager?
    get() =
    getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager

val Context.wifiManager: WifiManager
    get() =
    getSystemService(Context.WIFI_SERVICE) as WifiManager

val Context.windowService: WindowManager
    get() =
    getSystemService(Context.WINDOW_SERVICE) as WindowManager

<|start_filename|>saf-kotlin-utils/src/main/java/com/safframework/utils/ProcessUtils.kt<|end_filename|>
package com.safframework.utils

import android.app.ActivityManager
import android.app.AppOpsManager
import android.app.usage.UsageStats
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Settings
import com.safframework.tony.common.utils.Preconditions
import java.util.*

/**
 * Created by tony on 2017/2/26
 */
object ProcessUtils {

    /**
     * 获取前台线程包名
     * 当不是查看当前App，且SDK大于21时，
     * 需添加权限 <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
     *
     * @param context 上下文
     * @return 前台应哟过包名
     */
    @JvmStatic
    fun getForegroundProcessName(context: Context): String? {
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        am.runningAppProcesses.map {
            if (it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return it.processName
            }
        }
        if (Build.VERSION.SDK_INT > 21) {
            val pm = context.packageManager
            val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
            val list = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
            if (list.size > 0) {
                try {
                    val ai = pm.getApplicationInfo(context.packageName, 0)
                    val aom = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
                    if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, ai.uid, ai.packageName) != AppOpsManager.MODE_ALLOWED) {
                        context.startActivity(intent)
                        return null
                    }
                    val usm = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
                    val endTime = System.currentTimeMillis()
                    val beginTime = endTime - 86400000 * 7
                    val usageStats = usm.queryUsageStats(UsageStatsManager.INTERVAL_BEST, beginTime, endTime)
                    if (usageStats == null || usageStats.isEmpty()) {
                        return null
                    }
                    var recentStats : UsageStats? = null
                    usageStats.map {
                        if (recentStats == null || it.lastTimeUsed > (recentStats as UsageStats).lastTimeUsed) {
                            recentStats = it
                        }
                    }
                    return recentStats?.packageName
                } catch (e: PackageManager.NameNotFoundException) {
                    e.printStackTrace()
                }
            }
        }
        return null
    }

    /**
     * 获取所有的后台进程
     * 需添加权限 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
     *
     * @param context 上下文
     * @return 所有的后台进程的set
     */
    @JvmStatic
    fun getAllBackgroundProcesses(context: Context): HashSet<String> {
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val set = HashSet<String>()
        am.runningAppProcesses.map {
            set.addAll(it.pkgList)
        }
        return set
    }

    /**
     * 杀死所有的后台进程
     * 需添加权限 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
     *
     * @param context 上下文
     * @return 被杀死的后台进程的set
     */
    @JvmStatic
    fun killAllBackgroundProcesses(context: Context): HashSet<String> {
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val set = HashSet<String>()
        am.runningAppProcesses.map {
            it.pkgList.map {
                am.killBackgroundProcesses(it)
                set.add(it)
            }
        }
        am.runningAppProcesses.map {
            it.pkgList.map {
                set.remove(it)
            }
        }
        return set
    }

    /**
     * 杀死后台进程服务
     * 需添加权限 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
     *
     * @param context 上下文
     * @param packageName 包名
     * @return boolean
     */
    @JvmStatic
    fun killBackgroundProcesses(context: Context, packageName: String?): Boolean {
        if (Preconditions.isBlank(packageName)) {
            return false
        }

        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        am.runningAppProcesses.map {
            if (it.pkgList.asList().contains(packageName)) {
                am.killBackgroundProcesses(packageName)
            }
        }
        am.runningAppProcesses.map {
            if (it.pkgList.toList().contains(packageName)) {
                return false
            }
        }
        return true
    }
}

<|start_filename|>saf-kotlin-ext/src/main/java/com/safframework/ext/View+Extension.kt<|end_filename|>
package com.safframework.ext

import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import android.view.View
import android.view.inputmethod.InputMethodManager

/**
 * Created by <NAME> on 2017/6/30.
 */

val View.isVisible: Boolean
    get() = visibility == View.VISIBLE
val View.isInvisible: Boolean
    get() = visibility == View.INVISIBLE
val View.isGone: Boolean
    get() = visibility == View.GONE

fun View.hideKeyboard():Boolean {
    clearFocus()
    return (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(windowToken, 0)
}

fun View.showKeyboard():Boolean {
    requestFocus()
    return (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}

/**
 * 默认的时间单位是毫秒
 */
inline fun View.postDelayed(delay: Long, crossinline action: () -> Unit): Runnable {
    val runnable = Runnable { action() }
    postDelayed(runnable, delay)
    return runnable
}

/***************************延迟点击相关 Start******************************/

/***
 * 设置延迟时间的View扩展
 * @param delay Long 延迟时间，默认600毫秒
 * @return T
 */
fun <T : View> T.withTrigger(delay: Long = 600): T {
    triggerDelay = delay
    return this
}

/***
 * 点击事件的View扩展
 * @param block: (T) -> Unit 函数
 * @return Unit
 */
fun <T : View> T.click(block: (T) -> Unit) = setOnClickListener {

    if (clickEnable()) {
        block(it as T)
    }
}

/***
 * 带延迟过滤的点击事件View扩展
 * @param delay Long 延迟时间，默认600毫秒
 * @param block: (T) -> Unit 函数
 * @return Unit
 */
fun <T : View> T.clickWithTrigger(time: Long = 600, block: (T) -> Unit){
    triggerDelay = time
    setOnClickListener {
        if (clickEnable()) {
            block(it as T)
        }
    }
}

private var <T : View> T.triggerLastTime: Long
    get() = if (getTag(1123460103) != null) getTag(1123460103) as Long else 0
    set(value) {
        setTag(1123460103, value)
    }

private var <T : View> T.triggerDelay: Long
    get() = if (getTag(1123461123) != null) getTag(1123461123) as Long else 600
    set(value) {
        setTag(1123461123, value)
    }

private fun <T : View> T.clickEnable(): Boolean {
    var flag = false
    val currentClickTime = System.currentTimeMillis()
    if (currentClickTime - triggerLastTime >= triggerDelay) {
        flag = true
    }
    triggerLastTime = currentClickTime
    return flag
}

/***
 * 带延迟过滤的点击事件监听 View.OnClickListener
 * 延迟时间根据triggerDelay获取：600毫秒，不能动态设置
 */
interface OnLazyClickListener : View.OnClickListener {

    override fun onClick(v: View?) {
        if (v?.clickEnable() == true) {
            onLazyClick(v)
        }
    }

    fun onLazyClick(v: View)
}
/***************************延迟点击相关 End******************************/

fun <T : View> T.longClick(block: (T) -> Boolean) = setOnLongClickListener { block(it as T) }

fun View.toBitmap(): Bitmap?{
    clearFocus()
    isPressed = false
    val willNotCache = willNotCacheDrawing()
    setWillNotCacheDrawing(false)
    // Reset the drawing cache background color to fully transparent
    // for the duration of this operation
    val color = drawingCacheBackgroundColor
    drawingCacheBackgroundColor = 0
    if (color != 0) destroyDrawingCache()
    buildDrawingCache()
    val cacheBitmap = drawingCache
    if (cacheBitmap == null) {
        Log.e("Views", "failed to get bitmap from $this", RuntimeException())
        return null
    }
    val bitmap = Bitmap.createBitmap(cacheBitmap)
    // Restore the view
    destroyDrawingCache()
    setWillNotCacheDrawing(willNotCache)
    drawingCacheBackgroundColor = color
    return bitmap
}

<|start_filename|>saf-kotlin-utils/src/main/java/com/safframework/utils/ToastUtils.kt<|end_filename|>
package com.safframework.utils

import android.app.Activity
import android.content.Context
import android.text.TextUtils
import android.widget.Toast
import java.text.MessageFormat

/**
 * Created by <NAME> on 2017/2/28.
 */


/**
 * @param activity
 *
 * @param resId string资源id
 *
 * @param duration
 */
private fun showToast(activity: Activity?, resId: Int,
                      duration: Int) {
    if (activity == null)
        return

    val context = activity.application
    activity.runOnUiThread { Toast.makeText(context, resId, duration).show() }
}

/**
 * @param activity
 *
 * @param message toast的内容
 *
 * @param duration
 */
private fun showToast(activity: Activity?, message: String,
                      duration: Int) {
    if (activity == null)
        return
    if (TextUtils.isEmpty(message))
        return

    val context = activity.application
    activity.runOnUiThread { Toast.makeText(context, message, duration).show() }
}

fun showToast(context: Context?, resId: Int,
              duration: Int) {
    if (context == null)
        return

    (context as Activity).runOnUiThread {
        Toast.makeText(context.applicationContext, resId,
                duration).show()
    }
}

fun showToast(context: Context?, message: String,
              duration: Int) {
    if (context == null)
        return

    (context as Activity).runOnUiThread {
        Toast.makeText(context.applicationContext, message,
                duration).show()
    }

}

fun showLong(activity: Activity?, resId: Int) {
    showToast(activity, resId, Toast.LENGTH_LONG)
}

fun showLong(activity: Activity?, message: String) {
    showToast(activity, message, Toast.LENGTH_LONG)
}

fun showLong(activity: Activity?, message: String,
             vararg args: Any) {
    val formatted = MessageFormat.format(message, *args)
    showToast(activity, formatted, Toast.LENGTH_LONG)
}

fun showLong(activity: Activity?, resId: Int,
             vararg args: Any) {
    if (activity == null)
        return

    val message = activity.getString(resId)
    showLong(activity, message, *args)
}

fun showLong(context: Context?, resId: Int) {
    showToast(context, resId, Toast.LENGTH_LONG)
}

fun showLong(context: Context?, message: String) {
    showToast(context, message, Toast.LENGTH_LONG)
}

fun showShort(activity: Activity?, resId: Int) {
    showToast(activity, resId, Toast.LENGTH_SHORT)
}

fun showShort(activity: Activity?, message: String) {
    showToast(activity, message, Toast.LENGTH_SHORT)
}

fun showShort(activity: Activity?, message: String,
              vararg args: Any) {
    val formatted = MessageFormat.format(message, *args)
    showToast(activity, formatted, Toast.LENGTH_SHORT)
}

fun showShort(activity: Activity?, resId: Int,
              vararg args: Any) {
    if (activity == null)
        return

    val message = activity.getString(resId)
    showShort(activity, message, *args)
}

fun showShort(context: Context?, resId: Int) {
    showToast(context, resId, Toast.LENGTH_SHORT)
}

fun showShort(context: Context?, message: String) {
    showToast(context, message, Toast.LENGTH_SHORT)
}
