diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 19fbd6a5..a44321d0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -72,6 +72,7 @@ + - \ No newline at end of file + diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/action/AlarmSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/action/AlarmSetting.kt index aba773cd..2e51f526 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/entity/action/AlarmSetting.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/action/AlarmSetting.kt @@ -5,7 +5,9 @@ import java.io.Serializable data class AlarmSetting( var description: String = "", //描述 var action: String = "stop", //动作: start=启动警报, stop=停止警报 - var volume: Int = 80, //播放音量 + var volume: Int = 80, //播放音量,0=禁用 var playTimes: Int = 1, //播放次数,0=无限循环 var music: String = "", //音乐文件 + var repeatTimes: Int = 5, //振动重复次数,0=禁用 + var vibrate: String = "---___===___", //振动律动:=强振动, -弱震动, _不振动, 时长都是100ms ) : Serializable diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/AlarmFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/AlarmFragment.kt index cf2f6f62..559dab05 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/AlarmFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/AlarmFragment.kt @@ -20,6 +20,7 @@ import com.idormy.sms.forwarder.databinding.FragmentTasksActionAlarmBinding import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.entity.TaskSetting import com.idormy.sms.forwarder.entity.action.AlarmSetting +import com.idormy.sms.forwarder.utils.CommonUtils import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION import com.idormy.sms.forwarder.utils.KEY_BACK_DESCRIPTION_ACTION import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION @@ -76,7 +77,7 @@ class AlarmFragment : BaseFragment(), View.OnC mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, 2) mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener { override fun onCountDown(time: Int) { - binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time) + binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time.toString()) } override fun onFinished() { @@ -84,24 +85,55 @@ class AlarmFragment : BaseFragment(), View.OnC } }) + binding!!.sbEnableMusic.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + binding!!.layoutAlarmSettingsContent.visibility = View.VISIBLE + val volume = binding!!.xsbVolume.selectedNumber + if (volume == 0) { + binding!!.xsbVolume.setDefaultValue(80) + } + } else { + binding!!.layoutAlarmSettingsContent.visibility = View.GONE + binding!!.xsbVolume.setDefaultValue(0) + } + checkSetting(true) + } + binding!!.sbEnableVibrate.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + binding!!.layoutVibrateSettingsContent.visibility = View.VISIBLE + val repeatTimes = binding!!.xsbRepeatTimes.selectedNumber + if (repeatTimes == 0) { + binding!!.xsbRepeatTimes.setDefaultValue(5) + } + } else { + binding!!.layoutVibrateSettingsContent.visibility = View.GONE + binding!!.xsbRepeatTimes.setDefaultValue(0) + } + checkSetting(true) + } + + var settingVo = AlarmSetting() Log.d(TAG, "initViews eventData:$eventData") if (eventData != null) { - val settingVo = Gson().fromJson(eventData, AlarmSetting::class.java) + settingVo = Gson().fromJson(eventData, AlarmSetting::class.java) Log.d(TAG, "initViews settingVo:$settingVo") if (settingVo.action == "start") { binding!!.rgAlarmState.check(R.id.rb_start_alarm) binding!!.layoutAlarmSettings.visibility = View.VISIBLE + binding!!.layoutVibrateSettings.visibility = View.VISIBLE } else { binding!!.rgAlarmState.check(R.id.rb_stop_alarm) binding!!.layoutAlarmSettings.visibility = View.GONE + binding!!.layoutVibrateSettings.visibility = View.GONE } - binding!!.xsbVolume.setDefaultValue(settingVo.volume) - binding!!.xsbLoopTimes.setDefaultValue(settingVo.playTimes) - binding!!.etMusicPath.setText(settingVo.music) - } else { - binding!!.xsbVolume.setDefaultValue(80) - binding!!.xsbLoopTimes.setDefaultValue(1) } + binding!!.xsbVolume.setDefaultValue(settingVo.volume) + binding!!.xsbLoopTimes.setDefaultValue(settingVo.playTimes) + binding!!.etMusicPath.setText(settingVo.music) + binding!!.xsbRepeatTimes.setDefaultValue(settingVo.repeatTimes) + binding!!.etVibrationEffect.setText(settingVo.vibrate) + binding!!.sbEnableMusic.isChecked = settingVo.volume > 0 + binding!!.sbEnableVibrate.isChecked = settingVo.repeatTimes > 0 } override fun onDestroyView() { @@ -125,12 +157,29 @@ class AlarmFragment : BaseFragment(), View.OnC binding!!.layoutAlarmSettings.visibility = if (checkedId == R.id.rb_start_alarm) View.VISIBLE else View.GONE checkSetting(true) } + binding!!.btInsertVibrationEffect1.setOnClickListener(this) + binding!!.btInsertVibrationEffect2.setOnClickListener(this) + binding!!.btInsertVibrationEffect3.setOnClickListener(this) } @SingleClick override fun onClick(v: View) { try { when (v.id) { + R.id.bt_insert_vibration_effect_1 -> { + CommonUtils.insertOrReplaceText2Cursor(binding!!.etVibrationEffect, "=") + return + } + + R.id.bt_insert_vibration_effect_2 -> { + CommonUtils.insertOrReplaceText2Cursor(binding!!.etVibrationEffect, "-") + return + } + + R.id.bt_insert_vibration_effect_3 -> { + CommonUtils.insertOrReplaceText2Cursor(binding!!.etVibrationEffect, "_") + return + } R.id.btn_file_picker -> { // 申请储存权限 @@ -173,6 +222,10 @@ class AlarmFragment : BaseFragment(), View.OnC try { val settingVo = checkSetting() Log.d(TAG, settingVo.toString()) + if (settingVo.volume == 0 && settingVo.repeatTimes == 0) { + XToastUtils.error(getString(R.string.alarm_settings_error)) + return + } val taskAction = TaskSetting(TASK_ACTION_ALARM, getString(R.string.task_alarm), settingVo.description, Gson().toJson(settingVo), requestCode) val taskActionsJson = Gson().toJson(arrayListOf(taskAction)) val msgInfo = MsgInfo("task", getString(R.string.task_alarm), settingVo.description, Date(), getString(R.string.task_alarm)) @@ -212,6 +265,10 @@ class AlarmFragment : BaseFragment(), View.OnC @SuppressLint("SetTextI18n") override fun onGranted(permissions: List, all: Boolean) { val settingVo = checkSetting() + if (settingVo.volume == 0 && settingVo.repeatTimes == 0) { + XToastUtils.error(getString(R.string.alarm_settings_error)) + return + } val intent = Intent() intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, settingVo.description) intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo)) @@ -244,16 +301,27 @@ class AlarmFragment : BaseFragment(), View.OnC @Suppress("SameParameterValue") @SuppressLint("SetTextI18n") private fun checkSetting(updateView: Boolean = false): AlarmSetting { + val enableMusic = binding!!.sbEnableMusic.isChecked + val enableVibrate = binding!!.sbEnableVibrate.isChecked val volume = binding!!.xsbVolume.selectedNumber val loopTimes = binding!!.xsbLoopTimes.selectedNumber val music = binding!!.etMusicPath.text.toString().trim() + val repeatTimes = binding!!.xsbRepeatTimes.selectedNumber + val vibrationEffect = binding!!.etVibrationEffect.text.toString().trim() val description = StringBuilder() val action = if (binding!!.rgAlarmState.checkedRadioButtonId == R.id.rb_start_alarm) { description.append(getString(R.string.start_alarm)) - description.append(", ").append(getString(R.string.alarm_volume)).append(":").append(volume).append("%") - description.append(", ").append(getString(R.string.alarm_play_times)).append(":").append(loopTimes) - if (music.isNotEmpty()) { - description.append(", ").append(getString(R.string.alarm_music)).append(":").append(music) + if (enableMusic) { + description.append(", ").append(getString(R.string.alarm_volume)).append(":").append(volume).append("%") + description.append(", ").append(getString(R.string.alarm_play_times)).append(":").append(loopTimes) + if (music.isNotEmpty()) { + description.append(", ").append(getString(R.string.alarm_music)).append(":").append(music) + } + } + if (enableVibrate) { + vibrationEffect.ifEmpty { "---___===___".also { binding!!.etVibrationEffect.setText(it) } } + description.append(", ").append(getString(R.string.alarm_vibration_effect)).append(":").append(vibrationEffect) + description.append(", ").append(getString(R.string.alarm_repeat_times)).append(":").append(repeatTimes) } "start" } else { @@ -265,7 +333,7 @@ class AlarmFragment : BaseFragment(), View.OnC binding!!.tvDescription.text = description.toString() } - return AlarmSetting(description.toString(), action, volume, loopTimes, music) + return AlarmSetting(description.toString(), action, volume, loopTimes, music, repeatTimes, vibrationEffect) } private fun findAudioFiles(directoryPath: String): List { @@ -286,4 +354,4 @@ class AlarmFragment : BaseFragment(), View.OnC val supportedExtensions = listOf("mp3", "ogg", "wav") return supportedExtensions.any { it.equals(file.extension, ignoreCase = true) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt b/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt index fd7a345f..70cfd9cd 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt @@ -40,6 +40,7 @@ import com.idormy.sms.forwarder.utils.INTENT_FRPC_APPLY_FILE import com.idormy.sms.forwarder.utils.Log import com.idormy.sms.forwarder.utils.SettingUtils import com.idormy.sms.forwarder.utils.TASK_CONDITION_CRON +import com.idormy.sms.forwarder.utils.VibrationUtils import com.idormy.sms.forwarder.utils.task.CronJobScheduler import com.idormy.sms.forwarder.workers.LoadAppListWorker import com.jeremyliao.liveeventbus.LiveEventBus @@ -92,77 +93,96 @@ class ForegroundService : Service() { }) } + // 振动控制 + private lateinit var vibrationUtils: VibrationUtils + private var isVibrating = false + + // 音乐播放器 private var alarmPlayer: MediaPlayer? = null private var alarmPlayTimes = 0 private val alarmObserver = Observer { alarm -> Log.d(TAG, "Received alarm: $alarm") + //停止振动 + if (vibrationUtils.isVibrating) { + vibrationUtils.stopVibration() + } + //停止播放音乐 alarmPlayer?.release() alarmPlayer = null if (alarm.action == "start") { - //获取音量 - val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager - val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) - val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) - Log.d(TAG, "maxVolume=$maxVolume, currentVolume=$currentVolume") - //设置音量 - audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (maxVolume * alarm.volume / 100), 0) //播放音乐 - alarmPlayer = MediaPlayer().apply { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() - setAudioAttributes(audioAttributes) - } else { - // 对于 Android 5.0 之前的版本,使用 setAudioStreamType - val audioStreamType = AudioManager.STREAM_ALARM - setAudioStreamType(audioStreamType) - } - - try { - if (alarm.music.isEmpty() || !File(alarm.music).exists()) { - val fd = resources.openRawResourceFd(R.raw.alarm) - setDataSource(fd.fileDescriptor, fd.startOffset, fd.length) + if (alarm.volume > 0) { + //获取音量 + val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager + val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + Log.d(TAG, "maxVolume=$maxVolume, currentVolume=$currentVolume") + //设置音量 + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (maxVolume * alarm.volume / 100), 0) + //播放音乐 + alarmPlayer = MediaPlayer().apply { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val audioAttributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build() + setAudioAttributes(audioAttributes) } else { - setDataSource(alarm.music) + // 对于 Android 5.0 之前的版本,使用 setAudioStreamType + val audioStreamType = AudioManager.STREAM_ALARM + setAudioStreamType(audioStreamType) } - setOnPreparedListener { - Log.d(TAG, "MediaPlayer prepared") - start() - alarmPlayTimes++ - //更新通知栏 - updateNotification(alarm.description, R.drawable.auto_task_icon_alarm, true) - } + try { + if (alarm.music.isEmpty() || !File(alarm.music).exists()) { + val fd = resources.openRawResourceFd(R.raw.alarm) + setDataSource(fd.fileDescriptor, fd.startOffset, fd.length) + } else { + setDataSource(alarm.music) + } - setOnCompletionListener { - Log.d(TAG, "MediaPlayer completed") - if (alarm.playTimes == 0 || alarmPlayTimes < alarm.playTimes) { + setOnPreparedListener { + Log.d(TAG, "MediaPlayer prepared") start() alarmPlayTimes++ - } else { - stop() - reset() - release() - alarmPlayer = null - alarmPlayTimes = 0 - //恢复音量 - audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0) - //恢复通知栏 - updateNotification(SettingUtils.notifyContent) + //更新通知栏 + updateNotification(alarm.description, R.drawable.auto_task_icon_alarm, true) } - } - setOnErrorListener { _, what, extra -> - Log.e(TAG, "MediaPlayer error: what=$what, extra=$extra") - release() - return@setOnErrorListener true - } + setOnCompletionListener { + Log.d(TAG, "MediaPlayer completed") + if (alarm.playTimes == 0 || alarmPlayTimes < alarm.playTimes) { + start() + alarmPlayTimes++ + } else { + stop() + reset() + release() + alarmPlayer = null + alarmPlayTimes = 0 + //恢复音量 + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0) + //恢复通知栏 + updateNotification(SettingUtils.notifyContent) + } + } - setVolume(alarm.volume / 100F, alarm.volume / 100F) - prepareAsync() - } catch (e: Exception) { - Log.e(TAG, "MediaPlayer Exception: ${e.message}") + setOnErrorListener { _, what, extra -> + Log.e(TAG, "MediaPlayer error: what=$what, extra=$extra") + release() + return@setOnErrorListener true + } + + setVolume(alarm.volume / 100F, alarm.volume / 100F) + prepareAsync() + } catch (e: Exception) { + Log.e(TAG, "MediaPlayer Exception: ${e.message}") + } } } + //振动提醒 + if (alarm.repeatTimes > 0) { + isVibrating = true + val patternString = alarm.vibrate.repeat(alarm.repeatTimes) + vibrationUtils.startVibration(patternString) + } } } @@ -176,7 +196,11 @@ class ForegroundService : Service() { //纯客户端模式 if (SettingUtils.enablePureClientMode) return + //创建通知渠道 createNotificationChannel() + + //初始化振动 + vibrationUtils = VibrationUtils(this) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -292,6 +316,10 @@ class ForegroundService : Service() { isRunning = false alarmPlayer?.release() alarmPlayer = null + //停止振动 + if (vibrationUtils.isVibrating) { + vibrationUtils.stopVibration() + } } catch (e: Exception) { handleException(e, "stopForegroundService") } @@ -354,4 +382,4 @@ class ForegroundService : Service() { isRunning = false } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/VibrationUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/VibrationUtils.kt new file mode 100644 index 00000000..36bf1017 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/VibrationUtils.kt @@ -0,0 +1,77 @@ +package com.idormy.sms.forwarder.utils + +import android.content.Context +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.os.VibrationEffect +import android.os.Vibrator + +@Suppress("DEPRECATION") +class VibrationUtils(context: Context) { + + private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + private val handler = Handler(Looper.getMainLooper()) + var isVibrating = false + private set + + fun startVibration(patternString: String) { + isVibrating = true + val parsedPattern = parsePattern(patternString) + vibratePattern(parsedPattern, 0) + } + + fun stopVibration() { + isVibrating = false + vibrator.cancel() + } + + private fun parsePattern(pattern: String): List> { + val parsedPattern = mutableListOf>() + var currentChar = pattern[0] + var currentLength = 1L + + for (i in 1 until pattern.length) { + if (pattern[i] == currentChar) { + currentLength++ + } else { + parsedPattern.add(createTriple(currentChar, currentLength)) + currentChar = pattern[i] + currentLength = 1L + } + } + parsedPattern.add(createTriple(currentChar, currentLength)) + return parsedPattern + } + + private fun createTriple(char: Char, length: Long): Triple { + val duration = 100L * length + val intensity = when (char) { + '=' -> 255 + '-' -> 128 + '_' -> 0 + else -> 0 + } + return Triple(duration, intensity > 0, intensity) + } + + private fun vibratePattern(parsedPattern: List>, index: Int) { + if (isVibrating && index < parsedPattern.size) { + val (duration, shouldVibrate, intensity) = parsedPattern[index] + if (shouldVibrate) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val effect = VibrationEffect.createOneShot(duration, intensity) + vibrator.vibrate(effect) + } else { + vibrator.vibrate(duration) + } + } + handler.postDelayed({ + if (isVibrating) { + vibrator.cancel() + vibratePattern(parsedPattern, index + 1) + } + }, duration) + } + } +} diff --git a/app/src/main/res/layout/fragment_tasks_action_alarm.xml b/app/src/main/res/layout/fragment_tasks_action_alarm.xml index fb61c6a6..4b4b1ea5 100644 --- a/app/src/main/res/layout/fragment_tasks_action_alarm.xml +++ b/app/src/main/res/layout/fragment_tasks_action_alarm.xml @@ -86,101 +86,241 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - - - + android:gravity="center_vertical" + android:orientation="horizontal"> - - + android:text="@string/alarm_play_settings" + android:textStyle="bold" + tools:ignore="RelativeOverlap" /> + + + android:orientation="vertical"> - + - + android:gravity="center_vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:gravity="center_vertical" + android:orientation="horizontal"> - - + android:text="@string/alarm_vibrate_settings" + android:textStyle="bold" + tools:ignore="RelativeOverlap" /> - + + + + + + + + + android:gravity="center_vertical"> + + + + + + + + + + + + + + + + + + + + + + + + @@ -220,4 +360,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 50e6fe31..ec6dead9 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -973,8 +973,8 @@ Control the enable/disable of "Rules" Channels On/Off Control the enable/disable of "Senders" - Alarm - Alarm + Alarm Reminder + Play music/vibrate phone to remind Resend Message Resend forwarded records since N hours ago, 0=ALL Resend forwarding records since %s hours ago for %s @@ -1124,11 +1124,19 @@ Start Alarm Stop Alarm - Playback Settings + Play Music Specify Music Opt., download mp3/ogg/wav to the Download directory. Alarm Volume Play Times(0=Infinite) + Vibrate Phone + Repeat Times + Vibration Effect + Syntax: =[strong], -[weak], _[no], 100ms each + Strong vibration + Weak vibration + No vibration + At least one of Play Music/Vibrate Phone must be enabled %s tag is invalid: %s Please input task name. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 4e5c31ad..f6ccc67a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -974,8 +974,8 @@ 控制【转发规则】的启用/禁用 启停通道 控制【发送通道】的启用/禁用 - 声音警报 - 声音警报 + 警报提醒 + 播放音乐/振动手机提醒 重发消息 自动重发N小时以来的转发记录,0=全部 自动重发%s小时以来%s的转发记录 @@ -1125,11 +1125,19 @@ 启动警报 停止警报 - 播放设置 + 播放音乐 指定音乐 可选,下载 mp3/ogg/wav 到 Download 目录 播放音量 播放次数(0=无限) + 振动手机 + 重复次数 + 振动效果 + 语法:=[强振动], -[弱震动], _[不振动], 每次100ms + 强振动 100ms + 弱振动 100ms + 不振动 100ms + 播放音乐/振动手机必须至少开启一个 %s 标签无效:%s 请输入任务名称 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index c269f5d9..ce817f49 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -967,8 +967,8 @@ 控制【轉發規則】的啟用/禁用 啟停通道 控制【發送通道】的啟用/禁用 - 聲音警報 - 聲音警報 + 警報提醒 + 播放音樂/震動手機發出提醒 重發消息 自動重發N小時以來的轉發記錄,0=全部 自動重發%s小時以來%s的轉發記錄 @@ -1118,11 +1118,19 @@ 啟動警報 停止警報 - 播放設置 + 播放音樂 指定音樂 可選,下載 mp3/ogg/wav 到 Download 目錄 播放音量 播放次數(0=無限) + 振動手機 + 重複次數 + 振動效果 + 語法:=[強振動], -[弱振動], _[不振動], 每次100ms + 強振動 100ms + 弱振動 100ms + 不振動 100ms + 播放音樂/振動手機必須至少開啟一個 %s 標籤無效:%s 請輸入任務名稱 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 351047be..7bb27279 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1001,8 +1001,8 @@ 控制【转发规则】的启用/禁用 启停通道 控制【发送通道】的启用/禁用 - 声音警报 - 播放音乐提醒 + 警报提醒 + 播放音乐/振动手机提醒 重发消息 自动重发N小时以来的转发记录,0=全部 自动重发%s小时以来%s的转发记录 @@ -1152,11 +1152,19 @@ 启动警报 停止警报 - 播放设置 + 播放音乐 指定音乐 可选,下载 mp3/ogg/wav 到 Download 目录 播放音量 播放次数(0=无限) + 振动手机 + 重复次数 + 振动效果 + 语法:=[强振动], -[弱震动], _[不振动], 每次100ms + 强振动 100ms + 弱振动 100ms + 不振动 100ms + 播放音乐/振动手机必须至少开启一个 %s 标签无效:%s 请输入任务名称 diff --git a/gradle.properties b/gradle.properties index 4a72e88c..3a27ffdd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # org.gradle.parallel=true # 是否打包APK,打正式包时请设置为true,使用正式的签名 isNeedPackage=true -isNeedClean=true +isNeedClean=false # 是否排除Frpc动态库,打正式包时请设置为true excludeFrpclib=true # 是否使用leakcanary检测内存泄漏,打正式包时请设置为false