Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

2. 安装并打开MiCTS
- 如果幸运的话,在不需要root的情况下,打开MiCTS就会直接触发圈定即搜
- 如果提示`助理服务未运行`(例如ColorOS 16每次重启都会清空`voice_interaction_service`),执行一次`adb shell pm grant com.parallelc.micts android.permission.WRITE_SECURE_SETTINGS`(如果被拒绝,例如ColorOS国行版,可改为使用`adb install -r -g MiCTS.apk`重新安装),之后MiCTS会自动恢复助理服务
- 如果没有反应,大概率是因为Google对你的设备禁用了圈定即搜功能(可以通过在Logcat日志中查找`Omni invocation failed: not enabled`确认),在有root的情况下,可以尝试以下方法:
- 在LSPosed里激活模块,在[MiCTS设置](#进入设置的方式)里开启`Google机型伪装`后,强制重启Google
- 如果还是不行,使用[GMS-Flags](https://github.com/polodarb/GMS-Flags),将`com.google.android.apps.search.omnient.device`的flag`45631784`设为true
Expand Down
1 change: 1 addition & 0 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Trigger Circle to Search on any Android 9–16 device

2. Install and launch MiCTS
- If you're lucky, Circle to Search will be triggered directly without root when launching MiCTS
- If it shows `Assistant service not running` (e.g. ColorOS 16, where `voice_interaction_service` is cleared on every reboot), run once `adb shell pm grant com.parallelc.micts android.permission.WRITE_SECURE_SETTINGS` (if it is denied, e.g. on ColorOS CN, reinstall with `adb install -r -g MiCTS.apk` instead), then MiCTS will restore the assistant service automatically
- If nothing happened, most likely it's because Google disabled Circle to Search for your device (you can confirm by checking the message `Omni invocation failed: not enabled` in Logcat). Try the following **with root**:
- Activate the module in LSPosed, enable `Device spoof for Google` in the [MiCTS settings](#how-to-enter-settings), and force restart Google
- If it still doesn't work, then change `com.google.android.apps.search.omnient.device` flag `45631784` to true using [GMS-Flags](https://github.com/polodarb/GMS-Flags)
Expand Down
13 changes: 12 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />

<queries>
<intent>
<action android:name="android.speech.RecognitionService" />
</intent>
</queries>

<application
android:name=".MainApplication"
android:description="@string/xposed_description"
Expand Down
64 changes: 62 additions & 2 deletions app/src/main/java/com/parallelc/micts/ui/activity/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.parallelc.micts.ui.activity

import android.Manifest
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.AudioAttributes
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.os.SystemClock
import android.os.VibrationEffect
import android.os.Vibrator
import android.provider.Settings
import android.speech.RecognitionService
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
Expand Down Expand Up @@ -72,13 +78,67 @@ fun triggerCircleToSearch(entryPoint: Int, context: Context?, vibrate: Boolean):
return result
}

/**
* Some ROMs (e.g. ColorOS 16) keep the assistant role on Google but leave voice_interaction_service
* empty (it is cleared again on reboot), so no VoiceInteractionService is running and
* showSessionFromSession always returns false. Restore it from the assistant setting.
* Requires WRITE_SECURE_SETTINGS granted via adb.
* @return true if the setting was rewritten and the service needs time to bind
*/
fun restoreVoiceInteractionService(context: Context): Boolean {
return runCatching {
val resolver = context.contentResolver
if (!Settings.Secure.getString(resolver, "voice_interaction_service").isNullOrEmpty()) return false
val assistant = Settings.Secure.getString(resolver, "assistant")
val component = assistant?.let { ComponentName.unflattenFromString(it) } ?: return false
if (context.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) {
Log.w(LOG_TAG, "voice_interaction_service is empty, run: adb shell pm grant ${context.packageName} ${Manifest.permission.WRITE_SECURE_SETTINGS} " +
"(if denied, reinstall with: adb install -r -g <apk>)")
return false
}
Settings.Secure.putString(resolver, "voice_interaction_service", assistant)
if (Settings.Secure.getString(resolver, "voice_recognition_service").isNullOrEmpty()) {
context.packageManager.queryIntentServices(
Intent(RecognitionService.SERVICE_INTERFACE).setPackage(component.packageName),
PackageManager.MATCH_DISABLED_COMPONENTS
).firstOrNull()?.serviceInfo?.let {
Settings.Secure.putString(resolver, "voice_recognition_service", ComponentName(it.packageName, it.name).flattenToString())
}
}
Log.i(LOG_TAG, "restored voice_interaction_service to $assistant")
true
}.onFailure { e ->
Log.e(LOG_TAG, "restoreVoiceInteractionService failed: " + e.stackTraceToString())
}.getOrDefault(false)
}

fun isVoiceInteractionServiceMissing(context: Context): Boolean {
return runCatching {
val resolver = context.contentResolver
Settings.Secure.getString(resolver, "voice_interaction_service").isNullOrEmpty() &&
!Settings.Secure.getString(resolver, "assistant").isNullOrEmpty()
}.getOrDefault(false)
}

class MainActivity : ComponentActivity() {
suspend fun delayAndTrigger(delayMs: Long, vibrate: Boolean) {
val restored = restoreVoiceInteractionService(this)
if (delayMs > 0) {
delay(delayMs)
}
if (!triggerCircleToSearch(1, this, vibrate)) {
Toast.makeText(this, getString(R.string.trigger_failed), Toast.LENGTH_SHORT).show()
var result = triggerCircleToSearch(1, this, vibrate)
// The service binds asynchronously after the setting changes, retry until it is ready
var retries = if (restored) 20 else 0
while (!result && retries-- > 0) {
delay(100)
result = triggerCircleToSearch(1, this, vibrate)
}
if (!result) {
if (isVoiceInteractionServiceMissing(this)) {
Toast.makeText(this, getString(R.string.voice_interaction_service_missing), Toast.LENGTH_LONG).show()
} else {
Toast.makeText(this, getString(R.string.trigger_failed), Toast.LENGTH_SHORT).show()
}
}
finish()
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-vi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<string name="xposed_description">Kích hoạt tính năng Tìm kiếm vòng tròn trên bất kỳ thiết bị Android 9–16</string>
<string name="title_activity_settings">Cài đặt</string>
<string name="trigger_failed">Kích hoạt thất bại!</string>
<string name="voice_interaction_service_missing">Dịch vụ trợ lý chưa chạy. Hãy cấp quyền WRITE_SECURE_SETTINGS qua adb</string>
<string name="app_settings">Cài đặt ứng dụng</string>
<string name="default_trigger_delay">Độ trễ kích hoạt mặc định</string>
<string name="tile_trigger_delay">Độ trễ kích hoạt của ô lối tắt</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<string name="xposed_description">在任意Android 9–16设备上触发圈定即搜(Circle to Search)功能</string>
<string name="title_activity_settings">设置</string>
<string name="trigger_failed">触发失败!</string>
<string name="voice_interaction_service_missing">助理服务未运行,请通过adb授予WRITE_SECURE_SETTINGS权限</string>
<string name="app_settings">应用设置</string>
<string name="default_trigger_delay">默认触发延迟</string>
<string name="tile_trigger_delay">磁贴触发延迟</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="xposed_description">Trigger Circle to Search on any Android 9–16 device</string>
<string name="title_activity_settings">Settings</string>
<string name="trigger_failed">Trigger failed!</string>
<string name="voice_interaction_service_missing">Assistant service not running. Grant WRITE_SECURE_SETTINGS via adb</string>
<string name="app_settings">App Settings</string>
<string name="default_trigger_delay">Default trigger delay</string>
<string name="tile_trigger_delay">Tile trigger delay</string>
Expand Down
Loading