()
53 |
54 | fun addListener(lis: PrintListener) {
55 | liss.add(lis)
56 | }
57 |
58 | fun removeListener(lis: PrintListener) {
59 | liss.remove(lis)
60 | }
61 |
62 | private fun dispatchPrinter(msg: String) {
63 | liss.forEach {
64 | it.invoke(msg)
65 | }
66 | }
67 |
68 | private fun println(priority: Int, msg: String) {
69 | if (output_level > priority)
70 | return//省运算
71 |
72 | dispatchPrinter(msg)
73 |
74 | val pre = findCaller(3)?.let {
75 | (it.methodName + "(" + it.fileName +
76 | ":" + it.lineNumber + ")")
77 | }
78 | println("$pre >> $msg")
79 | }
80 |
81 | private fun findCaller(upDepth: Int): StackTraceElement? {
82 | // 获取堆栈信息
83 | val callStack = Thread.currentThread().stackTrace
84 | // 最原始被调用的堆栈信息
85 | // 日志类名称
86 | val logClassName = Vog::class.java.name
87 | // 循环遍历到日志类标识
88 | var i = 0
89 | val len = callStack.size
90 | while (i < len) {
91 | if (logClassName == callStack[i].className)
92 | break
93 | i++
94 | }
95 | return try {
96 | callStack[i + upDepth]
97 | } catch (e: Exception) {
98 | e.printStackTrace()
99 | null
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/smartkey/src/main/java/cn/vove7/smartkey/tool/encryptor/AESEncryptor.kt:
--------------------------------------------------------------------------------
1 | package cn.vove7.smartkey.tool.encryptor
2 |
3 | import java.security.MessageDigest
4 | import java.security.NoSuchAlgorithmException
5 | import javax.crypto.Cipher
6 | import javax.crypto.spec.SecretKeySpec
7 |
8 | /**
9 | * # AESEncryptor
10 | *
11 | * @author Vove
12 | * 2019/6/18
13 | */
14 | object AESEncryptor : Encryptor {
15 |
16 | private val key: String
17 |
18 | init {
19 | val serialNo = getDeviceSerialNumber()
20 | key = SHA("$serialNo#\$ERDTS\$D%F^Gojikbh").substring(0, 16)
21 | }
22 |
23 | private fun getDeviceSerialNumber(): String {
24 | return "DAIUD*&YEU#QQR"
25 | }
26 |
27 | /**
28 | * SHA加密
29 | *
30 | * @param strText 明文
31 | * @return
32 | */
33 | private fun SHA(strText: String?): String {
34 | // 返回值
35 | var strResult: String? = null
36 | // 是否是有效字符串
37 | if (!strText.isNullOrEmpty()) {
38 | try {
39 | // SHA 加密开始
40 | val messageDigest = MessageDigest.getInstance("SHA-256")
41 | // 传入要加密的字符串
42 | messageDigest.update(strText.toByteArray())
43 | val byteBuffer = messageDigest.digest()
44 | val strHexString = StringBuffer()
45 | for (i in byteBuffer.indices) {
46 | val hex = Integer.toHexString(0xff and byteBuffer[i].toInt())
47 | if (hex.length == 1) {
48 | strHexString.append('0')
49 | }
50 | strHexString.append(hex)
51 | }
52 | strResult = strHexString.toString()
53 | } catch (e: NoSuchAlgorithmException) {
54 | e.printStackTrace()
55 | }
56 |
57 | }
58 |
59 | return strResult ?: "bh&T*&GRjhlbli&^(*&RPEfiuw3y"
60 | }
61 |
62 |
63 | override fun encrypt(content: String): String {
64 | return try {
65 | val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
66 | val keyspec = SecretKeySpec(key.toByteArray(), "AES")
67 | cipher.init(Cipher.ENCRYPT_MODE, keyspec)
68 | val encrypted = cipher.doFinal(content.toByteArray())
69 | Base64.encodeToString(encrypted, Base64.NO_WRAP)
70 | } catch (e: Exception) {
71 | e.printStackTrace()
72 | content
73 | }
74 |
75 | }
76 |
77 | override fun decrypt(content: String): String {
78 | return try {
79 | val encrypted1 = Base64.decode(content, Base64.NO_WRAP)
80 | val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
81 | val keyspec = SecretKeySpec(key.toByteArray(), "AES")
82 | cipher.init(Cipher.DECRYPT_MODE, keyspec)
83 | val original = cipher.doFinal(encrypted1)
84 | String(original)
85 | } catch (e: Exception) {
86 | e.printStackTrace()
87 | content
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/smartkey/src/main/java/cn/vove7/smartkey/tool/encryptor/Base64.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cn.vove7.smartkey.tool.encryptor;
18 |
19 | import java.io.UnsupportedEncodingException;
20 |
21 | /**
22 | * Utilities for encoding and decoding the Base64 representation of
23 | * binary data. See RFCs 2045 and 3548.
26 | */
27 | public class Base64 {
28 | /**
29 | * Default values for encoder/decoder flags.
30 | */
31 | public static final int DEFAULT = 0;
32 |
33 | /**
34 | * Encoder flag bit to omit the padding '=' characters at the end
35 | * of the output (if any).
36 | */
37 | public static final int NO_PADDING = 1;
38 |
39 | /**
40 | * Encoder flag bit to omit all line terminators (i.e., the output
41 | * will be on one long line).
42 | */
43 | public static final int NO_WRAP = 2;
44 |
45 | /**
46 | * Encoder flag bit to indicate lines should be terminated with a
47 | * CRLF pair instead of just an LF. Has no effect if {@code
48 | * NO_WRAP} is specified as well.
49 | */
50 | public static final int CRLF = 4;
51 |
52 | /**
53 | * Encoder/decoder flag bit to indicate using the "URL and
54 | * filename safe" variant of Base64 (see RFC 3548 section 4) where
55 | * {@code -} and {@code _} are used in place of {@code +} and
56 | * {@code /}.
57 | */
58 | public static final int URL_SAFE = 8;
59 |
60 | /**
61 | * Flag to pass to {@link Base64OutputStream} to indicate that it
62 | * should not close the output stream it is wrapping when it
63 | * itself is closed.
64 | */
65 | public static final int NO_CLOSE = 16;
66 |
67 | // --------------------------------------------------------
68 | // shared code
69 | // --------------------------------------------------------
70 |
71 | /* package */ static abstract class Coder {
72 | public byte[] output;
73 | public int op;
74 |
75 | /**
76 | * Encode/decode another block of input data. this.output is
77 | * provided by the caller, and must be big enough to hold all
78 | * the coded data. On exit, this.opwill be set to the length
79 | * of the coded data.
80 | *
81 | * @param finish true if this is the final call to process for
82 | * this object. Will finalize the coder state and
83 | * include any final bytes in the output.
84 | *
85 | * @return true if the input so far is good; false if some
86 | * error has been detected in the input stream..
87 | */
88 | public abstract boolean process(byte[] input, int offset, int len, boolean finish);
89 |
90 | /**
91 | * @return the maximum number of bytes a call to process()
92 | * could produce for the given number of input bytes. This may
93 | * be an overestimate.
94 | */
95 | public abstract int maxOutputSize(int len);
96 | }
97 |
98 | // --------------------------------------------------------
99 | // decoding
100 | // --------------------------------------------------------
101 |
102 | /**
103 | * Decode the Base64-encoded data in input and return the data in
104 | * a new byte array.
105 | *
106 | * The padding '=' characters at the end are considered optional, but
107 | * if any are present, there must be the correct number of them.
108 | *
109 | * @param str the input String to decode, which is converted to
110 | * bytes using the default charset
111 | * @param flags controls certain features of the decoded output.
112 | * Pass {@code DEFAULT} to decode standard Base64.
113 | *
114 | * @throws IllegalArgumentException if the input contains
115 | * incorrect padding
116 | */
117 | public static byte[] decode(String str, int flags) {
118 | return decode(str.getBytes(), flags);
119 | }
120 |
121 | /**
122 | * Decode the Base64-encoded data in input and return the data in
123 | * a new byte array.
124 | *
125 | *
The padding '=' characters at the end are considered optional, but
126 | * if any are present, there must be the correct number of them.
127 | *
128 | * @param input the input array to decode
129 | * @param flags controls certain features of the decoded output.
130 | * Pass {@code DEFAULT} to decode standard Base64.
131 | *
132 | * @throws IllegalArgumentException if the input contains
133 | * incorrect padding
134 | */
135 | public static byte[] decode(byte[] input, int flags) {
136 | return decode(input, 0, input.length, flags);
137 | }
138 |
139 | /**
140 | * Decode the Base64-encoded data in input and return the data in
141 | * a new byte array.
142 | *
143 | *
The padding '=' characters at the end are considered optional, but
144 | * if any are present, there must be the correct number of them.
145 | *
146 | * @param input the data to decode
147 | * @param offset the position within the input array at which to start
148 | * @param len the number of bytes of input to decode
149 | * @param flags controls certain features of the decoded output.
150 | * Pass {@code DEFAULT} to decode standard Base64.
151 | *
152 | * @throws IllegalArgumentException if the input contains
153 | * incorrect padding
154 | */
155 | public static byte[] decode(byte[] input, int offset, int len, int flags) {
156 | // Allocate space for the most data the input could represent.
157 | // (It could contain less if it contains whitespace, etc.)
158 | Decoder decoder = new Decoder(flags, new byte[len*3/4]);
159 |
160 | if (!decoder.process(input, offset, len, true)) {
161 | throw new IllegalArgumentException("bad base-64");
162 | }
163 |
164 | // Maybe we got lucky and allocated exactly enough output space.
165 | if (decoder.op == decoder.output.length) {
166 | return decoder.output;
167 | }
168 |
169 | // Need to shorten the array, so allocate a new one of the
170 | // right size and copy.
171 | byte[] temp = new byte[decoder.op];
172 | System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
173 | return temp;
174 | }
175 |
176 | /* package */ static class Decoder extends Coder {
177 | /**
178 | * Lookup table for turning bytes into their position in the
179 | * Base64 alphabet.
180 | */
181 | private static final int DECODE[] = {
182 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
183 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
184 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
185 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
186 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
187 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
188 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
189 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
190 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
191 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
192 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
193 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
194 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
195 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
196 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
197 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
198 | };
199 |
200 | /**
201 | * Decode lookup table for the "web safe" variant (RFC 3548
202 | * sec. 4) where - and _ replace + and /.
203 | */
204 | private static final int DECODE_WEBSAFE[] = {
205 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
206 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
207 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
208 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
209 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
210 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
211 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
212 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
213 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
214 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
215 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
216 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
217 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
218 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
219 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
220 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
221 | };
222 |
223 | /** Non-data values in the DECODE arrays. */
224 | private static final int SKIP = -1;
225 | private static final int EQUALS = -2;
226 |
227 | /**
228 | * States 0-3 are reading through the next input tuple.
229 | * State 4 is having read one '=' and expecting exactly
230 | * one more.
231 | * State 5 is expecting no more data or padding characters
232 | * in the input.
233 | * State 6 is the error state; an error has been detected
234 | * in the input and no future input can "fix" it.
235 | */
236 | private int state; // state number (0 to 6)
237 | private int value;
238 |
239 | final private int[] alphabet;
240 |
241 | public Decoder(int flags, byte[] output) {
242 | this.output = output;
243 |
244 | alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
245 | state = 0;
246 | value = 0;
247 | }
248 |
249 | /**
250 | * @return an overestimate for the number of bytes {@code
251 | * len} bytes could decode to.
252 | */
253 | public int maxOutputSize(int len) {
254 | return len * 3/4 + 10;
255 | }
256 |
257 | /**
258 | * Decode another block of input data.
259 | *
260 | * @return true if the state machine is still healthy. false if
261 | * bad base-64 data has been detected in the input stream.
262 | */
263 | public boolean process(byte[] input, int offset, int len, boolean finish) {
264 | if (this.state == 6) return false;
265 |
266 | int p = offset;
267 | len += offset;
268 |
269 | // Using local variables makes the decoder about 12%
270 | // faster than if we manipulate the member variables in
271 | // the loop. (Even alphabet makes a measurable
272 | // difference, which is somewhat surprising to me since
273 | // the member variable is final.)
274 | int state = this.state;
275 | int value = this.value;
276 | int op = 0;
277 | final byte[] output = this.output;
278 | final int[] alphabet = this.alphabet;
279 |
280 | while (p < len) {
281 | // Try the fast path: we're starting a new tuple and the
282 | // next four bytes of the input stream are all data
283 | // bytes. This corresponds to going through states
284 | // 0-1-2-3-0. We expect to use this method for most of
285 | // the data.
286 | //
287 | // If any of the next four bytes of input are non-data
288 | // (whitespace, etc.), value will end up negative. (All
289 | // the non-data values in decode are small negative
290 | // numbers, so shifting any of them up and or'ing them
291 | // together will result in a value with its top bit set.)
292 | //
293 | // You can remove this whole block and the output should
294 | // be the same, just slower.
295 | if (state == 0) {
296 | while (p+4 <= len &&
297 | (value = ((alphabet[input[p] & 0xff] << 18) |
298 | (alphabet[input[p+1] & 0xff] << 12) |
299 | (alphabet[input[p+2] & 0xff] << 6) |
300 | (alphabet[input[p+3] & 0xff]))) >= 0) {
301 | output[op+2] = (byte) value;
302 | output[op+1] = (byte) (value >> 8);
303 | output[op] = (byte) (value >> 16);
304 | op += 3;
305 | p += 4;
306 | }
307 | if (p >= len) break;
308 | }
309 |
310 | // The fast path isn't available -- either we've read a
311 | // partial tuple, or the next four input bytes aren't all
312 | // data, or whatever. Fall back to the slower state
313 | // machine implementation.
314 |
315 | int d = alphabet[input[p++] & 0xff];
316 |
317 | switch (state) {
318 | case 0:
319 | if (d >= 0) {
320 | value = d;
321 | ++state;
322 | } else if (d != SKIP) {
323 | this.state = 6;
324 | return false;
325 | }
326 | break;
327 |
328 | case 1:
329 | if (d >= 0) {
330 | value = (value << 6) | d;
331 | ++state;
332 | } else if (d != SKIP) {
333 | this.state = 6;
334 | return false;
335 | }
336 | break;
337 |
338 | case 2:
339 | if (d >= 0) {
340 | value = (value << 6) | d;
341 | ++state;
342 | } else if (d == EQUALS) {
343 | // Emit the last (partial) output tuple;
344 | // expect exactly one more padding character.
345 | output[op++] = (byte) (value >> 4);
346 | state = 4;
347 | } else if (d != SKIP) {
348 | this.state = 6;
349 | return false;
350 | }
351 | break;
352 |
353 | case 3:
354 | if (d >= 0) {
355 | // Emit the output triple and return to state 0.
356 | value = (value << 6) | d;
357 | output[op+2] = (byte) value;
358 | output[op+1] = (byte) (value >> 8);
359 | output[op] = (byte) (value >> 16);
360 | op += 3;
361 | state = 0;
362 | } else if (d == EQUALS) {
363 | // Emit the last (partial) output tuple;
364 | // expect no further data or padding characters.
365 | output[op+1] = (byte) (value >> 2);
366 | output[op] = (byte) (value >> 10);
367 | op += 2;
368 | state = 5;
369 | } else if (d != SKIP) {
370 | this.state = 6;
371 | return false;
372 | }
373 | break;
374 |
375 | case 4:
376 | if (d == EQUALS) {
377 | ++state;
378 | } else if (d != SKIP) {
379 | this.state = 6;
380 | return false;
381 | }
382 | break;
383 |
384 | case 5:
385 | if (d != SKIP) {
386 | this.state = 6;
387 | return false;
388 | }
389 | break;
390 | }
391 | }
392 |
393 | if (!finish) {
394 | // We're out of input, but a future call could provide
395 | // more.
396 | this.state = state;
397 | this.value = value;
398 | this.op = op;
399 | return true;
400 | }
401 |
402 | // Done reading input. Now figure out where we are left in
403 | // the state machine and finish up.
404 |
405 | switch (state) {
406 | case 0:
407 | // Output length is a multiple of three. Fine.
408 | break;
409 | case 1:
410 | // Read one extra input byte, which isn't enough to
411 | // make another output byte. Illegal.
412 | this.state = 6;
413 | return false;
414 | case 2:
415 | // Read two extra input bytes, enough to emit 1 more
416 | // output byte. Fine.
417 | output[op++] = (byte) (value >> 4);
418 | break;
419 | case 3:
420 | // Read three extra input bytes, enough to emit 2 more
421 | // output bytes. Fine.
422 | output[op++] = (byte) (value >> 10);
423 | output[op++] = (byte) (value >> 2);
424 | break;
425 | case 4:
426 | // Read one padding '=' when we expected 2. Illegal.
427 | this.state = 6;
428 | return false;
429 | case 5:
430 | // Read all the padding '='s we expected and no more.
431 | // Fine.
432 | break;
433 | }
434 |
435 | this.state = state;
436 | this.op = op;
437 | return true;
438 | }
439 | }
440 |
441 | // --------------------------------------------------------
442 | // encoding
443 | // --------------------------------------------------------
444 |
445 | /**
446 | * Base64-encode the given data and return a newly allocated
447 | * String with the result.
448 | *
449 | * @param input the data to encode
450 | * @param flags controls certain features of the encoded output.
451 | * Passing {@code DEFAULT} results in output that
452 | * adheres to RFC 2045.
453 | */
454 | public static String encodeToString(byte[] input, int flags) {
455 | try {
456 | return new String(encode(input, flags), "US-ASCII");
457 | } catch (UnsupportedEncodingException e) {
458 | // US-ASCII is guaranteed to be available.
459 | throw new AssertionError(e);
460 | }
461 | }
462 |
463 | /**
464 | * Base64-encode the given data and return a newly allocated
465 | * String with the result.
466 | *
467 | * @param input the data to encode
468 | * @param offset the position within the input array at which to
469 | * start
470 | * @param len the number of bytes of input to encode
471 | * @param flags controls certain features of the encoded output.
472 | * Passing {@code DEFAULT} results in output that
473 | * adheres to RFC 2045.
474 | */
475 | public static String encodeToString(byte[] input, int offset, int len, int flags) {
476 | try {
477 | return new String(encode(input, offset, len, flags), "US-ASCII");
478 | } catch (UnsupportedEncodingException e) {
479 | // US-ASCII is guaranteed to be available.
480 | throw new AssertionError(e);
481 | }
482 | }
483 |
484 | /**
485 | * Base64-encode the given data and return a newly allocated
486 | * byte[] with the result.
487 | *
488 | * @param input the data to encode
489 | * @param flags controls certain features of the encoded output.
490 | * Passing {@code DEFAULT} results in output that
491 | * adheres to RFC 2045.
492 | */
493 | public static byte[] encode(byte[] input, int flags) {
494 | return encode(input, 0, input.length, flags);
495 | }
496 |
497 | /**
498 | * Base64-encode the given data and return a newly allocated
499 | * byte[] with the result.
500 | *
501 | * @param input the data to encode
502 | * @param offset the position within the input array at which to
503 | * start
504 | * @param len the number of bytes of input to encode
505 | * @param flags controls certain features of the encoded output.
506 | * Passing {@code DEFAULT} results in output that
507 | * adheres to RFC 2045.
508 | */
509 | public static byte[] encode(byte[] input, int offset, int len, int flags) {
510 | Encoder encoder = new Encoder(flags, null);
511 |
512 | // Compute the exact length of the array we will produce.
513 | int output_len = len / 3 * 4;
514 |
515 | // Account for the tail of the data and the padding bytes, if any.
516 | if (encoder.do_padding) {
517 | if (len % 3 > 0) {
518 | output_len += 4;
519 | }
520 | } else {
521 | switch (len % 3) {
522 | case 0: break;
523 | case 1: output_len += 2; break;
524 | case 2: output_len += 3; break;
525 | }
526 | }
527 |
528 | // Account for the newlines, if any.
529 | if (encoder.do_newline && len > 0) {
530 | output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
531 | (encoder.do_cr ? 2 : 1);
532 | }
533 |
534 | encoder.output = new byte[output_len];
535 | encoder.process(input, offset, len, true);
536 |
537 | assert encoder.op == output_len;
538 |
539 | return encoder.output;
540 | }
541 |
542 | /* package */ static class Encoder extends Coder {
543 | /**
544 | * Emit a new line every this many output tuples. Corresponds to
545 | * a 76-character line length (the maximum allowable according to
546 | * RFC 2045).
547 | */
548 | public static final int LINE_GROUPS = 19;
549 |
550 | /**
551 | * Lookup table for turning Base64 alphabet positions (6 bits)
552 | * into output bytes.
553 | */
554 | private static final byte ENCODE[] = {
555 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
556 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
557 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
558 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
559 | };
560 |
561 | /**
562 | * Lookup table for turning Base64 alphabet positions (6 bits)
563 | * into output bytes.
564 | */
565 | private static final byte ENCODE_WEBSAFE[] = {
566 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
567 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
568 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
569 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
570 | };
571 |
572 | final private byte[] tail;
573 | /* package */ int tailLen;
574 | private int count;
575 |
576 | final public boolean do_padding;
577 | final public boolean do_newline;
578 | final public boolean do_cr;
579 | final private byte[] alphabet;
580 |
581 | public Encoder(int flags, byte[] output) {
582 | this.output = output;
583 |
584 | do_padding = (flags & NO_PADDING) == 0;
585 | do_newline = (flags & NO_WRAP) == 0;
586 | do_cr = (flags & CRLF) != 0;
587 | alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
588 |
589 | tail = new byte[2];
590 | tailLen = 0;
591 |
592 | count = do_newline ? LINE_GROUPS : -1;
593 | }
594 |
595 | /**
596 | * @return an overestimate for the number of bytes {@code
597 | * len} bytes could encode to.
598 | */
599 | public int maxOutputSize(int len) {
600 | return len * 8/5 + 10;
601 | }
602 |
603 | public boolean process(byte[] input, int offset, int len, boolean finish) {
604 | // Using local variables makes the encoder about 9% faster.
605 | final byte[] alphabet = this.alphabet;
606 | final byte[] output = this.output;
607 | int op = 0;
608 | int count = this.count;
609 |
610 | int p = offset;
611 | len += offset;
612 | int v = -1;
613 |
614 | // First we need to concatenate the tail of the previous call
615 | // with any input bytes available now and see if we can empty
616 | // the tail.
617 |
618 | switch (tailLen) {
619 | case 0:
620 | // There was no tail.
621 | break;
622 |
623 | case 1:
624 | if (p+2 <= len) {
625 | // A 1-byte tail with at least 2 bytes of
626 | // input available now.
627 | v = ((tail[0] & 0xff) << 16) |
628 | ((input[p++] & 0xff) << 8) |
629 | (input[p++] & 0xff);
630 | tailLen = 0;
631 | };
632 | break;
633 |
634 | case 2:
635 | if (p+1 <= len) {
636 | // A 2-byte tail with at least 1 byte of input.
637 | v = ((tail[0] & 0xff) << 16) |
638 | ((tail[1] & 0xff) << 8) |
639 | (input[p++] & 0xff);
640 | tailLen = 0;
641 | }
642 | break;
643 | }
644 |
645 | if (v != -1) {
646 | output[op++] = alphabet[(v >> 18) & 0x3f];
647 | output[op++] = alphabet[(v >> 12) & 0x3f];
648 | output[op++] = alphabet[(v >> 6) & 0x3f];
649 | output[op++] = alphabet[v & 0x3f];
650 | if (--count == 0) {
651 | if (do_cr) output[op++] = '\r';
652 | output[op++] = '\n';
653 | count = LINE_GROUPS;
654 | }
655 | }
656 |
657 | // At this point either there is no tail, or there are fewer
658 | // than 3 bytes of input available.
659 |
660 | // The main loop, turning 3 input bytes into 4 output bytes on
661 | // each iteration.
662 | while (p+3 <= len) {
663 | v = ((input[p] & 0xff) << 16) |
664 | ((input[p+1] & 0xff) << 8) |
665 | (input[p+2] & 0xff);
666 | output[op] = alphabet[(v >> 18) & 0x3f];
667 | output[op+1] = alphabet[(v >> 12) & 0x3f];
668 | output[op+2] = alphabet[(v >> 6) & 0x3f];
669 | output[op+3] = alphabet[v & 0x3f];
670 | p += 3;
671 | op += 4;
672 | if (--count == 0) {
673 | if (do_cr) output[op++] = '\r';
674 | output[op++] = '\n';
675 | count = LINE_GROUPS;
676 | }
677 | }
678 |
679 | if (finish) {
680 | // Finish up the tail of the input. Note that we need to
681 | // consume any bytes in tail before any bytes
682 | // remaining in input; there should be at most two bytes
683 | // total.
684 |
685 | if (p-tailLen == len-1) {
686 | int t = 0;
687 | v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
688 | tailLen -= t;
689 | output[op++] = alphabet[(v >> 6) & 0x3f];
690 | output[op++] = alphabet[v & 0x3f];
691 | if (do_padding) {
692 | output[op++] = '=';
693 | output[op++] = '=';
694 | }
695 | if (do_newline) {
696 | if (do_cr) output[op++] = '\r';
697 | output[op++] = '\n';
698 | }
699 | } else if (p-tailLen == len-2) {
700 | int t = 0;
701 | v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
702 | (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
703 | tailLen -= t;
704 | output[op++] = alphabet[(v >> 12) & 0x3f];
705 | output[op++] = alphabet[(v >> 6) & 0x3f];
706 | output[op++] = alphabet[v & 0x3f];
707 | if (do_padding) {
708 | output[op++] = '=';
709 | }
710 | if (do_newline) {
711 | if (do_cr) output[op++] = '\r';
712 | output[op++] = '\n';
713 | }
714 | } else if (do_newline && op > 0 && count != LINE_GROUPS) {
715 | if (do_cr) output[op++] = '\r';
716 | output[op++] = '\n';
717 | }
718 |
719 | assert tailLen == 0;
720 | assert p == len;
721 | } else {
722 | // Save the leftovers in tail to be consumed on the next
723 | // call to encodeInternal.
724 |
725 | if (p == len-1) {
726 | tail[tailLen++] = input[p];
727 | } else if (p == len-2) {
728 | tail[tailLen++] = input[p];
729 | tail[tailLen++] = input[p+1];
730 | }
731 | }
732 |
733 | this.op = op;
734 | this.count = count;
735 |
736 | return true;
737 | }
738 | }
739 |
740 | private Base64() { } // don't instantiate
741 | }
742 |
--------------------------------------------------------------------------------
/smartkey/src/main/java/cn/vove7/smartkey/tool/encryptor/Encryptor.kt:
--------------------------------------------------------------------------------
1 | package cn.vove7.smartkey.tool.encryptor
2 |
3 | /**
4 | * # Encryptor
5 | *
6 | * @author Vove
7 | * 2019/6/18
8 | */
9 | interface Encryptor {
10 |
11 | fun encrypt(content: String): String
12 |
13 | fun encryptKey(key: String): String {
14 | return encrypt(key)
15 | .replace('\\', '-')
16 | .replace('/', '-')
17 | }
18 |
19 | fun decrypt(content: String): String
20 | }
--------------------------------------------------------------------------------
/smartkey/src/main/java/com/russhwolf/settings/Delegates.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Russell Wolf
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.russhwolf.settings
18 |
19 | import kotlin.properties.ReadWriteProperty
20 | import kotlin.reflect.KProperty
21 |
22 | /**
23 | * Returns an [Int] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
24 | */
25 | public fun Settings.int(key: String? = null, defaultValue: Int = 0): ReadWriteProperty =
26 | IntDelegate(this, key, defaultValue)
27 |
28 | /**
29 | * Returns a [Long] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
30 | */
31 | public fun Settings.long(key: String? = null, defaultValue: Long = 0): ReadWriteProperty =
32 | LongDelegate(this, key, defaultValue)
33 |
34 | /**
35 | * Returns a [String] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
36 | */
37 | public fun Settings.string(key: String? = null, defaultValue: String = ""): ReadWriteProperty =
38 | StringDelegate(this, key, defaultValue)
39 |
40 | /**
41 | * Returns a [Float] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
42 | */
43 | public fun Settings.float(key: String? = null, defaultValue: Float = 0f): ReadWriteProperty =
44 | FloatDelegate(this, key, defaultValue)
45 |
46 | /**
47 | * Returns a [Double] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
48 | */
49 | public fun Settings.double(key: String? = null, defaultValue: Double = 0.0): ReadWriteProperty =
50 | DoubleDelegate(this, key, defaultValue)
51 |
52 | /**
53 | * Returns a [Boolean] property delegate, backed by this [Settings] instance using the provided [key], with initial value [defaultValue].
54 | */
55 | public fun Settings.boolean(key: String? = null, defaultValue: Boolean = false): ReadWriteProperty =
56 | BooleanDelegate(this, key, defaultValue)
57 |
58 | /**
59 | * Returns a nullable [Int] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
60 | */
61 | public fun Settings.nullableInt(key: String? = null): ReadWriteProperty = NullableIntDelegate(this, key)
62 |
63 | /**
64 | * Returns a nullable [Long] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
65 | */
66 | public fun Settings.nullableLong(key: String? = null): ReadWriteProperty = NullableLongDelegate(this, key)
67 |
68 | /**
69 | * Returns a nullable [String] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
70 | */
71 | public fun Settings.nullableString(key: String? = null): ReadWriteProperty =
72 | NullableStringDelegate(this, key)
73 |
74 | /**
75 | * Returns a nullable [Float] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
76 | */
77 | public fun Settings.nullableFloat(key: String? = null): ReadWriteProperty =
78 | NullableFloatDelegate(this, key)
79 |
80 | /**
81 | * Returns a nullable [Double] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
82 | */
83 | public fun Settings.nullableDouble(key: String? = null): ReadWriteProperty =
84 | NullableDoubleDelegate(this, key)
85 |
86 | /**
87 | * Returns a nullable [Boolean] property delegate, backed by this [Settings] instance using the provided [key], with initial value `null`
88 | */
89 | public fun Settings.nullableBoolean(key: String? = null): ReadWriteProperty =
90 | NullableBooleanDelegate(this, key)
91 |
92 | private class IntDelegate(
93 | private val settings: Settings,
94 | key: String?,
95 | private val defaultValue: Int
96 | ) : OptionalKeyDelegate(key) {
97 | override fun getValue(key: String): Int = settings[key, defaultValue]
98 | override fun setValue(key: String, value: Int) {
99 | settings[key] = value
100 | }
101 | }
102 |
103 | private class LongDelegate(
104 | private val settings: Settings,
105 | key: String?,
106 | private val defaultValue: Long
107 | ) : OptionalKeyDelegate(key) {
108 | override fun getValue(key: String): Long = settings[key, defaultValue]
109 | override fun setValue(key: String, value: Long) {
110 | settings[key] = value
111 | }
112 | }
113 |
114 | private class StringDelegate(
115 | private val settings: Settings,
116 | key: String?,
117 | private val defaultValue: String
118 | ) : OptionalKeyDelegate(key) {
119 | override fun getValue(key: String): String = settings[key, defaultValue]
120 | override fun setValue(key: String, value: String) {
121 | settings[key] = value
122 | }
123 | }
124 |
125 | private class FloatDelegate(
126 | private val settings: Settings,
127 | key: String?,
128 | private val defaultValue: Float
129 | ) : OptionalKeyDelegate(key) {
130 | override fun getValue(key: String): Float = settings[key, defaultValue]
131 | override fun setValue(key: String, value: Float) {
132 | settings[key] = value
133 | }
134 | }
135 |
136 | private class DoubleDelegate(
137 | private val settings: Settings,
138 | key: String?,
139 | private val defaultValue: Double
140 | ) : OptionalKeyDelegate(key) {
141 | override fun getValue(key: String): Double = settings[key, defaultValue]
142 | override fun setValue(key: String, value: Double) {
143 | settings[key] = value
144 | }
145 | }
146 |
147 | private class BooleanDelegate(
148 | private val settings: Settings,
149 | key: String?,
150 | private val defaultValue: Boolean
151 | ) : OptionalKeyDelegate(key) {
152 | override fun getValue(key: String): Boolean = settings[key, defaultValue]
153 | override fun setValue(key: String, value: Boolean) {
154 | settings[key] = value
155 | }
156 | }
157 |
158 | private class NullableIntDelegate(
159 | private val settings: Settings,
160 | key: String?
161 | ) : OptionalKeyDelegate(key) {
162 | override fun getValue(key: String): Int? {
163 | return if (key in settings) settings[key, 0] else null
164 | }
165 |
166 | override fun setValue(key: String, value: Int?) =
167 | if (value != null) settings[key] = value else settings -= key
168 | }
169 |
170 | private class NullableLongDelegate(
171 | private val settings: Settings,
172 | key: String?
173 | ) : OptionalKeyDelegate(key) {
174 | override fun getValue(key: String): Long? =
175 | if (key in settings) settings[key, 0L] else null
176 |
177 | override fun setValue(key: String, value: Long?) =
178 | if (value != null) settings[key] = value else settings -= key
179 | }
180 |
181 | private class NullableStringDelegate(
182 | private val settings: Settings,
183 | key: String?
184 | ) : OptionalKeyDelegate(key) {
185 | override fun getValue(key: String): String? =
186 | if (key in settings) settings[key, ""] else null
187 |
188 | override fun setValue(key: String, value: String?) =
189 | if (value != null) settings[key] = value else settings -= key
190 | }
191 |
192 | private class NullableFloatDelegate(
193 | private val settings: Settings,
194 | key: String?
195 | ) : OptionalKeyDelegate(key) {
196 | override fun getValue(key: String): Float? =
197 | if (key in settings) settings[key, 0f] else null
198 |
199 | override fun setValue(key: String, value: Float?) =
200 | if (value != null) settings[key] = value else settings -= key
201 | }
202 |
203 | private class NullableDoubleDelegate(
204 | private val settings: Settings,
205 | key: String?
206 | ) : OptionalKeyDelegate(key) {
207 | override fun getValue(key: String): Double? =
208 | if (key in settings) settings[key, 0.0] else null
209 |
210 | override fun setValue(key: String, value: Double?) =
211 | if (value != null) settings[key] = value else settings -= key
212 | }
213 |
214 | private class NullableBooleanDelegate(
215 | private val settings: Settings,
216 | key: String?
217 | ) : OptionalKeyDelegate(key) {
218 | override fun getValue(key: String): Boolean? =
219 | if (key in settings) settings[key, false] else null
220 |
221 | override fun setValue(key: String, value: Boolean?) =
222 | if (value != null) settings[key] = value else settings -= key
223 | }
224 |
225 | /**
226 | * A [ReadWriteProperty] that coordinates its [getValue] and [setValue] functions via a [String] key. If the [key]
227 | * is null, then [KProperty.name] will be used as a default.
228 | */
229 | private abstract class OptionalKeyDelegate(private val key: String?) : ReadWriteProperty {
230 |
231 | abstract fun getValue(key: String): T
232 | abstract fun setValue(key: String, value: T)
233 |
234 | override fun getValue(thisRef: Any?, property: KProperty<*>): T = getValue(key ?: property.name)
235 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
236 | setValue(key ?: property.name, value)
237 | }
238 | }
--------------------------------------------------------------------------------
/smartkey/src/main/java/com/russhwolf/settings/ExperimentalListener.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Russell Wolf
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.russhwolf.settings
18 |
19 | import kotlin.annotation.AnnotationTarget.CLASS
20 | import kotlin.annotation.AnnotationTarget.CONSTRUCTOR
21 | import kotlin.annotation.AnnotationTarget.FIELD
22 | import kotlin.annotation.AnnotationTarget.FUNCTION
23 | import kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE
24 | import kotlin.annotation.AnnotationTarget.PROPERTY
25 | import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER
26 | import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER
27 | import kotlin.annotation.AnnotationTarget.TYPEALIAS
28 | import kotlin.annotation.AnnotationTarget.VALUE_PARAMETER
29 |
30 | /**
31 | * Annotation to mark listener functionality as experimental.
32 | */
33 | @Experimental
34 | @Target(
35 | CLASS,
36 | PROPERTY,
37 | FIELD,
38 | LOCAL_VARIABLE,
39 | VALUE_PARAMETER,
40 | CONSTRUCTOR,
41 | FUNCTION,
42 | PROPERTY_GETTER,
43 | PROPERTY_SETTER,
44 | TYPEALIAS
45 | )
46 | annotation class ExperimentalListener
47 |
--------------------------------------------------------------------------------
/smartkey/src/main/java/com/russhwolf/settings/Operators.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Russell Wolf
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | @file:Suppress("NOTHING_TO_INLINE")
18 |
19 | package com.russhwolf.settings
20 |
21 | /** Equivalent to [Settings.hasKey] */
22 | public inline operator fun Settings.contains(key: String): Boolean = hasKey(key)
23 |
24 | /** Equivalent to [Settings.remove]*/
25 | public inline operator fun Settings.minusAssign(key: String): Unit = remove(key)
26 |
27 | /** Equivalent to [Settings.getInt]*/
28 | public inline operator fun Settings.get(key: String, defaultValue: Int): Int = getInt(key, defaultValue)
29 |
30 | /** Equivalent to [Settings.getLong]*/
31 | public inline operator fun Settings.get(key: String, defaultValue: Long): Long = getLong(key, defaultValue)
32 |
33 | /** Equivalent to [Settings.getString]*/
34 | public inline operator fun Settings.get(key: String, defaultValue: String): String = getString(key, defaultValue)
35 |
36 | /** Equivalent to [Settings.getFloat]*/
37 | public inline operator fun Settings.get(key: String, defaultValue: Float): Float = getFloat(key, defaultValue)
38 |
39 | /** Equivalent to [Settings.getDouble]*/
40 | public inline operator fun Settings.get(key: String, defaultValue: Double): Double = getDouble(key, defaultValue)
41 |
42 | /** Equivalent to [Settings.getBoolean]*/
43 | public inline operator fun Settings.get(key: String, defaultValue: Boolean): Boolean = getBoolean(key, defaultValue)
44 |
45 | /** Equivalent to [Settings.putInt]*/
46 | public inline operator fun Settings.set(key: String, value: Int): Unit = putInt(key, value)
47 |
48 | /** Equivalent to [Settings.putLong]*/
49 | public inline operator fun Settings.set(key: String, value: Long): Unit = putLong(key, value)
50 |
51 | /** Equivalent to [Settings.putString]*/
52 | public inline operator fun Settings.set(key: String, value: String): Unit = putString(key, value)
53 |
54 | /** Equivalent to [Settings.putFloat]*/
55 | public inline operator fun Settings.set(key: String, value: Float): Unit = putFloat(key, value)
56 |
57 | /** Equivalent to [Settings.putDouble]*/
58 | public inline operator fun Settings.set(key: String, value: Double): Unit = putDouble(key, value)
59 |
60 | /** Equivalent to [Settings.putBoolean]*/
61 | public inline operator fun Settings.set(key: String, value: Boolean): Unit = putBoolean(key, value)
62 |
--------------------------------------------------------------------------------
/smartkey/src/main/java/com/russhwolf/settings/Settings.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Russell Wolf
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.russhwolf.settings
18 |
19 | /**
20 | * A collection of storage-backed key-value data
21 | *
22 | * This interface allows storage of values with the [Int], [Long], [String], [Float], [Double], or [Boolean] types, using a
23 | * [String] reference as a key. Values will be persisted across app launches.
24 | *
25 | * Operator extensions are defined in order to simplify usage. In addition, property delegates are provided for cleaner
26 | * syntax and better type-safety when interacting with values stored in a `Settings` instance.
27 | */
28 | public interface Settings {
29 |
30 | /**
31 | * A factory that can produce [Settings] instances.
32 | */
33 | public interface Factory {
34 | /**
35 | * Creates a [Settings] object associated with the provided [name].
36 | *
37 | * Multiple `Settings` instances created with the same `name` parameter will be backed by the same persistent
38 | * data, while distinct `name`s will use different data.
39 | */
40 | public fun create(name: String? = null): Settings
41 | }
42 |
43 | /**
44 | * Clears all values stored in this [Settings] instance.
45 | */
46 | public fun clear()
47 |
48 | /**
49 | * Removes the value stored at [key].
50 | */
51 | public fun remove(key: String)
52 |
53 | /**
54 | * Returns `true` if there is a value stored at [key], or `false` otherwise.
55 | */
56 | public fun hasKey(key: String): Boolean
57 |
58 | /**
59 | * Returns all keys for this setting
60 | */
61 | fun keys(): Set
62 |
63 | /**
64 | * Stores the `Int` [value] at [key].
65 | */
66 | public fun putInt(key: String, value: Int)
67 |
68 | /**
69 | * Returns the `Int` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
70 | * type was stored at `key`, the behavior is not defined.
71 | */
72 | public fun getInt(key: String, defaultValue: Int = 0): Int
73 |
74 | /**
75 | * Stores the `Long` [value] at [key].
76 | */
77 | public fun putLong(key: String, value: Long)
78 |
79 | /**
80 | * Returns the `Long` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
81 | * type was stored at `key`, the behavior is not defined.
82 | */
83 | public fun getLong(key: String, defaultValue: Long = 0): Long
84 |
85 | /**
86 | * Stores the `String` [value] at [key].
87 | */
88 | public fun putString(key: String, value: String)
89 |
90 | /**
91 | * Returns the `String` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
92 | * type was stored at `key`, the behavior is not defined.
93 | */
94 | public fun getString(key: String, defaultValue: String = ""): String
95 |
96 | /**
97 | * Stores the `Float` [value] at [key].
98 | */
99 | public fun putFloat(key: String, value: Float)
100 |
101 | /**
102 | * Returns the `Float` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
103 | * type was stored at `key`, the behavior is not defined.
104 | */
105 | public fun getFloat(key: String, defaultValue: Float = 0f): Float
106 |
107 | /**
108 | * Stores the `Double` [value] at [key].
109 | */
110 | public fun putDouble(key: String, value: Double)
111 |
112 | /**
113 | * Returns the `Double` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
114 | * type was stored at `key`, the behavior is not defined.
115 | */
116 | public fun getDouble(key: String, defaultValue: Double = 0.0): Double
117 |
118 | /**
119 | * Stores the `Boolean` [value] at [key].
120 | */
121 | public fun putBoolean(key: String, value: Boolean)
122 |
123 | /**
124 | * Returns the `Boolean` value stored at [key], or [defaultValue] if no value was stored. If a value of a different
125 | * type was stored at `key`, the behavior is not defined.
126 | */
127 | public fun getBoolean(key: String, defaultValue: Boolean = false): Boolean
128 |
129 | fun syncImmediately(): Boolean
130 | }
131 |
132 | /**
133 | * An extension to the [Settings] interface to include update listener functionality
134 | */
135 | @ExperimentalListener
136 | public interface ObservableSettings : Settings {
137 | /**
138 | * Adds a listener which will call the supplied [callback] anytime the value at [key] changes. A [SettingsListener]
139 | * reference is returned which should be passed to [removeListener] when you no longer need it so that the
140 | * associated platform resources can be cleaned up.
141 | *
142 | * A strong reference should be held to the `SettingsListener` returned by this method in order to avoid it being
143 | * garbage-collected on Android.
144 | *
145 | * No attempt is made in the current implementation to safely handle multithreaded interaction with the listener, so
146 | * it's recommended that interaction with the listener APIs be confined to the main UI thread.
147 | */
148 | @ExperimentalListener
149 | public fun addListener(key: String, callback: () -> Unit): SettingsListener
150 |
151 | /**
152 | * Unsubscribes the [listener] from receiving updates to the value at the key it monitors
153 | */
154 | @ExperimentalListener
155 | public fun removeListener(listener: SettingsListener)
156 |
157 | }
158 |
159 | @Deprecated(
160 | "ListenableSettings has been renamed ObservableSettings",
161 | replaceWith = ReplaceWith("ObservableSettings", "com.russhwolf.settings.ObservableSettings"),
162 | level = DeprecationLevel.WARNING
163 | )
164 | @ExperimentalListener
165 | @Suppress("UNUSED", "KDocMissingDocumentation")
166 | public typealias ListenableSettings = ObservableSettings
167 |
168 | /**
169 | * A handle to a listener instance returned by [ObservableSettings.addListener] so it can be passed to
170 | * [ObservableSettings.removeListener].
171 | */
172 | @ExperimentalListener
173 | public interface SettingsListener
174 |
--------------------------------------------------------------------------------