-
Notifications
You must be signed in to change notification settings - Fork 96
/
Preferences.kt
186 lines (160 loc) · 6.07 KB
/
Preferences.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package com.chiller3.bcr
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.preference.PreferenceManager
import java.io.File
object Preferences {
const val PREF_CALL_RECORDING = "call_recording"
const val PREF_OUTPUT_DIR = "output_dir"
const val PREF_OUTPUT_FORMAT = "output_format"
const val PREF_INHIBIT_BATT_OPT = "inhibit_batt_opt"
const val PREF_VERSION = "version"
// Not associated with a UI preference
private const val PREF_CODEC_NAME = "codec_name"
private const val PREF_CODEC_PARAM_PREFIX = "codec_param_"
/**
* Get the default output directory. The directory should always be writable and is suitable for
* use as a fallback.
*/
fun getDefaultOutputDir(context: Context): File =
context.getExternalFilesDir(null)!!
/**
* Get the user-specified output directory. The returned URI refers to a write-persisted URI
* provided by SAF.
*/
fun getSavedOutputDir(context: Context): Uri? {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val outputDir = prefs.getString(PREF_OUTPUT_DIR, null)
if (outputDir != null) {
return Uri.parse(outputDir)
}
return null
}
/**
* Get the user-specified output directory or the default if none was set. This method does not
* perform any filesystem operations to check if the user-specified directory is still valid.
*/
fun getOutputDir(context: Context): Uri {
return getSavedOutputDir(context) ?: Uri.fromFile(getDefaultOutputDir(context))
}
/**
* Set a new user-specified output directory. [uri] must refer to a document tree provided by
* SAF or null if the existing saved directory should be cleared. Persisted URI permissions for
* the old directory, if set, will be revoked and persisted write permissions for the new URI
* will be requested. If the old URI and the new URI is the same, nothing is done. If persisting
* permissions for the new URI fails, the saved directory is not changed.
*/
fun setOutputDir(context: Context, uri: Uri?) {
val oldUri = getSavedOutputDir(context)
if (oldUri == uri) {
// URI is the same as before or both are null
return
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val editor = prefs.edit()
if (uri != null) {
// Persist permissions for the new URI first
context.contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
editor.putString(PREF_OUTPUT_DIR, uri.toString())
} else {
editor.remove(PREF_OUTPUT_DIR)
}
editor.apply()
// Release persisted permissions on the old directory only after the new URI is set to
// guarantee atomicity
if (oldUri != null) {
context.contentResolver.releasePersistableUriPermission(
oldUri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
}
fun isCallRecordingEnabled(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(PREF_CALL_RECORDING, false)
}
fun setCallRecordingEnabled(context: Context, enabled: Boolean) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val editor = prefs.edit()
editor.putBoolean(PREF_CALL_RECORDING, enabled)
editor.apply()
}
/**
* Get the saved output codec.
*
* Use [getCodecParam] to get the codec-specific parameter.
*/
fun getCodecName(context: Context): String? {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getString(PREF_CODEC_NAME, null)
}
/**
* Save the selected output codec.
*
* Use [setCodecParam] to set the codec-specific parameter.
*/
fun setCodecName(context: Context, name: String?) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val editor = prefs.edit()
if (name == null) {
editor.remove(PREF_CODEC_NAME)
} else {
editor.putString(PREF_CODEC_NAME, name)
}
editor.apply()
}
/**
* Get the codec-specific parameter for codec [name].
*/
fun getCodecParam(context: Context, name: String): UInt? {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val key = PREF_CODEC_PARAM_PREFIX + name
// Use a sentinel value because doing contains + getInt results in TOCTOU issues
val value = prefs.getInt(key, -1)
return if (value == -1) {
null
} else {
value.toUInt()
}
}
/**
* Set the codec-specific parameter for codec [name].
*
* @param param Must not be [UInt.MAX_VALUE]
*
* @throws IllegalArgumentException if [param] is [UInt.MAX_VALUE]
*/
fun setCodecParam(context: Context, name: String, param: UInt?) {
// -1 (when casted to int) is used as a sentinel value
if (param == UInt.MAX_VALUE) {
throw IllegalArgumentException("Parameter cannot be ${UInt.MAX_VALUE}")
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val editor = prefs.edit()
val key = PREF_CODEC_PARAM_PREFIX + name
if (param == null) {
editor.remove(key)
} else {
editor.putInt(key, param.toInt())
}
editor.apply()
}
/**
* Remove the default codec preference and the parameters for all codecs.
*/
fun resetAllCodecs(context: Context) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val keys = prefs.all.keys.filter {
it == PREF_CODEC_NAME || it.startsWith(PREF_CODEC_PARAM_PREFIX)
}
val editor = prefs.edit()
for (key in keys) {
editor.remove(key)
}
editor.apply()
}
}