diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt index f70aed9393..f4e3631b8a 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt @@ -54,6 +54,7 @@ import im.vector.riotx.features.rageshake.BugReportActivity import im.vector.riotx.features.rageshake.BugReporter import im.vector.riotx.features.rageshake.RageShake import im.vector.riotx.features.session.SessionListener +import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.themes.ActivityOtherThemes import im.vector.riotx.features.themes.ThemeUtils import im.vector.riotx.receivers.DebugReceiver @@ -88,9 +89,11 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { private lateinit var configurationViewModel: ConfigurationViewModel private lateinit var sessionListener: SessionListener protected lateinit var bugReporter: BugReporter - private lateinit var rageShake: RageShake + lateinit var rageShake: RageShake + private set protected lateinit var navigator: Navigator private lateinit var activeSessionHolder: ActiveSessionHolder + private lateinit var vectorPreferences: VectorPreferences // Filter for multiple invalid token error private var mainActivityStarted = false @@ -135,7 +138,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { } override fun onCreate(savedInstanceState: Bundle?) { - screenComponent = DaggerScreenComponent.factory().create(getVectorComponent(), this) + val vectorComponent = getVectorComponent() + screenComponent = DaggerScreenComponent.factory().create(vectorComponent, this) val timeForInjection = measureTimeMillis { injectWith(screenComponent) } @@ -150,6 +154,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { rageShake = screenComponent.rageShake() navigator = screenComponent.navigator() activeSessionHolder = screenComponent.activeSessionHolder() + vectorPreferences = vectorComponent.vectorPreferences() configurationViewModel.activityRestarter.observe(this, Observer { if (!it.hasBeenHandled) { // Recreate the Activity because configuration has changed @@ -226,7 +231,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { configurationViewModel.onActivityResumed() - if (this !is BugReportActivity) { + if (this !is BugReportActivity && vectorPreferences.useRageshake()) { rageShake.start() } diff --git a/vector/src/main/java/im/vector/riotx/features/rageshake/RageShake.kt b/vector/src/main/java/im/vector/riotx/features/rageshake/RageShake.kt index 39749be8c2..bbd1090d98 100644 --- a/vector/src/main/java/im/vector/riotx/features/rageshake/RageShake.kt +++ b/vector/src/main/java/im/vector/riotx/features/rageshake/RageShake.kt @@ -19,33 +19,28 @@ package im.vector.riotx.features.rageshake import android.content.Context import android.hardware.Sensor import android.hardware.SensorManager -import android.preference.PreferenceManager import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.edit import com.squareup.seismic.ShakeDetector import im.vector.riotx.R +import im.vector.riotx.features.settings.VectorPreferences import javax.inject.Inject class RageShake @Inject constructor(private val activity: AppCompatActivity, - private val bugReporter: BugReporter) : ShakeDetector.Listener { + private val bugReporter: BugReporter, + private val vectorPreferences: VectorPreferences) : ShakeDetector.Listener { private var shakeDetector: ShakeDetector? = null private var dialogDisplayed = false + var interceptor: (() -> Unit)? = null + fun start() { - if (!isEnable(activity)) { - return - } - - val sensorManager = activity.getSystemService(AppCompatActivity.SENSOR_SERVICE) as? SensorManager - - if (sensorManager == null) { - return - } + val sensorManager = activity.getSystemService(AppCompatActivity.SENSOR_SERVICE) as? SensorManager ?: return shakeDetector = ShakeDetector(this).apply { + setSensitivity(vectorPreferences.getRageshakeSensitivity()) start(sensorManager) } } @@ -54,52 +49,41 @@ class RageShake @Inject constructor(private val activity: AppCompatActivity, shakeDetector?.stop() } - /** - * Enable the feature, and start it - */ - fun enable() { - PreferenceManager.getDefaultSharedPreferences(activity).edit { - putBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true) - } - - start() - } - - /** - * Disable the feature, and stop it - */ - fun disable() { - PreferenceManager.getDefaultSharedPreferences(activity).edit { - putBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, false) - } - - stop() + fun setSensitivity(sensitivity: Int) { + shakeDetector?.setSensitivity(sensitivity) } override fun hearShake() { - if (dialogDisplayed) { - // Filtered! - return + val i = interceptor + if (i != null) { + i.invoke() + } else { + if (dialogDisplayed) { + // Filtered! + return + } + + dialogDisplayed = true + + AlertDialog.Builder(activity) + .setMessage(R.string.send_bug_report_alert_message) + .setPositiveButton(R.string.yes) { _, _ -> openBugReportScreen() } + .setNeutralButton(R.string.settings) { _, _ -> openSettings() } + .setOnDismissListener { dialogDisplayed = false } + .setNegativeButton(R.string.no, null) + .show() } - - dialogDisplayed = true - - AlertDialog.Builder(activity) - .setMessage(R.string.send_bug_report_alert_message) - .setPositiveButton(R.string.yes) { _, _ -> openBugReportScreen() } - .setNeutralButton(R.string.disable) { _, _ -> disable() } - .setOnDismissListener { dialogDisplayed = false } - .setNegativeButton(R.string.no, null) - .show() } private fun openBugReportScreen() { bugReporter.openBugReportScreen(activity) } - companion object { - private const val SETTINGS_USE_RAGE_SHAKE_KEY = "SETTINGS_USE_RAGE_SHAKE_KEY" + private fun openSettings() { + // TODO + } + companion object { /** * Check if the feature is available */ @@ -107,12 +91,5 @@ class RageShake @Inject constructor(private val activity: AppCompatActivity, return (context.getSystemService(AppCompatActivity.SENSOR_SERVICE) as? SensorManager) ?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null } - - /** - * Check if the feature is enable (enabled by default) - */ - private fun isEnable(context: Context): Boolean { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true) - } } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt index 63b7c60bef..a86c3625ce 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt @@ -23,6 +23,7 @@ import android.net.Uri import android.provider.MediaStore import androidx.core.content.edit import androidx.preference.PreferenceManager +import com.squareup.seismic.ShakeDetector import im.vector.riotx.R import im.vector.riotx.features.homeserver.ServerUrlsRepository import im.vector.riotx.features.themes.ThemeUtils @@ -153,7 +154,10 @@ class VectorPreferences @Inject constructor(private val context: Context) { // analytics const val SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY" + + // Rageshake const val SETTINGS_USE_RAGE_SHAKE_KEY = "SETTINGS_USE_RAGE_SHAKE_KEY" + const val SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY = "SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY" // other const val SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY" @@ -732,6 +736,13 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true) } + /** + * Get the rage shake sensitivity. + */ + fun getRageshakeSensitivity(): Int { + return defaultPrefs.getInt(SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY, ShakeDetector.SENSITIVITY_MEDIUM) + } + /** * Update the rage shake status. * diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsDeveloperModeFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsDeveloperModeFragment.kt index 00f71192bf..f700759fd0 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsDeveloperModeFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsDeveloperModeFragment.kt @@ -16,14 +16,63 @@ package im.vector.riotx.features.settings +import androidx.preference.Preference +import androidx.preference.SeekBarPreference import im.vector.riotx.R +import im.vector.riotx.core.platform.VectorBaseActivity +import im.vector.riotx.core.preference.VectorSwitchPreference +import im.vector.riotx.features.rageshake.RageShake class VectorSettingsDeveloperModeFragment : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_developer_mode override val preferenceXmlRes = R.xml.vector_settings_developer_mode + private var rageshake: RageShake? = null + + override fun onResume() { + super.onResume() + + rageshake = (activity as? VectorBaseActivity)?.rageShake + rageshake?.interceptor = { + (activity as? VectorBaseActivity)?.showSnackbar(getString(R.string.rageshake_detected)) + } + } + + override fun onPause() { + super.onPause() + rageshake?.interceptor = null + rageshake = null + } + override fun bindPref() { - // Nothing to do + val isRageShakeAvailable = RageShake.isAvailable(requireContext()) + + if (isRageShakeAvailable) { + findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_USE_RAGE_SHAKE_KEY)!! + .onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + + if (newValue as? Boolean == true) { + rageshake?.start() + } else { + rageshake?.stop() + } + + true + } + + findPreference<SeekBarPreference>(VectorPreferences.SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY)!! + .onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + (activity as? VectorBaseActivity)?.let { + val newValueAsInt = newValue as? Int ?: return@OnPreferenceChangeListener true + + rageshake?.setSensitivity(newValueAsInt) + } + + true + } + } else { + findPreference<VectorSwitchPreference>("SETTINGS_RAGE_SHAKE_CATEGORY_KEY")!!.isVisible = false + } } } diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index d0019bfca5..1134b4be0f 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -10,5 +10,9 @@ <string name="settings_developer_mode">Developer mode</string> <string name="settings_developer_mode_summary">The developer mode activates hidden features and may also make the application less stable. For developers only!</string> <string name="settings_rageshake">Rageshake</string> + <string name="settings_rageshake_detection_threshold">Detection threshold</string> + <string name="settings_rageshake_detection_threshold_summary">Shake your phone to test the detection threshold</string> + <string name="rageshake_detected">Shake detected!</string> + <string name="settings">Settings</string> </resources> diff --git a/vector/src/main/res/xml/vector_settings_developer_mode.xml b/vector/src/main/res/xml/vector_settings_developer_mode.xml index 8ceb03f323..6cae5fad06 100644 --- a/vector/src/main/res/xml/vector_settings_developer_mode.xml +++ b/vector/src/main/res/xml/vector_settings_developer_mode.xml @@ -2,40 +2,63 @@ <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> - <im.vector.riotx.core.preference.VectorSwitchPreference - android:defaultValue="false" - android:key="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" - android:summary="@string/settings_developer_mode_summary" - android:title="@string/settings_developer_mode" /> - - <im.vector.riotx.core.preference.VectorSwitchPreference - android:defaultValue="false" - android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" - android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY" - android:title="@string/settings_labs_show_hidden_events_in_timeline" /> - - <im.vector.riotx.core.preference.VectorSwitchPreference - android:defaultValue="false" - android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" - android:key="SETTINGS_LABS_ALLOW_EXTENDED_LOGS" - android:summary="@string/labs_allow_extended_logging_summary" - android:title="@string/labs_allow_extended_logging" /> - - <!-- TODO Display unsupported events --> - <im.vector.riotx.core.preference.VectorPreferenceCategory - android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" - android:title="@string/settings_notifications"> + android:key="SETTINGS_RAGE_SHAKE_CATEGORY_KEY" + android:title="@string/settings_rageshake"> - <im.vector.riotx.core.preference.VectorPreference - android:persistent="false" - android:title="@string/settings_notifications_targets" - app:fragment="im.vector.riotx.features.settings.push.PushGatewaysFragment" /> + <im.vector.riotx.core.preference.VectorSwitchPreference + android:key="SETTINGS_USE_RAGE_SHAKE_KEY" + android:title="@string/send_bug_report_rage_shake" /> - <im.vector.riotx.core.preference.VectorPreference - android:persistent="false" - android:title="@string/settings_push_rules" - app:fragment="im.vector.riotx.features.settings.push.PushRulesFragment" /> + <SeekBarPreference + android:defaultValue="13" + android:dependency="SETTINGS_USE_RAGE_SHAKE_KEY" + android:key="SETTINGS_RAGE_SHAKE_DETECTION_THRESHOLD_KEY" + android:max="17" + android:summary="@string/settings_rageshake_detection_threshold_summary" + android:title="@string/settings_rageshake_detection_threshold" + app:min="9" /> + + </im.vector.riotx.core.preference.VectorPreferenceCategory> + + <im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_developer_mode"> + + <im.vector.riotx.core.preference.VectorSwitchPreference + android:defaultValue="false" + android:key="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" + android:summary="@string/settings_developer_mode_summary" + android:title="@string/settings_developer_mode" /> + + <im.vector.riotx.core.preference.VectorSwitchPreference + android:defaultValue="false" + android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" + android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY" + android:title="@string/settings_labs_show_hidden_events_in_timeline" /> + + <im.vector.riotx.core.preference.VectorSwitchPreference + android:defaultValue="false" + android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" + android:key="SETTINGS_LABS_ALLOW_EXTENDED_LOGS" + android:summary="@string/labs_allow_extended_logging_summary" + android:title="@string/labs_allow_extended_logging" /> + + <!-- TODO Display unsupported events --> + + <im.vector.riotx.core.preference.VectorPreferenceCategory + android:dependency="SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY" + android:title="@string/settings_notifications"> + + <im.vector.riotx.core.preference.VectorPreference + android:persistent="false" + android:title="@string/settings_notifications_targets" + app:fragment="im.vector.riotx.features.settings.push.PushGatewaysFragment" /> + + <im.vector.riotx.core.preference.VectorPreference + android:persistent="false" + android:title="@string/settings_push_rules" + app:fragment="im.vector.riotx.features.settings.push.PushRulesFragment" /> + + </im.vector.riotx.core.preference.VectorPreferenceCategory> </im.vector.riotx.core.preference.VectorPreferenceCategory> diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml index dd6a89ff1f..9a9185cdc7 100644 --- a/vector/src/main/res/xml/vector_settings_security_privacy.xml +++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml @@ -81,13 +81,4 @@ </im.vector.riotx.core.preference.VectorPreferenceCategory> - <im.vector.riotx.core.preference.VectorPreferenceDivider /> - - <im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_rageshake"> - - <im.vector.riotx.core.preference.VectorSwitchPreference - android:key="SETTINGS_USE_RAGE_SHAKE_KEY" - android:title="@string/send_bug_report_rage_shake" /> - - </im.vector.riotx.core.preference.VectorPreferenceCategory> </androidx.preference.PreferenceScreen> \ No newline at end of file