稍微完善输入法以及输入法体验页

This commit is contained in:
pengxiaolong
2025-12-11 14:52:29 +08:00
parent 867dad509e
commit 79b5bc0273
45 changed files with 2174 additions and 727 deletions

View File

@@ -5,28 +5,27 @@ import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.provider.Settings
import android.view.View
import android.util.Log
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplication.MyInputMethodService
class ImeGuideActivity : AppCompatActivity() {
private lateinit var btnEnable: LinearLayout
private lateinit var btnSelect: LinearLayout
private lateinit var tvStep1Status: TextView//
private lateinit var tvStep2Status: TextView//
private lateinit var btnEnabledText: TextView//
private lateinit var btnSelectText: TextView//
private lateinit var btnEnabledimg: ImageView//
private lateinit var btnSelectimg: ImageView//
private val TAG = "ImeGuideActivity"
// 改成可空,避免 findViewById 返回 null 时直接 NPE
private var btnEnable: LinearLayout? = null
private var btnSelect: LinearLayout? = null
private var tvStep1Status: TextView? = null
private var tvStep2Status: TextView? = null
private var btnEnabledText: TextView? = null
private var btnSelectText: TextView? = null
private var btnEnabledimg: ImageView? = null
private var btnSelectimg: ImageView? = null
private var imeObserver: android.database.ContentObserver? = null
@@ -34,68 +33,79 @@ class ImeGuideActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ime_guide)
// // 设置关闭按钮点击事件
// findViewById<FrameLayout>(R.id.iv_close).setOnClickListener {
// finish()
// }
Log.d(TAG, "onCreate")
btnEnable = findViewById(R.id.enabled)//btn启用输入法
btnSelect = findViewById(R.id.select)//btn选择输入法
tvStep1Status = findViewById(R.id.Steps)//第一步的提示
tvStep2Status = findViewById(R.id.stepTips)//第二步的提示
btnEnabledText = findViewById(R.id.btnEnabledText)//启用输入法按钮文字
btnSelectText = findViewById(R.id.btnSelectText)//选择输入法按钮文字
btnEnabledimg = findViewById(R.id.btnEnabledimg)//启用输入法按钮图片
btnSelectimg = findViewById(R.id.btnSelectimg)//选择输入法按钮图片
// // 第一步:启用输入法
// btnEnable.setOnClickListener {
// startActivity(Intent(Settings.ACTION_INPUT_METHOD_SETTINGS))
// }
// // 第二步:切换输入法
// btnSelect.setOnClickListener {
// val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
// imm.showInputMethodPicker()
// }
btnEnable = findViewById(R.id.enabled) // btn启用输入法
btnSelect = findViewById(R.id.select) // btn选择输入法
tvStep1Status = findViewById(R.id.Steps) // 第一步的提示
tvStep2Status = findViewById(R.id.stepTips) // 第二步的提示
btnEnabledText = findViewById(R.id.btnEnabledText) // 启用输入法按钮文字
btnSelectText = findViewById(R.id.btnSelectText) // 选择输入法按钮文字
btnEnabledimg = findViewById(R.id.btnEnabledimg) // 启用输入法按钮图片
btnSelectimg = findViewById(R.id.btnSelectimg) // 选择输入法按钮图片
}
override fun onResume() {
super.onResume()
refreshStatus()
registerImeObserver()
try {
refreshStatus()
} catch (e: Exception) {
Log.e(TAG, "refreshStatus 崩了", e)
}
try {
registerImeObserver()
} catch (e: Exception) {
Log.e(TAG, "registerImeObserver 崩了", e)
}
}
override fun onPause() {
super.onPause()
unregisterImeObserver()
try {
unregisterImeObserver()
} catch (e: Exception) {
Log.e(TAG, "unregisterImeObserver 崩了", e)
}
}
private fun registerImeObserver() {
if (imeObserver != null) return
imeObserver = object : android.database.ContentObserver(
android.os.Handler(android.os.Looper.getMainLooper())
) {
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
refreshStatus()
try {
refreshStatus()
} catch (e: Exception) {
Log.e(TAG, "onChange -> refreshStatus 崩了", e)
}
}
}
contentResolver.registerContentObserver(
android.provider.Settings.Secure.getUriFor(
android.provider.Settings.Secure.DEFAULT_INPUT_METHOD
),
false,
imeObserver!!
)
try {
contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.DEFAULT_INPUT_METHOD),
false,
imeObserver!!
)
} catch (e: SecurityException) {
// 部分 ROM/系统可能在这里抛异常
Log.e(TAG, "registerContentObserver SecurityException", e)
} catch (e: Exception) {
Log.e(TAG, "registerContentObserver 其他异常", e)
}
}
private fun unregisterImeObserver() {
imeObserver?.let {
contentResolver.unregisterContentObserver(it)
try {
contentResolver.unregisterContentObserver(it)
} catch (e: Exception) {
Log.e(TAG, "unregisterContentObserver 异常", e)
}
}
imeObserver = null
}
@@ -104,100 +114,144 @@ class ImeGuideActivity : AppCompatActivity() {
private fun refreshStatus() {
val enabled = isImeEnabled()
val selected = isImeSelected()
// 把所有 view 拿成局部变量并判空,避免 NPE
val enableLayout = btnEnable
val selectLayout = btnSelect
val step1 = tvStep1Status
val step2 = tvStep2Status
val enableText = btnEnabledText
val selectText = btnSelectText
val enableImg = btnEnabledimg
val selectImg = btnSelectimg
if (enableLayout == null || selectLayout == null ||
step1 == null || step2 == null ||
enableText == null || selectText == null ||
enableImg == null || selectImg == null
) {
Log.e(TAG, "有 View 为 null检查 activity_ime_guide.xml 的 id 是否匹配")
return
}
// 根据状态设置按钮的点击行为
if (enabled) {
// 输入法已启用时,禁用启用按钮的点击事件
btnEnable.setOnClickListener(null)
enableLayout.setOnClickListener(null)
} else {
// 输入法未启用时,设置启用按钮的点击事件
btnEnable.setOnClickListener {
enableLayout.setOnClickListener {
startActivity(Intent(Settings.ACTION_INPUT_METHOD_SETTINGS))
}
}
if (selected) {
// 输入法已切换时,禁用选择按钮的点击事件
btnSelect.setOnClickListener(null)
selectLayout.setOnClickListener(null)
} else {
// 输入法未切换时,设置选择按钮的点击事件
btnSelect.setOnClickListener {
selectLayout.setOnClickListener {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.showInputMethodPicker()
}
}
if(!enabled &&!selected) {
btnEnable.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
btnSelect.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
btnEnabledText.setTextColor(Color.parseColor("#FFFFFF"))
btnSelectText.setTextColor(Color.parseColor("#FFFFFF"))
btnEnabledimg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
btnSelectimg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
tvStep1Status.text = "Step one"
tvStep1Status.text = "Step one"
tvStep2Status.text = "Check to enable key of love"
}else if(!enabled && selected){
btnEnable.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
btnSelect.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
btnEnabledimg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
btnSelectimg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
btnEnabledText.setTextColor(Color.parseColor("#FFFFFF"))
btnSelectText.setTextColor(Color.parseColor("#FFFFFF"))
tvStep1Status.text = "Step one"
tvStep2Status.text = "Check to enable key of love"
}else if(enabled && !selected){
btnEnable.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
btnSelect.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
btnEnabledimg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
btnSelectimg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
btnEnabledText.setTextColor(Color.parseColor("#A1A1A1"))
btnSelectText.setTextColor(Color.parseColor("#FFFFFF"))
tvStep1Status.text = "Step two"
tvStep2Status.text = "Select key of love as your default input method"
}else if(enabled && selected){
btnEnable.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
btnSelect.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
btnEnabledimg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
btnSelectimg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
btnEnabledText.setTextColor(Color.parseColor("#A1A1A1"))
btnSelectText.setTextColor(Color.parseColor("#A1A1A1"))
tvStep1Status.text = "Completed"
tvStep2Status.text = "You have completed the relevant Settings"
if (!enabled && !selected) {
enableLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
selectLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
enableText.setTextColor(Color.parseColor("#FFFFFF"))
selectText.setTextColor(Color.parseColor("#FFFFFF"))
enableImg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
selectImg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
step1.text = "Step one"
step2.text = "Check to enable key of love"
} else if (!enabled && selected) {
enableLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
selectLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
enableImg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
selectImg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
enableText.setTextColor(Color.parseColor("#FFFFFF"))
selectText.setTextColor(Color.parseColor("#FFFFFF"))
step1.text = "Step one"
step2.text = "Check to enable key of love"
} else if (enabled && !selected) {
enableLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
selectLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_unfinished)
enableImg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
selectImg.setImageResource(R.drawable.ime_guide_activity_btn_unfinished_img)
enableText.setTextColor(Color.parseColor("#A1A1A1"))
selectText.setTextColor(Color.parseColor("#FFFFFF"))
step1.text = "Step two"
step2.text = "Select key of love as your default input method"
} else if (enabled && selected) {
enableLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
selectLayout.background = getDrawable(R.drawable.ime_guide_activity_btn_completed)
enableImg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
selectImg.setImageResource(R.drawable.ime_guide_activity_btn_completed_img)
enableText.setTextColor(Color.parseColor("#A1A1A1"))
selectText.setTextColor(Color.parseColor("#A1A1A1"))
step1.text = "Completed"
step2.text = "You have completed the relevant Settings"
Toast.makeText(this, "The input method is all set!", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, GuideActivity::class.java))
try {
startActivity(Intent(this, GuideActivity::class.java))
} catch (e: Exception) {
Log.e(TAG, "启动 GuideActivity 失败,检查是否在 Manifest 中声明", e)
}
finish()
}
}
/** 是否启用了本输入法 */
private fun isImeEnabled(): Boolean {
val enabledImes = Settings.Secure.getString(
contentResolver,
Settings.Secure.ENABLED_INPUT_METHODS
) ?: return false
// 用真正的类,而不是手写字符串
val myImeComponent = ComponentName(this, MyInputMethodService::class.java)
// 系统存的是 flattenToString() 的格式
val myImeId = myImeComponent.flattenToString()
// enabledImes 是一个用 ":" 分隔的列表
return enabledImes.split(':').contains(myImeId)
/** 是否启用了本输入法 */
private fun isImeEnabled(): Boolean {
return try {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
val myComponent = ComponentName(this, MyInputMethodService::class.java)
val result = imm.enabledInputMethodList.any { imeInfo ->
imeInfo.packageName == myComponent.packageName &&
imeInfo.serviceName == myComponent.className
}
Log.d(TAG, "isImeEnabled = $result")
result
} catch (e: Exception) {
Log.e(TAG, "isImeEnabled 出错", e)
false
}
}
/** 是否已切换为当前输入法 */
private fun isImeSelected(): Boolean {
val currentIme = Settings.Secure.getString(
/** 是否已切换为当前输入法 */
private fun isImeSelected(): Boolean {
return try {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
val myComponent = ComponentName(this, MyInputMethodService::class.java)
val currentImeId = Settings.Secure.getString(
contentResolver,
Settings.Secure.DEFAULT_INPUT_METHOD
) ?: return false
val myImeComponent = ComponentName(this, MyInputMethodService::class.java)
val myImeId = myImeComponent.flattenToString()
// 直接用同一种格式比对
return currentIme == myImeId
Log.d(TAG, "DEFAULT_INPUT_METHOD = $currentImeId")
// 找到“当前默认 IME”对应的 InputMethodInfo
val currentImeInfo = imm.enabledInputMethodList.firstOrNull { imeInfo ->
imeInfo.id == currentImeId
}
if (currentImeInfo == null) {
Log.d(TAG, "currentImeInfo == null")
return false
}
val isMine = currentImeInfo.packageName == myComponent.packageName &&
currentImeInfo.serviceName == myComponent.className
Log.d(TAG, "isImeSelected = $isMine")
isMine
} catch (e: Exception) {
Log.e(TAG, "isImeSelected 出错", e)
false
}
}
}