新增:自动任务-快捷指令-警报提醒动作添加闪烁手机的功能 #581

This commit is contained in:
pppscn 2025-03-21 19:12:06 +08:00
parent 0391868790
commit 114052d1c6
10 changed files with 332 additions and 11 deletions

View File

@ -6,6 +6,10 @@
<uses-feature <uses-feature
android:name="android.hardware.telephony" android:name="android.hardware.telephony"
android:required="false" /> android:required="false" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature
android:name="android.hardware.camera.flash"
android:required="false" />
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" /> <uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
<uses-permission <uses-permission
@ -74,6 +78,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<application <application
android:name=".App" android:name=".App"

View File

@ -10,4 +10,6 @@ data class AlarmSetting(
var music: String = "", //音乐文件 var music: String = "", //音乐文件
var repeatTimes: Int = 5, //振动重复次数0=无限循环,-1=禁用 var repeatTimes: Int = 5, //振动重复次数0=无限循环,-1=禁用
var vibrate: String = "---___===___", //振动律动:=强振动, -弱震动, _不振动, 时长都是100ms var vibrate: String = "---___===___", //振动律动:=强振动, -弱震动, _不振动, 时长都是100ms
var flashTimes: Int = 5, //闪烁次数0=无限循环,-1=禁用
var flash: String = "XXOOXXOO", //闪烁律动X亮灯, O灭灯, 时长都是100ms
) : Serializable ) : Serializable

View File

@ -38,6 +38,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
import java.io.File import java.io.File
import java.util.Date import java.util.Date
import java.util.Locale
@Page(name = "Alarm") @Page(name = "Alarm")
@Suppress("PrivatePropertyName", "DEPRECATION") @Suppress("PrivatePropertyName", "DEPRECATION")
@ -103,10 +104,12 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
binding!!.rgAlarmState.check(R.id.rb_start_alarm) binding!!.rgAlarmState.check(R.id.rb_start_alarm)
binding!!.layoutAlarmSettings.visibility = View.VISIBLE binding!!.layoutAlarmSettings.visibility = View.VISIBLE
binding!!.layoutVibrateSettings.visibility = View.VISIBLE binding!!.layoutVibrateSettings.visibility = View.VISIBLE
binding!!.layoutFlashSettings.visibility = View.VISIBLE
} else { } else {
binding!!.rgAlarmState.check(R.id.rb_stop_alarm) binding!!.rgAlarmState.check(R.id.rb_stop_alarm)
binding!!.layoutAlarmSettings.visibility = View.GONE binding!!.layoutAlarmSettings.visibility = View.GONE
binding!!.layoutVibrateSettings.visibility = View.GONE binding!!.layoutVibrateSettings.visibility = View.GONE
binding!!.layoutFlashSettings.visibility = View.GONE
} }
} }
binding!!.xsbVolume.setDefaultValue(settingVo.volume) binding!!.xsbVolume.setDefaultValue(settingVo.volume)
@ -114,8 +117,14 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
binding!!.etMusicPath.setText(settingVo.music) binding!!.etMusicPath.setText(settingVo.music)
binding!!.xsbRepeatTimes.setDefaultValue(if (settingVo.repeatTimes >= 0) settingVo.repeatTimes else 0) binding!!.xsbRepeatTimes.setDefaultValue(if (settingVo.repeatTimes >= 0) settingVo.repeatTimes else 0)
binding!!.etVibrationEffect.setText(settingVo.vibrate) binding!!.etVibrationEffect.setText(settingVo.vibrate)
binding!!.xsbFlashTimes.setDefaultValue(if (settingVo.flashTimes >= 0) settingVo.flashTimes else 0)
binding!!.etFlashEffect.setText(settingVo.flash)
binding!!.sbEnableMusic.isChecked = settingVo.playTimes >= 0 binding!!.sbEnableMusic.isChecked = settingVo.playTimes >= 0
binding!!.sbEnableVibrate.isChecked = settingVo.repeatTimes >= 0 binding!!.sbEnableVibrate.isChecked = settingVo.repeatTimes >= 0
binding!!.sbEnableFlash.isChecked = settingVo.flashTimes >= 0
binding!!.layoutAlarmSettingsContent.visibility = if (settingVo.playTimes >= 0) View.VISIBLE else View.GONE
binding!!.layoutVibrateSettingsContent.visibility = if (settingVo.repeatTimes >= 0) View.VISIBLE else View.GONE
binding!!.layoutFlashSettingsContent.visibility = if (settingVo.flashTimes >= 0) View.VISIBLE else View.GONE
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -135,13 +144,20 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
binding!!.xsbPlayTimes.setOnSeekBarListener { _, _ -> binding!!.xsbPlayTimes.setOnSeekBarListener { _, _ ->
checkSetting(true) checkSetting(true)
} }
binding!!.xsbRepeatTimes.setOnSeekBarListener { _, _ ->
checkSetting(true)
}
binding!!.rgAlarmState.setOnCheckedChangeListener { _, checkedId -> binding!!.rgAlarmState.setOnCheckedChangeListener { _, checkedId ->
binding!!.layoutAlarmSettings.visibility = if (checkedId == R.id.rb_start_alarm) View.VISIBLE else View.GONE binding!!.layoutAlarmSettings.visibility = if (checkedId == R.id.rb_start_alarm) View.VISIBLE else View.GONE
binding!!.layoutVibrateSettings.visibility = if (checkedId == R.id.rb_start_alarm) View.VISIBLE else View.GONE
binding!!.layoutFlashSettings.visibility = if (checkedId == R.id.rb_start_alarm) View.VISIBLE else View.GONE
checkSetting(true) checkSetting(true)
} }
binding!!.btInsertVibrationEffect1.setOnClickListener(this) binding!!.btInsertVibrationEffect1.setOnClickListener(this)
binding!!.btInsertVibrationEffect2.setOnClickListener(this) binding!!.btInsertVibrationEffect2.setOnClickListener(this)
binding!!.btInsertVibrationEffect3.setOnClickListener(this) binding!!.btInsertVibrationEffect3.setOnClickListener(this)
binding!!.btInsertFlashEffect1.setOnClickListener(this)
binding!!.btInsertFlashEffect2.setOnClickListener(this)
} }
@SingleClick @SingleClick
@ -163,6 +179,16 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
return return
} }
R.id.bt_insert_flash_effect_1 -> {
CommonUtils.insertOrReplaceText2Cursor(binding!!.etFlashEffect, "X")
return
}
R.id.bt_insert_flash_effect_2 -> {
CommonUtils.insertOrReplaceText2Cursor(binding!!.etFlashEffect, "O")
return
}
R.id.btn_file_picker -> { R.id.btn_file_picker -> {
// 申请储存权限 // 申请储存权限
XXPermissions.with(this).permission(Permission.MANAGE_EXTERNAL_STORAGE).request(object : OnPermissionCallback { XXPermissions.with(this).permission(Permission.MANAGE_EXTERNAL_STORAGE).request(object : OnPermissionCallback {
@ -196,15 +222,20 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
} }
R.id.btn_test -> { R.id.btn_test -> {
val permissions = arrayListOf<String>()
permissions.add(Permission.WRITE_SETTINGS)
if (binding!!.sbEnableFlash.isChecked) {
permissions.add(Permission.CAMERA)
}
// 申请修改系统设置权限 // 申请修改系统设置权限
XXPermissions.with(this).permission(Permission.WRITE_SETTINGS).request(object : OnPermissionCallback { XXPermissions.with(this).permission(permissions).request(object : OnPermissionCallback {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onGranted(permissions: List<String>, all: Boolean) { override fun onGranted(permissions: List<String>, all: Boolean) {
mCountDownHelper?.start() mCountDownHelper?.start()
try { try {
val settingVo = checkSetting() val settingVo = checkSetting()
Log.d(TAG, settingVo.toString()) Log.d(TAG, settingVo.toString())
if (settingVo.playTimes < 0 && settingVo.repeatTimes < 0) { if (settingVo.playTimes < 0 && settingVo.repeatTimes < 0 && settingVo.flashTimes < 0) {
XToastUtils.error(getString(R.string.alarm_settings_error)) XToastUtils.error(getString(R.string.alarm_settings_error))
return return
} }
@ -242,12 +273,17 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
} }
R.id.btn_save -> { R.id.btn_save -> {
val permissions = arrayListOf<String>()
permissions.add(Permission.WRITE_SETTINGS)
if (binding!!.sbEnableFlash.isChecked) {
permissions.add(Permission.CAMERA)
}
// 申请修改系统设置权限 // 申请修改系统设置权限
XXPermissions.with(this).permission(Permission.WRITE_SETTINGS).request(object : OnPermissionCallback { XXPermissions.with(this).permission(permissions).request(object : OnPermissionCallback {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onGranted(permissions: List<String>, all: Boolean) { override fun onGranted(permissions: List<String>, all: Boolean) {
val settingVo = checkSetting() val settingVo = checkSetting()
if (settingVo.playTimes < 0 && settingVo.repeatTimes < 0) { if (settingVo.playTimes < 0 && settingVo.repeatTimes < 0 && settingVo.flashTimes < 0) {
XToastUtils.error(getString(R.string.alarm_settings_error)) XToastUtils.error(getString(R.string.alarm_settings_error))
return return
} }
@ -285,11 +321,14 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
private fun checkSetting(updateView: Boolean = false): AlarmSetting { private fun checkSetting(updateView: Boolean = false): AlarmSetting {
val enableMusic = binding!!.sbEnableMusic.isChecked val enableMusic = binding!!.sbEnableMusic.isChecked
val enableVibrate = binding!!.sbEnableVibrate.isChecked val enableVibrate = binding!!.sbEnableVibrate.isChecked
val enableFlash = binding!!.sbEnableFlash.isChecked
val volume = binding!!.xsbVolume.selectedNumber val volume = binding!!.xsbVolume.selectedNumber
var playTimes = binding!!.xsbPlayTimes.selectedNumber var playTimes = binding!!.xsbPlayTimes.selectedNumber
val music = binding!!.etMusicPath.text.toString().trim() val music = binding!!.etMusicPath.text.toString().trim()
var repeatTimes = binding!!.xsbRepeatTimes.selectedNumber var repeatTimes = binding!!.xsbRepeatTimes.selectedNumber
val vibrationEffect = binding!!.etVibrationEffect.text.toString().trim() val vibrationEffect = binding!!.etVibrationEffect.text.toString().trim()
var flashTimes = binding!!.xsbFlashTimes.selectedNumber
var flashEffect = binding!!.etFlashEffect.text.toString().trim()
val description = StringBuilder() val description = StringBuilder()
val action = if (binding!!.rgAlarmState.checkedRadioButtonId == R.id.rb_start_alarm) { val action = if (binding!!.rgAlarmState.checkedRadioButtonId == R.id.rb_start_alarm) {
description.append(getString(R.string.start_alarm)) description.append(getString(R.string.start_alarm))
@ -309,6 +348,14 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
} else { } else {
repeatTimes = -1 repeatTimes = -1
} }
if (enableFlash) {
flashEffect.ifEmpty { "XXOOXXOO".also { binding!!.etFlashEffect.setText(it) } }
flashEffect = flashEffect.toUpperCase(Locale.ROOT).replace("1", "X").replace("0", "O")
description.append(", ").append(getString(R.string.alarm_flash_effect)).append(":").append(flashEffect)
description.append(", ").append(getString(R.string.alarm_repeat_times)).append(":").append(flashTimes)
} else {
flashTimes = -1
}
"start" "start"
} else { } else {
description.append(getString(R.string.stop_alarm)) description.append(getString(R.string.stop_alarm))
@ -319,7 +366,7 @@ class AlarmFragment : BaseFragment<FragmentTasksActionAlarmBinding?>(), View.OnC
binding!!.tvDescription.text = description.toString() binding!!.tvDescription.text = description.toString()
} }
return AlarmSetting(description.toString(), action, volume, playTimes, music, repeatTimes, vibrationEffect) return AlarmSetting(description.toString(), action, volume, playTimes, music, repeatTimes, vibrationEffect, flashTimes, flashEffect)
} }
private fun findAudioFiles(directoryPath: String): List<String> { private fun findAudioFiles(directoryPath: String): List<String> {

View File

@ -36,6 +36,7 @@ import com.idormy.sms.forwarder.utils.EXTRA_UPDATE_NOTIFICATION
import com.idormy.sms.forwarder.utils.FRONT_CHANNEL_ID import com.idormy.sms.forwarder.utils.FRONT_CHANNEL_ID
import com.idormy.sms.forwarder.utils.FRONT_CHANNEL_NAME import com.idormy.sms.forwarder.utils.FRONT_CHANNEL_NAME
import com.idormy.sms.forwarder.utils.FRONT_NOTIFY_ID import com.idormy.sms.forwarder.utils.FRONT_NOTIFY_ID
import com.idormy.sms.forwarder.utils.FlashUtils
import com.idormy.sms.forwarder.utils.INTENT_FRPC_APPLY_FILE import com.idormy.sms.forwarder.utils.INTENT_FRPC_APPLY_FILE
import com.idormy.sms.forwarder.utils.Log import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SettingUtils import com.idormy.sms.forwarder.utils.SettingUtils
@ -97,6 +98,10 @@ class ForegroundService : Service() {
private lateinit var vibrationUtils: VibrationUtils private lateinit var vibrationUtils: VibrationUtils
private var isVibrating = false private var isVibrating = false
// 闪光灯控制
private lateinit var flashUtils: FlashUtils
private var isFlash = false
// 音乐播放器 // 音乐播放器
private var alarmPlayer: MediaPlayer? = null private var alarmPlayer: MediaPlayer? = null
private var alarmPlayTimes = 0 private var alarmPlayTimes = 0
@ -106,6 +111,10 @@ class ForegroundService : Service() {
if (vibrationUtils.isVibrating) { if (vibrationUtils.isVibrating) {
vibrationUtils.stopVibration() vibrationUtils.stopVibration()
} }
//停止闪光灯
if (flashUtils.isFlashing) {
flashUtils.stopFlashing()
}
//停止播放音乐 //停止播放音乐
alarmPlayer?.release() alarmPlayer?.release()
alarmPlayer = null alarmPlayer = null
@ -182,6 +191,11 @@ class ForegroundService : Service() {
isVibrating = true isVibrating = true
vibrationUtils.startVibration(alarm.vibrate, alarm.repeatTimes) vibrationUtils.startVibration(alarm.vibrate, alarm.repeatTimes)
} }
//闪光灯提醒
if (alarm.flashTimes >= 0) {
isFlash = true
flashUtils.startFlashing(alarm.flash, alarm.flashTimes)
}
} }
} }
@ -200,6 +214,9 @@ class ForegroundService : Service() {
//初始化振动 //初始化振动
vibrationUtils = VibrationUtils(this) vibrationUtils = VibrationUtils(this)
//初始化闪光灯
flashUtils = FlashUtils(this)
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -235,7 +252,7 @@ class ForegroundService : Service() {
override fun onDestroy() { override fun onDestroy() {
//非纯客户端模式 //非纯客户端模式
if (!SettingUtils.enablePureClientMode) stopForegroundService() if (!SettingUtils.enablePureClientMode) stopForegroundService()
flashUtils.release()
super.onDestroy() super.onDestroy()
} }
@ -319,6 +336,10 @@ class ForegroundService : Service() {
if (vibrationUtils.isVibrating) { if (vibrationUtils.isVibrating) {
vibrationUtils.stopVibration() vibrationUtils.stopVibration()
} }
//停止闪光灯
if (flashUtils.isFlashing) {
flashUtils.stopFlashing()
}
} catch (e: Exception) { } catch (e: Exception) {
handleException(e, "stopForegroundService") handleException(e, "stopForegroundService")
} }

View File

@ -0,0 +1,116 @@
@file:Suppress("DEPRECATION")
package com.idormy.sms.forwarder.utils
import android.content.Context
import android.hardware.Camera
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
import android.os.Handler
import android.os.Looper
class FlashUtils(context: Context) {
private var cameraManager: CameraManager? = null
private var cameraId: String? = null
private var legacyCamera: Camera? = null
private var legacyParams: Camera.Parameters? = null
private var handler: Handler? = null
private val duration = 100L // 闪烁持续时间
var isFlashing = false
private set
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
cameraId = cameraManager?.cameraIdList?.get(0) // 获取后置摄像头 ID
} catch (e: CameraAccessException) {
e.printStackTrace()
}
} else {
try {
legacyCamera = Camera.open()
legacyParams = legacyCamera?.parameters
} catch (e: Exception) {
e.printStackTrace()
}
}
}
/**
* 按照模式控制闪光灯
* @param pattern 例如 "XXOOXXOO" X-O-
* @param repeatTimes 闪烁的重复次数0 表示无限循环
*/
fun startFlashing(pattern: String, repeatTimes: Int) {
if (isFlashing) return
isFlashing = true
handler = Handler(Looper.getMainLooper())
val sequence = pattern.toCharArray()
var index = 0
var repeatCount = 0
val runnable = object : Runnable {
override fun run() {
if (!isFlashing) return
val shouldFlash = sequence[index] == 'X' || sequence[index] == '1'
setFlashlight(shouldFlash)
index++
if (index >= sequence.size) {
index = 0
repeatCount++
if (repeatTimes != 0 && repeatCount >= repeatTimes) {
stopFlashing()
return
}
}
handler?.postDelayed(this, duration)
}
}
handler?.post(runnable)
}
/**
* 关闭闪光灯并停止模式
*/
fun stopFlashing() {
isFlashing = false
handler?.removeCallbacksAndMessages(null)
setFlashlight(false) // 确保停止后灯是关闭的
}
/**
* 设置闪光灯状态兼容 Android 4.4+
*/
private fun setFlashlight(enable: Boolean) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraManager?.setTorchMode(cameraId!!, enable)
} else {
legacyParams?.flashMode = if (enable) Camera.Parameters.FLASH_MODE_TORCH else Camera.Parameters.FLASH_MODE_OFF
legacyCamera?.parameters = legacyParams
if (enable) legacyCamera?.startPreview() else legacyCamera?.stopPreview()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 释放旧 API 资源
*/
fun release() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
legacyCamera?.stopPreview()
legacyCamera?.release()
legacyCamera = null
}
}
}

View File

@ -209,7 +209,6 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/layout_vibrate_settings" android:id="@+id/layout_vibrate_settings"
style="@style/BarStyle" style="@style/BarStyle"
@ -326,6 +325,116 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/layout_flash_settings"
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/alarm_flash_settings"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_enable_flash"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_flash_settings_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:background="?attr/xui_config_color_separator_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_flash_effect"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.ClearEditText
android:id="@+id/et_flash_effect"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:hint="@string/alarm_flash_effect_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_flash_effect_1"
style="@style/insertButtonStyle"
android:text="@string/alarm_flash_effect_1" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_flash_effect_2"
style="@style/insertButtonStyle"
android:layout_marginStart="5dp"
android:text="@string/alarm_flash_effect_2" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_repeat_times"
android:textStyle="bold" />
<com.xuexiang.xui.widget.picker.XSeekBar
android:id="@+id/xsb_flash_times"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:padding="0dp"
app:xsb_max="30"
app:xsb_min="0" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -1165,7 +1165,12 @@
<string name="alarm_vibration_effect_1">Strong vibration</string> <string name="alarm_vibration_effect_1">Strong vibration</string>
<string name="alarm_vibration_effect_2">Weak vibration</string> <string name="alarm_vibration_effect_2">Weak vibration</string>
<string name="alarm_vibration_effect_3">No vibration</string> <string name="alarm_vibration_effect_3">No vibration</string>
<string name="alarm_settings_error">At least one of Play Music/Vibrate Phone must be enabled</string> <string name="alarm_flash_settings">Flash Phone</string>
<string name="alarm_flash_effect">Flash Effect</string>
<string name="alarm_flash_effect_tips">Syntax: 1 or X [turn on flash], 0 or O [turn off flash], each time 100ms</string>
<string name="alarm_flash_effect_1">Turn on flash 100ms</string>
<string name="alarm_flash_effect_2">Turn off flash 100ms</string>
<string name="alarm_settings_error">At least one of Play Music/Vibrate Phone/Flash Phone must be enabled</string>
<string name="invalid_tag" formatted="false">%s tag is invalid: %s</string> <string name="invalid_tag" formatted="false">%s tag is invalid: %s</string>
<string name="invalid_task_name">Please input task name.</string> <string name="invalid_task_name">Please input task name.</string>

View File

@ -1166,7 +1166,12 @@
<string name="alarm_vibration_effect_1">强振动 100ms</string> <string name="alarm_vibration_effect_1">强振动 100ms</string>
<string name="alarm_vibration_effect_2">弱振动 100ms</string> <string name="alarm_vibration_effect_2">弱振动 100ms</string>
<string name="alarm_vibration_effect_3">不振动 100ms</string> <string name="alarm_vibration_effect_3">不振动 100ms</string>
<string name="alarm_settings_error">播放音乐/振动手机必须至少开启一个</string> <string name="alarm_flash_settings">闪烁手机</string>
<string name="alarm_flash_effect">闪光效果</string>
<string name="alarm_flash_effect_tips">语法1或X[开启闪光灯], 0或O[关闭闪光灯], 每次100ms</string>
<string name="alarm_flash_effect_1">开启闪光灯 100ms</string>
<string name="alarm_flash_effect_2">关闭闪光灯 100ms</string>
<string name="alarm_settings_error">播放音乐/振动手机/闪烁手机必须至少开启一个</string>
<string name="invalid_tag" formatted="false">%s 标签无效:%s</string> <string name="invalid_tag" formatted="false">%s 标签无效:%s</string>
<string name="invalid_task_name">请输入任务名称</string> <string name="invalid_task_name">请输入任务名称</string>

View File

@ -1166,7 +1166,13 @@
<string name="alarm_vibration_effect_1">強振動 100ms</string> <string name="alarm_vibration_effect_1">強振動 100ms</string>
<string name="alarm_vibration_effect_2">弱振動 100ms</string> <string name="alarm_vibration_effect_2">弱振動 100ms</string>
<string name="alarm_vibration_effect_3">不振動 100ms</string> <string name="alarm_vibration_effect_3">不振動 100ms</string>
<string name="alarm_settings_error">播放音樂/振動手機必須至少開啟一個</string> <string name="alarm_flash_settings">閃爍手機</string>
<string name="alarm_flash_effect">閃光效果</string>
<string name="alarm_flash_effect_tips">語法1或X[開啟閃光燈]0或O[關閉閃光燈]每次300毫秒</string>
<string name="alarm_flash_effect_1">開啟閃光燈 300毫秒</string>
<string name="alarm_flash_effect_2">關閉閃光燈 300毫秒</string>
<string name="alarm_settings_error">播放音樂/振動手機/閃爍手機必須至少開啟一個</string>
<string name="invalid_tag" formatted="false">%s 標籤無效:%s</string> <string name="invalid_tag" formatted="false">%s 標籤無效:%s</string>
<string name="invalid_task_name">請輸入任務名稱</string> <string name="invalid_task_name">請輸入任務名稱</string>

View File

@ -1195,7 +1195,12 @@
<string name="alarm_vibration_effect_1">强振动 100ms</string> <string name="alarm_vibration_effect_1">强振动 100ms</string>
<string name="alarm_vibration_effect_2">弱振动 100ms</string> <string name="alarm_vibration_effect_2">弱振动 100ms</string>
<string name="alarm_vibration_effect_3">不振动 100ms</string> <string name="alarm_vibration_effect_3">不振动 100ms</string>
<string name="alarm_settings_error">播放音乐/振动手机必须至少开启一个</string> <string name="alarm_flash_settings">闪烁手机</string>
<string name="alarm_flash_effect">闪光效果</string>
<string name="alarm_flash_effect_tips">语法1或X[开启闪光灯], 0或O[关闭闪光灯], 每次100ms</string>
<string name="alarm_flash_effect_1">开启闪光灯 100ms</string>
<string name="alarm_flash_effect_2">关闭闪光灯 100ms</string>
<string name="alarm_settings_error">播放音乐/振动手机/闪烁手机必须至少开启一个</string>
<string name="invalid_tag" formatted="false">%s 标签无效:%s</string> <string name="invalid_tag" formatted="false">%s 标签无效:%s</string>
<string name="invalid_task_name">请输入任务名称</string> <string name="invalid_task_name">请输入任务名称</string>