mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
2627 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4db088eda | ||
|
|
96454b7cbf | ||
|
|
9c1df2179c | ||
|
|
52c9125404 | ||
|
|
172a857604 | ||
|
|
d8e68a266c | ||
|
|
1f57ba6c50 | ||
|
|
ff19578807 | ||
|
|
9298d57f22 | ||
|
|
8cf5d5728e | ||
|
|
bdf6d764ca | ||
|
|
05e8da4bcc | ||
|
|
382e547f74 | ||
|
|
4f9985d2b0 | ||
|
|
ef97417cd7 | ||
|
|
7bdf4d8b18 | ||
|
|
a6c95d06b5 | ||
|
|
bd4a275558 | ||
|
|
a2b46ee7cb | ||
|
|
2003ac9d2c | ||
|
|
2a5667251e | ||
|
|
79589b07fc | ||
|
|
0aed13a2cf | ||
|
|
df412e75d1 | ||
|
|
2b8dbde923 | ||
|
|
33791a03ac | ||
|
|
80a33e98a2 | ||
|
|
afed18908b | ||
|
|
fe58dea3e0 | ||
|
|
569045fcd5 | ||
|
|
fdda670311 | ||
|
|
fbb7b05b9c | ||
|
|
976eeab6d7 | ||
|
|
e61bcd2785 | ||
|
|
570edb4319 | ||
|
|
8fe8c42765 | ||
|
|
0eebe6b156 | ||
|
|
946831b37e | ||
|
|
1d4e742d66 | ||
|
|
29979f6b04 | ||
|
|
2f6e1ff477 | ||
|
|
c1030c48fa | ||
|
|
ef5d08cb75 | ||
|
|
faa6904ce3 | ||
|
|
c27da8e7c4 | ||
|
|
3ef5ca9cc0 | ||
|
|
2fbd3b4538 | ||
|
|
b3b21ea6b1 | ||
|
|
a3b4ede8f3 | ||
|
|
10ea6a86e3 | ||
|
|
3b2b37b3b0 | ||
|
|
75e27ffbe3 | ||
|
|
a2cff6da28 | ||
|
|
fe80fd0ba1 | ||
|
|
5c6b9fa471 | ||
|
|
d926565358 | ||
|
|
ce0b8bc62d | ||
|
|
04aeddc5de | ||
|
|
13ffbe911a | ||
|
|
ab04759b0e | ||
|
|
798cfef391 | ||
|
|
3b5cdfe03c | ||
|
|
63449a3832 | ||
|
|
23011aa8ae | ||
|
|
654d71cbbc | ||
|
|
d0e424abd9 | ||
|
|
5cee71ce8a | ||
|
|
c3be4f44a4 | ||
|
|
ff3ac10bc3 | ||
|
|
37bee011dc | ||
|
|
3c7029bdc8 | ||
|
|
29369b7bb2 | ||
|
|
f2b9214836 | ||
|
|
8b7b8a5e43 | ||
|
|
142d056393 | ||
|
|
2b81bd2c8a | ||
|
|
53c82f23bf | ||
|
|
9b621bd1d0 | ||
|
|
9165cb2b0e | ||
|
|
2c13cef17c | ||
|
|
1098686d51 | ||
|
|
6fa23475e3 | ||
|
|
685548ab72 | ||
|
|
3799eb4603 | ||
|
|
20d5c6a63a | ||
|
|
ce11232cbe | ||
|
|
233319a0a3 | ||
|
|
7cf64ff088 | ||
|
|
a8acd36b1e | ||
|
|
d88695f5d5 | ||
|
|
5e70d03dbe | ||
|
|
2602a09443 | ||
|
|
a18e59a28a | ||
|
|
52ba9f2ba7 | ||
|
|
8d5614cd7b | ||
|
|
9b6bf136f1 | ||
|
|
10677f3705 | ||
|
|
9d4d09810a | ||
|
|
28a1bd5219 | ||
|
|
1197c10592 | ||
|
|
3bb92d452b | ||
|
|
2bfabfd838 | ||
|
|
9876cd547f | ||
|
|
4a8d261a82 | ||
|
|
c4823f1c37 | ||
|
|
6e9238329c | ||
|
|
c86cb962b9 | ||
|
|
56935a7210 | ||
|
|
cdc08e7e8a | ||
|
|
ca7794e6f2 | ||
|
|
3b5cae01e0 | ||
|
|
edb8dc58f7 | ||
|
|
3fc69f16d5 | ||
|
|
bd3fdcab26 | ||
|
|
201191e96d | ||
|
|
f545eafa77 | ||
|
|
5583c59e96 | ||
|
|
fbcf9c900c | ||
|
|
0801dea6e6 | ||
|
|
217514af66 | ||
|
|
e0191c573d | ||
|
|
ef4b53b337 | ||
|
|
acf2e4360f | ||
|
|
3227daddaf | ||
|
|
6e40b7f25b | ||
|
|
0dd87bbf78 | ||
|
|
dcfdc7d0ea | ||
|
|
e79097603f | ||
|
|
ffd8f9951f | ||
|
|
e27370cf32 | ||
|
|
405c4d1706 | ||
|
|
f7e081ba5d | ||
|
|
c71deb5051 | ||
|
|
edab722a76 | ||
|
|
2d280bd995 | ||
|
|
27e3c6553e | ||
|
|
6258a9cff9 | ||
|
|
a72f497581 | ||
|
|
311d3dd635 | ||
|
|
e80b3e4542 | ||
|
|
82c96555dc | ||
|
|
75b6e69d34 | ||
|
|
532b5f7c33 | ||
|
|
a841419c30 | ||
|
|
730a56380a | ||
|
|
97aa974443 | ||
|
|
b2eee8bde7 | ||
|
|
3cbe932248 | ||
|
|
26d5504a2f | ||
|
|
b163a0fe77 | ||
|
|
523e713d7a | ||
|
|
c7cf634a94 | ||
|
|
c8c14396f1 | ||
|
|
e72ccaf440 | ||
|
|
0b7e07ebab | ||
|
|
37e19d9a60 | ||
|
|
8f533bc576 | ||
|
|
096a9561ed | ||
|
|
c6ac9376fc | ||
|
|
fd55cf6996 | ||
|
|
0359705361 | ||
|
|
e31a7e5236 | ||
|
|
bb477908ef | ||
|
|
26175fbe1b | ||
|
|
67bc59f6b6 | ||
|
|
7b358b1bbb | ||
|
|
0387d5bdd1 | ||
|
|
2ddf624f7d | ||
|
|
74b34661a5 | ||
|
|
dc9765ef58 | ||
|
|
a50e66faf4 | ||
|
|
0388738e02 | ||
|
|
d33e38012a | ||
|
|
785d0b21c6 | ||
|
|
db12cd92b7 | ||
|
|
52261f99d7 | ||
|
|
692dc154ef | ||
|
|
22101d8f4a | ||
|
|
f68db90b1f | ||
|
|
5e680531da | ||
|
|
93cd31018e | ||
|
|
277c570723 | ||
|
|
f1419a75f6 | ||
|
|
3af08a4727 | ||
|
|
a535cea85f | ||
|
|
29e443ed76 | ||
|
|
f95cddd05a | ||
|
|
ae28de4159 | ||
|
|
39de2c1d25 | ||
|
|
22570e08aa | ||
|
|
3b4ef4d238 | ||
|
|
c5a71c4304 | ||
|
|
4f37c2cb73 | ||
|
|
c1ec97055c | ||
|
|
086c71126f | ||
|
|
10a78c1c94 | ||
|
|
cf6021d898 | ||
|
|
ff322cd2dd | ||
|
|
1a96d3c38e | ||
|
|
cfe84963fa | ||
|
|
d908a599b1 | ||
|
|
9b3ddb8da3 | ||
|
|
56d994a69d | ||
|
|
67cd17c604 | ||
|
|
f4fb7eb8b7 | ||
|
|
b9021e4331 | ||
|
|
3583836d3e | ||
|
|
278815119f | ||
|
|
1bb678e455 | ||
|
|
b9e5fc604b | ||
|
|
b65e8c48ce | ||
|
|
e59bc1a08e | ||
|
|
ff994629de | ||
|
|
a458b9bc88 | ||
|
|
2834e25151 | ||
|
|
c2582fe055 | ||
|
|
0980219c8d | ||
|
|
c5f158f1cf | ||
|
|
62afc023c8 | ||
|
|
52ca84946b | ||
|
|
e64fb39c32 | ||
|
|
1066598150 | ||
|
|
caed8c2cf0 | ||
|
|
663be2402d | ||
|
|
6fd24c842f | ||
|
|
302631c4fa | ||
|
|
8a94623b2b | ||
|
|
016dfdb455 | ||
|
|
097415385e | ||
|
|
8e6c6e04a3 | ||
|
|
81a30e580e | ||
|
|
676efe7253 | ||
|
|
39e0e77824 | ||
|
|
363f5be8ff | ||
|
|
df15fa2f0e | ||
|
|
e8c1fbb86f | ||
|
|
df986b9ecf | ||
|
|
daabf4bab9 | ||
|
|
3095948024 | ||
|
|
fad289305f | ||
|
|
97d8f07e0d | ||
|
|
dc374c7ce9 | ||
|
|
1584475bc3 | ||
|
|
8f1db25c5c | ||
|
|
092b536009 | ||
|
|
f95bbaa0f7 | ||
|
|
bc1f6464d3 | ||
|
|
b828cd5975 | ||
|
|
766b4f7971 | ||
|
|
45e2ffd71e | ||
|
|
98757c3f11 | ||
|
|
9aed6d350b | ||
|
|
ca6ce6db32 | ||
|
|
1c9a6a02af | ||
|
|
ba9bafcb5f | ||
|
|
0628394122 | ||
|
|
99b2cd2ad0 | ||
|
|
707a6ecbaa | ||
|
|
aa2bc40f03 | ||
|
|
5e00e76c4b | ||
|
|
0dba992dd4 | ||
|
|
b6f61cac9b | ||
|
|
0e41945a8a | ||
|
|
a05e037308 | ||
|
|
f40576c39d | ||
|
|
9fc810182a | ||
|
|
dd7a52ba08 | ||
|
|
fa6d2a3080 | ||
|
|
36efc0c877 | ||
|
|
e9efcf1b92 | ||
|
|
f4ad1ec8e7 | ||
|
|
0027c21630 | ||
|
|
6173cab99f | ||
|
|
80c8097a71 | ||
|
|
ba3d577125 | ||
|
|
8ce4ebb16e | ||
|
|
4358ff2338 | ||
|
|
53f9eb083d | ||
|
|
0a3a982cb9 | ||
|
|
c30239b3a8 | ||
|
|
183834689d | ||
|
|
5da2f3279b | ||
|
|
ec7d87e757 | ||
|
|
4155f69e3c | ||
|
|
473e93ea16 | ||
|
|
fd1941cc3e | ||
|
|
dbb51b58db | ||
|
|
e7d00cfe54 | ||
|
|
63453fa962 | ||
|
|
689eb7f87b | ||
|
|
67a4646a50 | ||
|
|
a4e0535464 | ||
|
|
61495cd428 | ||
|
|
9e7b7415a5 | ||
|
|
06a462d48c | ||
|
|
d3e6e415b9 | ||
|
|
7e633d31a0 | ||
|
|
0fcf006484 | ||
|
|
48e5b1686f | ||
|
|
608d879c80 | ||
|
|
66055f1d7c | ||
|
|
1120bff34d | ||
|
|
24547e67bf | ||
|
|
f8c7285f56 | ||
|
|
82eb6a4568 | ||
|
|
a3f1f7c78d | ||
|
|
c377c4a52b | ||
|
|
e5a74cf43c | ||
|
|
ccf2bf84da | ||
|
|
fbf3d97d57 | ||
|
|
6da0f82ddd | ||
|
|
4c3df2e1e1 | ||
|
|
39e10ff01c | ||
|
|
0b29c6e5a4 | ||
|
|
cd3585be58 | ||
|
|
4e1f91f4d5 | ||
|
|
272c2e5303 | ||
|
|
2a82b09f7b | ||
|
|
fd26492577 | ||
|
|
528b90b694 | ||
|
|
9c7961ff6b | ||
|
|
954ed6457c | ||
|
|
5a8fc2dabc | ||
|
|
ce965ba5e1 | ||
|
|
4b9a036e5e | ||
|
|
4576f378cc | ||
|
|
4c65daa995 | ||
|
|
9159e14dd9 | ||
|
|
da661c229c | ||
|
|
973f09f98a | ||
|
|
fef370ad88 | ||
|
|
bc46b7172d | ||
|
|
71f546b467 | ||
|
|
a66f66c8ac | ||
|
|
c2c6ca22db | ||
|
|
b29440556a | ||
|
|
4104f6f772 | ||
|
|
01c56dabdf | ||
|
|
fafd8f8ee6 | ||
|
|
e2033eee23 | ||
|
|
780761664d | ||
|
|
0cfa737eff | ||
|
|
6463898c5d | ||
|
|
7d4fffa8b6 | ||
|
|
bcc415ccb3 | ||
|
|
827fead347 | ||
|
|
36cdc7dd1c | ||
|
|
99dceda8ac | ||
|
|
9d27f111bf | ||
|
|
69e0906491 | ||
|
|
1d48171fd5 | ||
|
|
cb0a3e3edf | ||
|
|
2b3915a91f | ||
|
|
9a403ba0ed | ||
|
|
0f35885d1c | ||
|
|
e3e07b6bfe | ||
|
|
84a6d1db71 | ||
|
|
8cee50299f | ||
|
|
5a78cbef02 | ||
|
|
ae66a781d1 | ||
|
|
5ae3b66e06 | ||
|
|
c3f1cee5d6 | ||
|
|
5552c42e37 | ||
|
|
6f146b888b | ||
|
|
56c09eae90 | ||
|
|
6883864e2d | ||
|
|
15bc395454 | ||
|
|
41997d5fe0 | ||
|
|
ed259cd130 | ||
|
|
1dc027cf49 | ||
|
|
b2abcda111 | ||
|
|
d66eaf8855 | ||
|
|
78cfd82fdd | ||
|
|
8ad44b405d | ||
|
|
4ce4288f68 | ||
|
|
d635555576 | ||
|
|
44999557c0 | ||
|
|
5d64bab719 | ||
|
|
4d3d8b643a | ||
|
|
915e8cf072 | ||
|
|
3c18fd7636 | ||
|
|
6c00ac43fc | ||
|
|
5d9a597d8d | ||
|
|
92930955c3 | ||
|
|
145482ea30 | ||
|
|
6fdb1e3356 | ||
|
|
55dff81b9f | ||
|
|
ed37972b99 | ||
|
|
c6b37307b0 | ||
|
|
5d719ba235 | ||
|
|
c19795cce0 | ||
|
|
df8f44d77d | ||
|
|
a4eff45534 | ||
|
|
b2b12be3b0 | ||
|
|
9c77c53366 | ||
|
|
1449f165dd | ||
|
|
94216cf745 | ||
|
|
120e179fb8 | ||
|
|
f10114ee17 | ||
|
|
8a059e0fbb | ||
|
|
6263788d6a | ||
|
|
6ffb3136d4 | ||
|
|
b65b01fe3d | ||
|
|
b9c134654f | ||
|
|
d1a1342587 | ||
|
|
1ec2ac472a | ||
|
|
9894322c17 | ||
|
|
7edbf4ffc8 | ||
|
|
2b1d186611 | ||
|
|
70c49922b0 | ||
|
|
30d6a4d9eb | ||
|
|
033b2b9ba0 | ||
|
|
25aec80e4c | ||
|
|
cf3d52772d | ||
|
|
f78f303a79 | ||
|
|
02cffa01e2 | ||
|
|
c2f2a5e52f | ||
|
|
d8e19415e3 | ||
|
|
387dc2f59c | ||
|
|
ec3660a86d | ||
|
|
36fb23d467 | ||
|
|
33df456cfd | ||
|
|
7a6fe5ed5f | ||
|
|
558b10499b | ||
|
|
1fb3698ba2 | ||
|
|
89f26bbc6b | ||
|
|
bbd8615cda | ||
|
|
93132f5d7b | ||
|
|
179514ddf1 | ||
|
|
4b9cff2271 | ||
|
|
c3649a9c80 | ||
|
|
9a66b9003f | ||
|
|
34e32403b0 | ||
|
|
c2e34a8b0e | ||
|
|
d0ba4b6702 | ||
|
|
eb16025800 | ||
|
|
9f06c9a051 | ||
|
|
641122b16f | ||
|
|
fbe8708378 | ||
|
|
21c7b486ff | ||
|
|
c33728d418 | ||
|
|
a9dacd561c | ||
|
|
051e15215d | ||
|
|
fee8f58c0a | ||
|
|
cc036cf3c5 | ||
|
|
4e51517ddb | ||
|
|
3b7454961d | ||
|
|
88009e1a63 | ||
|
|
0afca29b0c | ||
|
|
46a75a2944 | ||
|
|
c099f82752 | ||
|
|
1da94bd9c8 | ||
|
|
96ce8165e9 | ||
|
|
f9b617339d | ||
|
|
58084810f3 | ||
|
|
429e62e6b5 | ||
|
|
b0b7f2afdf | ||
|
|
55f160d125 | ||
|
|
f6352f5392 | ||
|
|
ac7e90c0aa | ||
|
|
88fccfd6cd | ||
|
|
5fdf8e6045 | ||
|
|
d9907cdbeb | ||
|
|
d308f1ca3b | ||
|
|
0cdc138ba3 | ||
|
|
59d5314164 | ||
|
|
9c08a37772 | ||
|
|
b13f5356fe | ||
|
|
5f0c9725ce | ||
|
|
f951fea555 | ||
|
|
4b989b01e9 | ||
|
|
aed3ec5474 | ||
|
|
b354986199 | ||
|
|
e1983a7d66 | ||
|
|
0400d79f43 | ||
|
|
c911484632 | ||
|
|
713e441d2e | ||
|
|
d4b577732b | ||
|
|
440a410d7f | ||
|
|
37a536b138 | ||
|
|
a0aca3e837 | ||
|
|
b58c29111a | ||
|
|
b0f86ea161 | ||
|
|
93b59a75a4 | ||
|
|
54fcabaea6 | ||
|
|
0e966c0304 | ||
|
|
a363712127 | ||
|
|
4d8c665917 | ||
|
|
53bdd92e72 | ||
|
|
e51aa39ede | ||
|
|
33c82129ff | ||
|
|
7c5b8c0e9f | ||
|
|
9dc01bca1c | ||
|
|
3c7920b84c | ||
|
|
b92f3abbaf | ||
|
|
b6747a63ed | ||
|
|
41a44548d2 | ||
|
|
a79d3a0d7c | ||
|
|
f3a17709e5 | ||
|
|
ced9d33d2e | ||
|
|
23b1373f80 | ||
|
|
a80eb1f533 | ||
|
|
f657edf195 | ||
|
|
d34279dca5 | ||
|
|
954aa1112a | ||
|
|
b35a3339cb | ||
|
|
b59433debd | ||
|
|
fb2db9c652 | ||
|
|
2507f3301b | ||
|
|
bdad5e4f0a | ||
|
|
b5dcdc74d7 | ||
|
|
e2d1da02d3 | ||
|
|
8253f18312 | ||
|
|
f4a98a2031 | ||
|
|
224845cfd3 | ||
|
|
fc8c2ad67a | ||
|
|
c9d6f58563 | ||
|
|
325b557506 | ||
|
|
ce751cfc87 | ||
|
|
0f451fd4b9 | ||
|
|
b7819838b8 | ||
|
|
67c6cf6b8c | ||
|
|
d91d71333b | ||
|
|
431804ea80 | ||
|
|
7a7ab7bd0e | ||
|
|
b8cdee383b | ||
|
|
580fa02ee1 | ||
|
|
421834153d | ||
|
|
011f04e1dc | ||
|
|
3d8056704c | ||
|
|
41263f3419 | ||
|
|
9fe9210cb7 | ||
|
|
2272b10820 | ||
|
|
9d6fc73fcc | ||
|
|
73ecd67b20 | ||
|
|
e5ce3dbd32 | ||
|
|
a0a5e30f48 | ||
|
|
0eddee5816 | ||
|
|
6d2dcb73ae | ||
|
|
0d6cc91b67 | ||
|
|
ae52922698 | ||
|
|
236496e69f | ||
|
|
fe5cdb0004 | ||
|
|
f9547f158e | ||
|
|
0c75374c0f | ||
|
|
0b249d4dd4 | ||
|
|
a2bac9d368 | ||
|
|
392e429dfd | ||
|
|
50623b9b29 | ||
|
|
e7ce050324 | ||
|
|
762b574d49 | ||
|
|
d73bf6d225 | ||
|
|
c2108fdda0 | ||
|
|
2062a284e3 | ||
|
|
9164c9b946 | ||
|
|
13ddd10c40 | ||
|
|
e407acd2a7 | ||
|
|
11cdf52ec8 | ||
|
|
40a3541e8e | ||
|
|
7da13e22ad | ||
|
|
38d702b6fe | ||
|
|
df2af5459e | ||
|
|
40d68b1654 | ||
|
|
a240a4ac66 | ||
|
|
416ec3812d | ||
|
|
ff24891903 | ||
|
|
ddcbe298ac | ||
|
|
6d8f647aee | ||
|
|
a654987175 | ||
|
|
a5f960d8a1 | ||
|
|
1f707cda68 | ||
|
|
4e7f195fd2 | ||
|
|
7728e930be | ||
|
|
ab84200347 | ||
|
|
62d8824450 | ||
|
|
cf35d20adb | ||
|
|
65725b5a38 | ||
|
|
eca4777b99 | ||
|
|
066b3aba5b | ||
|
|
8e485ff26f | ||
|
|
341b66f44f | ||
|
|
19c62d3320 | ||
|
|
13ffbd7675 | ||
|
|
9af6aae699 | ||
|
|
2e562e8318 | ||
|
|
c6db763716 | ||
|
|
a3383af4ae | ||
|
|
6c56e44b61 | ||
|
|
64506a7080 | ||
|
|
fac9ae4b6c | ||
|
|
a2dc73afef | ||
|
|
59c5a34cd0 | ||
|
|
3321e6b0e2 | ||
|
|
8b7ac179fa | ||
|
|
ea745665c8 | ||
|
|
ca8f6ee10b | ||
|
|
3e51ff46f3 | ||
|
|
fa2e814559 | ||
|
|
87e337cbeb | ||
|
|
abb39df547 | ||
|
|
43e15bf911 | ||
|
|
4d79d0af89 | ||
|
|
69100d7db5 | ||
|
|
a064a6cf9b | ||
|
|
7953a9a3ce | ||
|
|
be3c6f210d | ||
|
|
f7cbddab4b | ||
|
|
d423818764 | ||
|
|
519acd43aa | ||
|
|
2682a0d9e4 | ||
|
|
8629ae048c | ||
|
|
905d01e804 | ||
|
|
0588bbc41d | ||
|
|
b308b4c54f | ||
|
|
c2c73d5460 | ||
|
|
e01bf57874 | ||
|
|
7ced93225b | ||
|
|
b5e61864af | ||
|
|
1e5aaea8f4 | ||
|
|
ab3bebf06a | ||
|
|
4a294d6a77 | ||
|
|
e0fda1a0bc | ||
|
|
d17da80f19 | ||
|
|
2e7658f857 | ||
|
|
53d0b28c7c | ||
|
|
33ba4d3871 | ||
|
|
225db6397d | ||
|
|
73b5d1b3f1 | ||
|
|
8da2eac6d0 | ||
|
|
fbd62153ee | ||
|
|
9145fa1c48 | ||
|
|
caa0af1258 | ||
|
|
7a230ee5f5 | ||
|
|
f237fa98d2 | ||
|
|
be4ae605a9 | ||
|
|
9c2cbc0ecb | ||
|
|
fb3009fc66 | ||
|
|
04c32e28cd | ||
|
|
645576c949 | ||
|
|
775bee3546 | ||
|
|
88aea96034 | ||
|
|
5f474dfaf5 | ||
|
|
fe7aad0835 | ||
|
|
79746efa2d | ||
|
|
a158021f46 | ||
|
|
2d91a893f7 | ||
|
|
dd4561d985 | ||
|
|
92764eeae0 | ||
|
|
b72808ab40 | ||
|
|
14f3f99218 | ||
|
|
d7130d9b67 | ||
|
|
3f94eee4d5 | ||
|
|
72cbdcbc8d | ||
|
|
e33b49e78c | ||
|
|
8e04945d4e | ||
|
|
3ca5da55cb | ||
|
|
ea30373a09 | ||
|
|
4b4757d0e5 | ||
|
|
4bc837509d | ||
|
|
c9d1e8dc65 | ||
|
|
88b8a192b5 | ||
|
|
94fbf627ba | ||
|
|
45fbdb8411 | ||
|
|
d9c947ccd0 | ||
|
|
2b670a5ae1 | ||
|
|
1af0178b50 | ||
|
|
3ec5d894b3 | ||
|
|
d81585ccc3 | ||
|
|
38f91bce1c | ||
|
|
2d41dd6ae0 | ||
|
|
1705a21f68 | ||
|
|
164d79898a | ||
|
|
50f809d290 | ||
|
|
39284b475d | ||
|
|
d44950d46c | ||
|
|
e9b55bc207 | ||
|
|
5470f08fee | ||
|
|
f9a3bbd7fa | ||
|
|
9d3165dc65 | ||
|
|
3475d39f37 | ||
|
|
44782b1ddf | ||
|
|
dd8d5fd84c | ||
|
|
e8f2d9d0dd | ||
|
|
a2de3b5d80 | ||
|
|
a2960c45bc | ||
|
|
dc91624597 | ||
|
|
223ec180fc | ||
|
|
0116572fec | ||
|
|
5350e5385c | ||
|
|
8f18c4fd45 | ||
|
|
8538fbabe5 | ||
|
|
9367b34bbe | ||
|
|
a766044cb4 | ||
|
|
0eb385e49f | ||
|
|
e30136dace | ||
|
|
c50dee479a | ||
|
|
58ef292fa7 | ||
|
|
61b728fea7 | ||
|
|
b782eeb839 | ||
|
|
77314d4b8d | ||
|
|
c79d1d24b3 | ||
|
|
5dbea8ca09 | ||
|
|
09a1c17fb4 | ||
|
|
a0632bcac2 | ||
|
|
07d57ebe8c | ||
|
|
325c88018c | ||
|
|
dcb1102746 | ||
|
|
636d3c02c4 | ||
|
|
5b119ded17 | ||
|
|
f25ae870c5 | ||
|
|
49673262e4 | ||
|
|
3ed814c1f7 | ||
|
|
8b858e5407 | ||
|
|
30145894b6 | ||
|
|
8df4c27203 | ||
|
|
28166f79a1 | ||
|
|
2fe67137c5 | ||
|
|
a6ea2de691 | ||
|
|
7ffcde002e | ||
|
|
a3f66b8ab1 | ||
|
|
43cee53dc8 | ||
|
|
6c5979040f | ||
|
|
666291d12d | ||
|
|
c04a8ccdc2 | ||
|
|
b13d2f7f91 | ||
|
|
0b56dd2795 | ||
|
|
028ebff102 | ||
|
|
cd60c3da2a | ||
|
|
3d239a3c2b | ||
|
|
26d0077bb8 | ||
|
|
5dbe9e5ca2 | ||
|
|
5aac96edb5 | ||
|
|
c45b62fa6e | ||
|
|
e05708979d | ||
|
|
b6e7db6ecf | ||
|
|
17060a2a1b | ||
|
|
389fbc31e9 | ||
|
|
da3c3c30e7 | ||
|
|
42a7086088 | ||
|
|
5d4cc007bb | ||
|
|
a8dfb8e2b9 | ||
|
|
873999336f | ||
|
|
8476f53337 | ||
|
|
31a77a6e19 | ||
|
|
2376489f51 | ||
|
|
0bfd9f386e | ||
|
|
00e214871d | ||
|
|
fd41047923 | ||
|
|
393882f57b | ||
|
|
313e3a3447 | ||
|
|
23b3972503 | ||
|
|
01a64676b4 | ||
|
|
a8ee067215 | ||
|
|
504731885a | ||
|
|
76078348d6 | ||
|
|
464fb2144b | ||
|
|
c4e64ae80a | ||
|
|
a614d6634a | ||
|
|
856d7905db | ||
|
|
5b4be62fb4 | ||
|
|
44a58e3e9b | ||
|
|
28b6d2ee2e | ||
|
|
d749095d08 | ||
|
|
2cdf2cbe19 | ||
|
|
06669bc77b | ||
|
|
6cd6b00ea6 | ||
|
|
61bf43cd96 | ||
|
|
3be53235a5 | ||
|
|
0f0d9f9a10 | ||
|
|
e6cfa84b73 | ||
|
|
e5888e4b90 | ||
|
|
8e9e818c43 | ||
|
|
5f41487fd2 | ||
|
|
3b7d3e2652 | ||
|
|
5963cd35d5 | ||
|
|
c4ebd8b6b7 | ||
|
|
678640966e | ||
|
|
89f9394977 | ||
|
|
e7df752581 | ||
|
|
dca567b00d | ||
|
|
5248df85ec | ||
|
|
31d39e0626 | ||
|
|
5485bb574e | ||
|
|
337965a7f7 | ||
|
|
81cd2e26f4 | ||
|
|
95c07334d7 | ||
|
|
2f66ee264b | ||
|
|
5f16066641 | ||
|
|
6cdf84dcb7 | ||
|
|
d7bfc64840 | ||
|
|
d199c83a61 | ||
|
|
060e1a822f | ||
|
|
54141f77d6 | ||
|
|
d5c610b819 | ||
|
|
a2bedaab8a | ||
|
|
fa5c8c2c75 | ||
|
|
a2d00c4057 | ||
|
|
cf9595a0bc | ||
|
|
68d8b1fa3e | ||
|
|
6f905319c3 | ||
|
|
d6fd3edb3c | ||
|
|
5441c49d8d | ||
|
|
c7938a8630 | ||
|
|
bc0bb7c7bb | ||
|
|
1c58d99006 | ||
|
|
e0c52dea3a | ||
|
|
a1a5d3b363 | ||
|
|
9ae08932c2 | ||
|
|
7d8dfb997e | ||
|
|
c8d8d94c7f | ||
|
|
58f01493e0 | ||
|
|
4a01116e93 | ||
|
|
1cdc97f037 | ||
|
|
927c1a6799 | ||
|
|
8eec0c22d7 | ||
|
|
9d86fac103 | ||
|
|
65f2ea1df2 | ||
|
|
4d54c8f1d1 | ||
|
|
046f25c223 | ||
|
|
661cd79654 | ||
|
|
3b7078e565 | ||
|
|
e59ac5d65d | ||
|
|
67da9387ff | ||
|
|
c3f91761f6 | ||
|
|
a239ee80bc | ||
|
|
96275d8eec | ||
|
|
1ef086a02c | ||
|
|
db10fee207 | ||
|
|
279b53704b | ||
|
|
dbc750b44e | ||
|
|
b29ccf67b1 | ||
|
|
b67adf8789 | ||
|
|
113eaef0d1 | ||
|
|
6c88d25941 | ||
|
|
f6f6253eab | ||
|
|
8e1753ea37 | ||
|
|
83f8989d1f | ||
|
|
e1f5c97550 | ||
|
|
f8fa867154 | ||
|
|
f0893ca214 | ||
|
|
82a58d9487 | ||
|
|
d0ea6aedd0 | ||
|
|
775d929711 | ||
|
|
5bae62cdcb | ||
|
|
0a664c47b7 | ||
|
|
f856e559a2 | ||
|
|
0283120934 | ||
|
|
5237cbeab0 | ||
|
|
15961c419e | ||
|
|
8b591a7f0c | ||
|
|
f7977c3435 | ||
|
|
0c699e6c12 | ||
|
|
11e5b2ea5d | ||
|
|
fdfd2d20e6 | ||
|
|
32adb7b91a | ||
|
|
237d31be28 | ||
|
|
ee07182157 | ||
|
|
506ab12b95 | ||
|
|
42d6a7c9b8 | ||
|
|
44530b63ca | ||
|
|
eadba95d5f | ||
|
|
2574e0cba5 | ||
|
|
e03cf94441 | ||
|
|
b38b801963 | ||
|
|
4f990ffe96 | ||
|
|
8c54062c44 | ||
|
|
9766ebc8e3 | ||
|
|
07bc425046 | ||
|
|
d0b8c2c4bf | ||
|
|
83bc7c6d51 | ||
|
|
d64625aba2 | ||
|
|
d1eec27fae | ||
|
|
43517fc4f6 | ||
|
|
0e3eeab828 | ||
|
|
6b68e85077 | ||
|
|
c9faa40475 | ||
|
|
f8969675e7 | ||
|
|
d620b70dac | ||
|
|
4055f92831 | ||
|
|
3e50461ea7 | ||
|
|
5eee358059 | ||
|
|
17b90c744c | ||
|
|
a78997771f | ||
|
|
3a691977aa | ||
|
|
4bea105693 | ||
|
|
0918e1d963 | ||
|
|
11ec9b320e | ||
|
|
97e98e1d9d | ||
|
|
e6dcdc51a4 | ||
|
|
702d27fea0 | ||
|
|
59b086168a | ||
|
|
57c89f5b2a | ||
|
|
b69304992f | ||
|
|
a5256a6491 | ||
|
|
8211f85725 | ||
|
|
c27e44a7d2 | ||
|
|
22f16ea514 | ||
|
|
7ed45c3535 | ||
|
|
a3716bc841 | ||
|
|
e8c776fe49 | ||
|
|
999c9667c8 | ||
|
|
59620e6435 | ||
|
|
cf4a6bb1a2 | ||
|
|
8658ebd6bb | ||
|
|
59f1dcca12 | ||
|
|
4382490823 | ||
|
|
479ad31325 | ||
|
|
dd976b5b86 | ||
|
|
18c2c1433b | ||
|
|
0fc013eb8a | ||
|
|
1d95c73173 | ||
|
|
312b6c2d44 | ||
|
|
cab2b261b5 | ||
|
|
2ddb384c80 | ||
|
|
ca27b34122 | ||
|
|
5ce2eaf77e | ||
|
|
4ae02c27a4 | ||
|
|
50f71e7280 | ||
|
|
638de90cc4 | ||
|
|
d1646e5aca | ||
|
|
ddd521cd4b | ||
|
|
f5b05ecd92 | ||
|
|
4f2b76c442 | ||
|
|
6aef106482 | ||
|
|
b191542ab7 | ||
|
|
e0e69920e9 | ||
|
|
f3edae9bb1 | ||
|
|
0d5f5ec9ba | ||
|
|
582799464f | ||
|
|
fc0d91d3e7 | ||
|
|
81b8c1716f | ||
|
|
b5d2a9a2fb | ||
|
|
a98283f3ff | ||
|
|
61be796c76 | ||
|
|
dd090b0ed9 | ||
|
|
6588b5bebb | ||
|
|
aa3fd29508 | ||
|
|
dcf412d94d | ||
|
|
defac4e2d5 | ||
|
|
6163a6dd77 | ||
|
|
32e757a873 | ||
|
|
8df940447d | ||
|
|
ac6f3a6bb6 | ||
|
|
46e631388d | ||
|
|
ff7c9f210c | ||
|
|
eecf81f0a5 | ||
|
|
b356627afd | ||
|
|
e3dcf4aed1 | ||
|
|
4dd05cf10e | ||
|
|
68a85a2561 | ||
|
|
49cde1c67d | ||
|
|
249dffe778 | ||
|
|
6d9b860c8b | ||
|
|
b1eabdfe86 | ||
|
|
ab9bbf7b0f | ||
|
|
cf2308a12d | ||
|
|
0aa1359ad4 | ||
|
|
48c51173a1 | ||
|
|
6838b32304 | ||
|
|
60f81c5cba | ||
|
|
419cfceef1 | ||
|
|
c7b62c8551 | ||
|
|
a66489cd8c | ||
|
|
6d51864873 | ||
|
|
dc7b37c8f2 | ||
|
|
21bbb2af42 | ||
|
|
c3b9f4e5a8 | ||
|
|
70fa41ca3e | ||
|
|
49705b1074 | ||
|
|
32395dcb20 | ||
|
|
e34ca49b9b | ||
|
|
46a8ffa5ae | ||
|
|
3f8f29dfe7 | ||
|
|
67970afc1e | ||
|
|
1c08901698 | ||
|
|
86d8d64bf6 | ||
|
|
cc8b8f9ceb | ||
|
|
6e91d66b2c | ||
|
|
886f356525 | ||
|
|
3fe7324cdf | ||
|
|
a1741fdd67 | ||
|
|
40484a7bf0 | ||
|
|
48376d0a93 | ||
|
|
6be54fa7ee | ||
|
|
6c6da368dd | ||
|
|
d70de04816 | ||
|
|
bf022f8a41 | ||
|
|
7046a010f9 | ||
|
|
5cdccc7527 | ||
|
|
02552d0b24 | ||
|
|
026dd4761e | ||
|
|
635dd5d4d5 | ||
|
|
81d972a462 | ||
|
|
bfeddd6d99 | ||
|
|
437a60a967 | ||
|
|
6218c65ec6 | ||
|
|
25d02cec25 | ||
|
|
0bbb549533 | ||
|
|
4ca5593d2e | ||
|
|
630fc3f73c | ||
|
|
d66646d168 | ||
|
|
ffe7771801 | ||
|
|
5942bcc16d | ||
|
|
eb3d0d726f | ||
|
|
a4846c7b11 | ||
|
|
8e7ed05f25 | ||
|
|
84d21efb5d | ||
|
|
68ee013114 | ||
|
|
cd8a09ddef | ||
|
|
e1f6302280 | ||
|
|
144197daaf | ||
|
|
57af4e0a03 | ||
|
|
309caa2f83 | ||
|
|
3f11fdaa82 | ||
|
|
faccb61a6b | ||
|
|
786f3b4644 | ||
|
|
58d101659a | ||
|
|
822fc7f308 | ||
|
|
29ab7f7a30 | ||
|
|
bf4f0bdba0 | ||
|
|
e8705d49f2 | ||
|
|
6d49253ee5 | ||
|
|
23f27282d6 | ||
|
|
bfa336b72d | ||
|
|
b5522c1b5e | ||
|
|
543e3418a5 | ||
|
|
ea3dcd6250 | ||
|
|
b8cbd5e0aa | ||
|
|
29951207ec | ||
|
|
3c58775ae2 | ||
|
|
9ab41c5de6 | ||
|
|
65f3a146fa | ||
|
|
22366ec0a2 | ||
|
|
d038fb900e | ||
|
|
13c5ebe065 | ||
|
|
4112e0a4c9 | ||
|
|
f73a5d6307 | ||
|
|
a3e165fa06 | ||
|
|
3e633dc38e | ||
|
|
d53bfae529 | ||
|
|
9d491a3636 | ||
|
|
c77d4b795a | ||
|
|
c96daf2d68 | ||
|
|
961e23f0b8 | ||
|
|
defb67c523 | ||
|
|
4aa1209bc7 | ||
|
|
a7ad89471a | ||
|
|
1f74e102fa | ||
|
|
5761b47073 | ||
|
|
22a0b262e1 | ||
|
|
6e42f5ce7b | ||
|
|
c5bd59e52c | ||
|
|
c65b065dd7 | ||
|
|
3f8ab1bfe7 | ||
|
|
cf41c5e090 | ||
|
|
290e90ba8e | ||
|
|
84c9516659 | ||
|
|
3eb1ab0452 | ||
|
|
f317f45d14 | ||
|
|
5f6a3f4cb5 | ||
|
|
27b6631cc1 | ||
|
|
f7bb091366 | ||
|
|
5cf2092576 | ||
|
|
954de743f5 | ||
|
|
8ab632e207 | ||
|
|
547cd4e828 | ||
|
|
264028b623 | ||
|
|
2c302985f8 | ||
|
|
d6f46cf5c5 | ||
|
|
d4ed276684 | ||
|
|
67e458833f | ||
|
|
291c201b00 | ||
|
|
f9473ea61d | ||
|
|
b68031bd11 | ||
|
|
879b5ef3aa | ||
|
|
ff1f895476 | ||
|
|
3229835f50 | ||
|
|
f0a96759a4 | ||
|
|
4f4c6064db | ||
|
|
df802152d7 | ||
|
|
4f3a3a5b19 | ||
|
|
cc7ccf921b | ||
|
|
4dfd8b6985 | ||
|
|
919eedc0fa | ||
|
|
9400c22e4f | ||
|
|
99f00b8e63 | ||
|
|
29d876eaed | ||
|
|
018a7c9f96 | ||
|
|
28473dd85f | ||
|
|
29b37219c2 | ||
|
|
34fd9b5842 | ||
|
|
2b2787b187 | ||
|
|
253217cf20 | ||
|
|
74c0e52458 | ||
|
|
75cb67890d | ||
|
|
9668bd85c1 | ||
|
|
9aef584494 | ||
|
|
a535e8a82b | ||
|
|
3bd01067e3 | ||
|
|
056b9fd2de | ||
|
|
da2ec4a38e | ||
|
|
fb5c36071d | ||
|
|
b07afa7f11 | ||
|
|
a0e65fa75e | ||
|
|
866a20ed5a | ||
|
|
49c355e52f | ||
|
|
8d0dc2d230 | ||
|
|
cbda58f770 | ||
|
|
bb0ee239b4 | ||
|
|
0495c17fc8 | ||
|
|
2a5739dfdc | ||
|
|
0b73317dd0 | ||
|
|
5dc4357078 | ||
|
|
cf2ae9d7e8 | ||
|
|
68c6537bcb | ||
|
|
a236d7fbb1 | ||
|
|
13267ff83d | ||
|
|
8c31c7290c | ||
|
|
7d3ef39f67 | ||
|
|
51ee93eca0 | ||
|
|
2816e72aa9 | ||
|
|
5ef4c96ee7 | ||
|
|
4ed12a859b | ||
|
|
128935eb9f | ||
|
|
2553938380 | ||
|
|
59e412ea09 | ||
|
|
9195bdcf95 | ||
|
|
2ca066327a | ||
|
|
daa9bdfb8c | ||
|
|
faf690d899 | ||
|
|
9965121011 | ||
|
|
15cda95c64 | ||
|
|
9678eab43f | ||
|
|
3b97fa0379 | ||
|
|
c8368a2190 | ||
|
|
ba9605383d | ||
|
|
caaec3ea57 | ||
|
|
a018369ae8 | ||
|
|
b4f4f24c24 | ||
|
|
9eeafcd027 | ||
|
|
464f4ba300 | ||
|
|
cad56d438f | ||
|
|
5812dc7e7e | ||
|
|
4a1bccd516 | ||
|
|
e46277c2ac | ||
|
|
33684bd140 | ||
|
|
865deaf401 | ||
|
|
1f4bdb04ee | ||
|
|
a5bf16a415 | ||
|
|
2a6fe3f351 | ||
|
|
9468bb322d | ||
|
|
9650e44078 | ||
|
|
134a4ec5d2 | ||
|
|
b7d87486a8 | ||
|
|
a75295662c | ||
|
|
69eeb8bd23 | ||
|
|
65fe0e8f62 | ||
|
|
8fa2ef863f | ||
|
|
5e114e8074 | ||
|
|
223e8a5293 | ||
|
|
aee9ce802a | ||
|
|
04bd6b49ad | ||
|
|
e9d54d9cf5 | ||
|
|
9b2ce98b46 | ||
|
|
d7312e2977 | ||
|
|
c2a168c6b7 | ||
|
|
a01f9c7351 | ||
|
|
dc0f9847c6 | ||
|
|
7613f4191b | ||
|
|
1b613db534 | ||
|
|
fb50123af0 | ||
|
|
08c3aff60b | ||
|
|
9cb141ef62 | ||
|
|
baf77eb3a3 | ||
|
|
0625f313dc | ||
|
|
b644ed5a25 | ||
|
|
18ff6c7976 | ||
|
|
be5fd8381f | ||
|
|
003092a55b | ||
|
|
3d50133fa8 | ||
|
|
594a491251 | ||
|
|
1cde9b8356 | ||
|
|
b107df60e2 | ||
|
|
997ed42178 | ||
|
|
913cd23c45 | ||
|
|
6cd1171fd5 | ||
|
|
c3fe3292ad | ||
|
|
b48c231500 | ||
|
|
a6cd16cdb5 | ||
|
|
2959577163 | ||
|
|
efddb385d8 | ||
|
|
ea5a411f30 | ||
|
|
7548122e2d | ||
|
|
a4cbf3bee3 | ||
|
|
7f2c265965 | ||
|
|
c6ce3e9480 | ||
|
|
6d8af4d97a | ||
|
|
60efcbaf02 | ||
|
|
3b63fbb61b | ||
|
|
2637587cf7 | ||
|
|
480f954433 | ||
|
|
7c1549bb95 | ||
|
|
4b7366e9b3 | ||
|
|
6288a06b49 | ||
|
|
b3c67bab92 | ||
|
|
8c8fa8ae4c | ||
|
|
0c93fc2662 | ||
|
|
aec2855db9 | ||
|
|
2becf769c1 | ||
|
|
da73a2f5d2 | ||
|
|
1dd5f9fc27 | ||
|
|
e141991166 | ||
|
|
fff32e8086 | ||
|
|
859788ca46 | ||
|
|
b94485be75 | ||
|
|
43948c65f1 | ||
|
|
b61355a8fa | ||
|
|
8834492ec2 | ||
|
|
676e896d8c | ||
|
|
6d159740d9 | ||
|
|
f48aa24129 | ||
|
|
f46151bb71 | ||
|
|
818414eb37 | ||
|
|
808fcea655 | ||
|
|
d050e01d08 | ||
|
|
6cab060509 | ||
|
|
18f04af051 | ||
|
|
4b3bae5797 | ||
|
|
98291caf76 | ||
|
|
a1a8c95ece | ||
|
|
40b6460ac9 | ||
|
|
25c82ffd58 | ||
|
|
f76051d362 | ||
|
|
351c99fb42 | ||
|
|
803527f585 | ||
|
|
d1c696bad5 | ||
|
|
5d2f4e6ca4 | ||
|
|
567ebcd06e | ||
|
|
1103354de3 | ||
|
|
2fa3d214e5 | ||
|
|
7d6ec46ebe | ||
|
|
40598721f1 | ||
|
|
576f44a924 | ||
|
|
694e4960ad | ||
|
|
4b67ba027e | ||
|
|
eeb28f6ddf | ||
|
|
4aa5ba2754 | ||
|
|
f228758fb7 | ||
|
|
d136eee224 | ||
|
|
52a978a59a | ||
|
|
8ade49c958 | ||
|
|
7c6c36b744 | ||
|
|
6c59bf8717 | ||
|
|
87798612a6 | ||
|
|
c89805d123 | ||
|
|
a1ba2bf60b | ||
|
|
87543f5beb | ||
|
|
2e31a7b280 | ||
|
|
9fb2ce9297 | ||
|
|
567d527a71 | ||
|
|
6ee109dc80 | ||
|
|
6a65b6d735 | ||
|
|
b9838ecc4e | ||
|
|
e1080f9be4 | ||
|
|
115fa349d2 | ||
|
|
567161d8f3 | ||
|
|
579a7e0398 | ||
|
|
0d417b3eee | ||
|
|
9e51c46522 | ||
|
|
36780c5ef8 | ||
|
|
9e3ee50020 | ||
|
|
963b27fd71 | ||
|
|
13a2206735 | ||
|
|
929727ba41 | ||
|
|
a0f6af8097 | ||
|
|
f79f93ba43 | ||
|
|
0898e3cc09 | ||
|
|
c68927c17a | ||
|
|
9f740cf371 | ||
|
|
474ce458bf | ||
|
|
8c6823c463 | ||
|
|
8055de4f25 | ||
|
|
d1c1aff7d9 | ||
|
|
41321e3c9e | ||
|
|
992cf033f2 | ||
|
|
24b4073616 | ||
|
|
4ef8ccaa8e | ||
|
|
f0eca137ef | ||
|
|
3f5115728b | ||
|
|
3539d7389e | ||
|
|
8c79c42b28 | ||
|
|
1085808867 | ||
|
|
0a5f9f1b23 | ||
|
|
8006bcf10c | ||
|
|
61e95e03c8 | ||
|
|
2b2342bcad | ||
|
|
56b8bc1730 | ||
|
|
53aaf7caa8 | ||
|
|
18f659de7b | ||
|
|
b2c0b02be4 | ||
|
|
61c1c6ebf8 | ||
|
|
b837c600a8 | ||
|
|
54a109345b | ||
|
|
3a90b3beb6 | ||
|
|
fe52324eea | ||
|
|
a1c853d7fc | ||
|
|
53974c4464 | ||
|
|
69ac98b2f6 | ||
|
|
d84eece715 | ||
|
|
af7a456e96 | ||
|
|
6088cfe266 | ||
|
|
02e03c7654 | ||
|
|
30dd2e993f | ||
|
|
574c826036 | ||
|
|
6d22888bf6 | ||
|
|
556741683d | ||
|
|
cb9dddc7a7 | ||
|
|
fca1dbd6ec | ||
|
|
364f25e22a | ||
|
|
9042702c09 | ||
|
|
86f1874379 | ||
|
|
781f838ce7 | ||
|
|
addb7a0ecb | ||
|
|
21777602f6 | ||
|
|
a88f799372 | ||
|
|
daee1a8e9d | ||
|
|
afd5d55b5f | ||
|
|
0f2d2ac7a9 | ||
|
|
a77bf9ddff | ||
|
|
297beac169 | ||
|
|
5a7f106e3e | ||
|
|
25636ac6ce | ||
|
|
6d11921f45 | ||
|
|
05f6d6d156 | ||
|
|
b0cabbbfc2 | ||
|
|
4b9fa5041c | ||
|
|
ed2ea75938 | ||
|
|
a1fdc4a970 | ||
|
|
d20b3cadbf | ||
|
|
1374ee31ba | ||
|
|
062f6b6665 | ||
|
|
8053e6cb81 | ||
|
|
60c5bbc73d | ||
|
|
f0fb401d07 | ||
|
|
6f3c302f28 | ||
|
|
ba5495877c | ||
|
|
2b8fe5fa98 | ||
|
|
c4253e63d2 | ||
|
|
8c1dc9c4ae | ||
|
|
bfddb2b4d6 | ||
|
|
b53ba52d05 | ||
|
|
0694721e68 | ||
|
|
bc0084cc8b | ||
|
|
d3d4cca0e8 | ||
|
|
5b6becc63f | ||
|
|
7ed015aeb1 | ||
|
|
a8b84da17f | ||
|
|
2d687c98df | ||
|
|
9c2a6da692 | ||
|
|
ee9ecfbee9 | ||
|
|
9d8a9387bc | ||
|
|
8934cebc2a | ||
|
|
c03a42e108 | ||
|
|
a39dfcf4d5 | ||
|
|
f25ab537f2 | ||
|
|
ff776e485a | ||
|
|
3b9f4433ad | ||
|
|
a8c18cf83a | ||
|
|
dff91dc67d | ||
|
|
fdea212415 | ||
|
|
421f7e8799 | ||
|
|
8fc5ad099b | ||
|
|
0b1c0be0f0 | ||
|
|
5cc1e2bb29 | ||
|
|
c0eb84b7b1 | ||
|
|
66e8d955d9 | ||
|
|
e280f585cf | ||
|
|
366578600b | ||
|
|
8611501423 | ||
|
|
8175af4e84 | ||
|
|
7ff628ea51 | ||
|
|
5792372a47 | ||
|
|
9a169251d7 | ||
|
|
2f0935dbbe | ||
|
|
5af7c7d58a | ||
|
|
9e1abb13a3 | ||
|
|
bbea5fe53c | ||
|
|
ed087b81b4 | ||
|
|
0b06c87cb7 | ||
|
|
a9d204d3fa | ||
|
|
36e263b9ff | ||
|
|
49af74729f | ||
|
|
aec0415cad | ||
|
|
8c8cec08e5 | ||
|
|
8d0ee1caba | ||
|
|
a2a6d5a57f | ||
|
|
9593f330db | ||
|
|
144d932591 | ||
|
|
726db336a8 | ||
|
|
8632f7cadc | ||
|
|
525b5fa19a | ||
|
|
b7c6b65a3d | ||
|
|
a4f93eea45 | ||
|
|
8d9a5bc08f | ||
|
|
28a93cdcb4 | ||
|
|
d32dd95e12 | ||
|
|
f19a8a3cc5 | ||
|
|
f8d5ee9d5d | ||
|
|
a98fb7d41e | ||
|
|
d2ccc5c022 | ||
|
|
3339c8b676 | ||
|
|
2cc331b136 | ||
|
|
df1a65e6a3 | ||
|
|
f416f95b77 | ||
|
|
44fe5af4fb | ||
|
|
f394eddc01 | ||
|
|
07dd9df3ec | ||
|
|
340d4ce714 | ||
|
|
2870b8331e | ||
|
|
bc79f22e22 | ||
|
|
b3e0b148a6 | ||
|
|
6131dfeb2c | ||
|
|
42fc868b68 | ||
|
|
e9ec02929d | ||
|
|
389d7d77c2 | ||
|
|
03a55d38d3 | ||
|
|
5504298251 | ||
|
|
0fff61de34 | ||
|
|
4db7311611 | ||
|
|
650d970b5e | ||
|
|
7f796963f3 | ||
|
|
9231da2f1c | ||
|
|
0d422c53d1 | ||
|
|
7bf9354e32 | ||
|
|
277fd67814 | ||
|
|
68e9cd3779 | ||
|
|
73b2ae71a9 | ||
|
|
f9028245d8 | ||
|
|
3fff0617fe | ||
|
|
d958dc6bce | ||
|
|
045ce42168 | ||
|
|
edef84a4f9 | ||
|
|
ec9b2d7f7d | ||
|
|
640beeed23 | ||
|
|
a998ee84ec | ||
|
|
bd74634201 | ||
|
|
364287028b | ||
|
|
7be8513bb5 | ||
|
|
89c2f62f11 | ||
|
|
fce2a7ba94 | ||
|
|
e613198252 | ||
|
|
3e240c4d2f | ||
|
|
eee96bf8cf | ||
|
|
471871eb2e | ||
|
|
225b8b8cd8 | ||
|
|
cb2d133eb0 | ||
|
|
d957111249 | ||
|
|
f0a701e134 | ||
|
|
0c8c216fba | ||
|
|
f153c7509c | ||
|
|
197683b722 | ||
|
|
fbce0be457 | ||
|
|
24304c2f55 | ||
|
|
b0c6c09cea | ||
|
|
2732fc93f9 | ||
|
|
cc9a4a288a | ||
|
|
f57db917d1 | ||
|
|
d32eb9c9bc | ||
|
|
219af7f288 | ||
|
|
e767b6c5be | ||
|
|
5f1a8017f1 | ||
|
|
df80122ce1 | ||
|
|
6904ea118b | ||
|
|
0baa07daa2 | ||
|
|
2abf407b36 | ||
|
|
55dc9cbfc7 | ||
|
|
fa15a10ae0 | ||
|
|
e821d8a135 | ||
|
|
cefcc14d4d | ||
|
|
a52d1e1506 | ||
|
|
42df1aecd5 | ||
|
|
920f4fc525 | ||
|
|
d57d583076 | ||
|
|
1c8cd2dcbb | ||
|
|
bb66a6c805 | ||
|
|
10ecdfbe31 | ||
|
|
43dad1df63 | ||
|
|
fdcc6b0cb8 | ||
|
|
ac82d6bc6b | ||
|
|
a8e98cfa78 | ||
|
|
fa51314639 | ||
|
|
3e0097c22c | ||
|
|
e62ff2fe36 | ||
|
|
88a13eb54f | ||
|
|
355dc151c4 | ||
|
|
4f0ea44078 | ||
|
|
9cc12fd577 | ||
|
|
960c2567bd | ||
|
|
430e4dd445 | ||
|
|
1ec31c6899 | ||
|
|
42c21ce892 | ||
|
|
d278fde5f2 | ||
|
|
2616a5f500 | ||
|
|
cc58f7730e | ||
|
|
d49e001b21 | ||
|
|
f12ceb69ce | ||
|
|
7862005055 | ||
|
|
e70dbf8d8d | ||
|
|
16ee34d7a7 | ||
|
|
2ad55e8a8c | ||
|
|
a8a1750d5c | ||
|
|
5407e20150 | ||
|
|
58aa37bf8e | ||
|
|
7c781b60c5 | ||
|
|
acdfce7e88 | ||
|
|
4e4b56d7fe | ||
|
|
a3174d7015 | ||
|
|
b595c8aeac | ||
|
|
a9a33ad71e | ||
|
|
4d08ce90cc | ||
|
|
01d9ccc110 | ||
|
|
029f069ad5 | ||
|
|
13b9e01604 | ||
|
|
19c46a472a | ||
|
|
37edfffb97 | ||
|
|
67fa653d06 | ||
|
|
366b9ddc4a | ||
|
|
c9354f79b8 | ||
|
|
d5b3bd5905 | ||
|
|
45dd240415 | ||
|
|
bf99cea004 | ||
|
|
f680b1e856 | ||
|
|
b2f40c7af0 | ||
|
|
82b17677b9 | ||
|
|
b7df2d5441 | ||
|
|
dd511ba365 | ||
|
|
d705e3c1fb | ||
|
|
4bd1322904 | ||
|
|
ac027ee3a0 | ||
|
|
e5e3ebdbba | ||
|
|
993fc2e6f4 | ||
|
|
61c480618c | ||
|
|
db7f2622c8 | ||
|
|
a39e78a989 | ||
|
|
5a461d68a7 | ||
|
|
899816673c | ||
|
|
84a10139c1 | ||
|
|
da3aa56d86 | ||
|
|
a6dcd512ea | ||
|
|
572d32c1de | ||
|
|
e8b67ead1e | ||
|
|
377029226e | ||
|
|
72d1421f1d | ||
|
|
d359547dab | ||
|
|
9523c7ab33 | ||
|
|
7cac07c185 | ||
|
|
a607a7f3ef | ||
|
|
b5277e89d5 | ||
|
|
99713f8ed7 | ||
|
|
145dac500c | ||
|
|
eefd9bf31c | ||
|
|
3f47ca645b | ||
|
|
c906f037b5 | ||
|
|
ffc4e32119 | ||
|
|
51eb46241b | ||
|
|
541416f64b | ||
|
|
14d1d132a3 | ||
|
|
22a0045796 | ||
|
|
2e5ba0335d | ||
|
|
3315704c14 | ||
|
|
f90c407fb6 | ||
|
|
d3646e10a5 | ||
|
|
d3003efe72 | ||
|
|
235ca947be | ||
|
|
e7bc9ed5ba | ||
|
|
740a18dbc0 | ||
|
|
add5189bb1 | ||
|
|
62002b8bb3 | ||
|
|
41b4ee33fe | ||
|
|
85c67ac676 | ||
|
|
4637b7d93f | ||
|
|
8b9a178c87 | ||
|
|
c595c381a9 | ||
|
|
c308d7a610 | ||
|
|
f7570122c6 | ||
|
|
1e5f186b58 | ||
|
|
b732b2ffa7 | ||
|
|
617a7be4f3 | ||
|
|
5c5e368d6b | ||
|
|
ff9f49416a | ||
|
|
93cae0e9cc | ||
|
|
61e75ce747 | ||
|
|
50affe26c5 | ||
|
|
8566362607 | ||
|
|
36925770d0 | ||
|
|
d17ca1686e | ||
|
|
2ad709dae4 | ||
|
|
5a3d86a12a | ||
|
|
1a4ba36820 | ||
|
|
ddeae3b5ba | ||
|
|
10df9e7cd5 | ||
|
|
be11933c60 | ||
|
|
d2db68b781 | ||
|
|
da6e271584 | ||
|
|
5103c80e1e | ||
|
|
b5c80ea267 | ||
|
|
b5747fbb44 | ||
|
|
215ded8a77 | ||
|
|
e7ab6da068 | ||
|
|
ee881f67ee | ||
|
|
f33248aa4f | ||
|
|
c6a40bac03 | ||
|
|
aa38e79d08 | ||
|
|
9cac10e559 | ||
|
|
efbd418f56 | ||
|
|
4ff3464abd | ||
|
|
907ddbf903 | ||
|
|
7041991d5a | ||
|
|
b26067e5da | ||
|
|
e519b13533 | ||
|
|
30bc3867bf | ||
|
|
5326c3aecc | ||
|
|
c95251c903 | ||
|
|
e08a0a0938 | ||
|
|
fcb072c37d | ||
|
|
262c19b194 | ||
|
|
1031ddcd83 | ||
|
|
aaee0212f0 | ||
|
|
8fc95759ba | ||
|
|
b6a3a0a54f | ||
|
|
e3091be314 | ||
|
|
045d0678b3 | ||
|
|
e3eeaddb3e | ||
|
|
f2b202c714 | ||
|
|
e6f3ad60ef | ||
|
|
fb6e0c9eb8 | ||
|
|
fb6e488339 | ||
|
|
0bccc8f0d5 | ||
|
|
560d831e92 | ||
|
|
7c8f6a1cc7 | ||
|
|
deb1ead4ea | ||
|
|
005b2a4fb6 | ||
|
|
4c8204f29a | ||
|
|
83fd19784a | ||
|
|
1f21a2ecc7 | ||
|
|
c3f4d56d1e | ||
|
|
7e4f79bacb | ||
|
|
b8267d4329 | ||
|
|
205ca693b3 | ||
|
|
23159c2201 | ||
|
|
884521ced0 | ||
|
|
aeb01ba292 | ||
|
|
2b1a556e9e | ||
|
|
d5c3ae3d19 | ||
|
|
7654bb7088 | ||
|
|
64c301caeb | ||
|
|
e875b530b1 | ||
|
|
ee8c2b5272 | ||
|
|
9b8bdb0639 | ||
|
|
1a99bbb040 | ||
|
|
0982b45473 | ||
|
|
bcd210d504 | ||
|
|
c71608824b | ||
|
|
170876ac16 | ||
|
|
a6b172c445 | ||
|
|
e625450100 | ||
|
|
fca5447094 | ||
|
|
89f32beec5 | ||
|
|
65eb7662ad | ||
|
|
ea090dbe18 | ||
|
|
5750817620 | ||
|
|
93386d0e8b | ||
|
|
e9dd7b8f98 | ||
|
|
5010e7cb7a | ||
|
|
fb35f4fbca | ||
|
|
00c0a93a6b | ||
|
|
cd9a312e0b | ||
|
|
8cdb27fe43 | ||
|
|
d84d11d064 | ||
|
|
5d646a6112 | ||
|
|
dd334858ff | ||
|
|
dfd39ebc95 | ||
|
|
9dbb1f15a4 | ||
|
|
32fd04a7d9 | ||
|
|
3a33ff375d | ||
|
|
8877e71bd2 | ||
|
|
5b5385c01d | ||
|
|
9c365ecc48 | ||
|
|
99d1a6d043 | ||
|
|
854ef7e645 | ||
|
|
a8eeb12325 | ||
|
|
86a3f516b1 | ||
|
|
d6818939b3 | ||
|
|
c51449e607 | ||
|
|
333894ddeb | ||
|
|
052e227b65 | ||
|
|
4dd6df5bbe | ||
|
|
8847991bba | ||
|
|
0ffc6e4a1a | ||
|
|
9a399e06f3 | ||
|
|
6afccc2aea | ||
|
|
8cd3a21468 | ||
|
|
8b6d2d2b83 | ||
|
|
a39f4d5987 | ||
|
|
e236d045b0 | ||
|
|
592c7951df | ||
|
|
41efa96291 | ||
|
|
53f406a267 | ||
|
|
1390df48b6 | ||
|
|
01878ef00c | ||
|
|
6f119f25f4 | ||
|
|
3f31d78db1 | ||
|
|
014bf7777b | ||
|
|
7191969e9c | ||
|
|
0950510526 | ||
|
|
9eba3064a7 | ||
|
|
a4d785258e | ||
|
|
efef49f976 | ||
|
|
32a7b5bafb | ||
|
|
5fa080063c | ||
|
|
b3573f9482 | ||
|
|
916b7ee46b | ||
|
|
bfe8ad2034 | ||
|
|
bb9db7bf9d | ||
|
|
d7f7c8c568 | ||
|
|
10839588dd | ||
|
|
12cd2b67cd | ||
|
|
9a13036f4e | ||
|
|
2f025d51ff | ||
|
|
6cb6d3a358 | ||
|
|
0bb01d14bd | ||
|
|
2229c4e4d1 | ||
|
|
5c90c62378 | ||
|
|
b7ed0a29fe | ||
|
|
796c2ed58c | ||
|
|
39bd573d9d | ||
|
|
d4aaa547a7 | ||
|
|
f7e2382847 | ||
|
|
4bb16e7d93 | ||
|
|
e7e00e4ebf | ||
|
|
55d050fca7 | ||
|
|
98d4fef0ee | ||
|
|
5521892736 | ||
|
|
8f0fd0dfef | ||
|
|
514eab0b98 | ||
|
|
e35c84245d | ||
|
|
4a2391eb1b | ||
|
|
04eb497e10 | ||
|
|
a9a5da6dc6 | ||
|
|
3f1aab27d6 | ||
|
|
8f77df4ebb | ||
|
|
65a8b3fcd4 | ||
|
|
71dd4e512e | ||
|
|
ca03a5ecf4 | ||
|
|
694efb9508 | ||
|
|
c60a112039 | ||
|
|
c3570dd07a | ||
|
|
b680b190d4 | ||
|
|
310d51d859 | ||
|
|
cf9e820227 | ||
|
|
b91d2f4fb1 | ||
|
|
9456f5dc31 | ||
|
|
fa9e22730a | ||
|
|
7261fd7ed9 | ||
|
|
ad9e5fbf07 | ||
|
|
c242117230 | ||
|
|
d7c1b23fa2 | ||
|
|
25e9919bb3 | ||
|
|
912c01457a | ||
|
|
8083390eab | ||
|
|
44baa4cc1e | ||
|
|
f0662bb878 | ||
|
|
fbe1a6d4c5 | ||
|
|
2235f1f7af | ||
|
|
3f46f83ec8 | ||
|
|
d537d4a27e | ||
|
|
c67250da2d | ||
|
|
6027406eef | ||
|
|
fdc51f33ad | ||
|
|
ea7290afab | ||
|
|
be65597d57 | ||
|
|
253ed75800 | ||
|
|
e4f3671ae0 | ||
|
|
c60cefd188 | ||
|
|
175a41f275 | ||
|
|
bd5fd72459 | ||
|
|
98b70a647b | ||
|
|
3eee5e696d | ||
|
|
d92c6cc6c6 | ||
|
|
488485da54 | ||
|
|
a3f0254fb2 | ||
|
|
ab5f1385c5 | ||
|
|
cde5b09943 | ||
|
|
db42b6a3a5 | ||
|
|
ece35b96db | ||
|
|
c4c24ee240 | ||
|
|
c7ba465970 | ||
|
|
937ad444da | ||
|
|
0c0a928e87 | ||
|
|
2823a86b4e | ||
|
|
1a06683611 | ||
|
|
50fa74adfe | ||
|
|
4ebd249356 | ||
|
|
4dc388015c | ||
|
|
0270cf6e45 | ||
|
|
7a19c50ec0 | ||
|
|
e2fc5fff23 | ||
|
|
839df123ff | ||
|
|
f897193f79 | ||
|
|
9f23f4ead7 | ||
|
|
45ab6d47de | ||
|
|
35bc94f4bd | ||
|
|
94a4a38798 | ||
|
|
7f431dbd01 | ||
|
|
d0257df134 | ||
|
|
be3ed16d3c | ||
|
|
b651becf66 | ||
|
|
bcf49ab396 | ||
|
|
fb76ecf198 | ||
|
|
1bed49b4c6 | ||
|
|
c34376820a | ||
|
|
582e6ee322 | ||
|
|
2b4ffaa357 | ||
|
|
379a82972a | ||
|
|
713796a4f7 | ||
|
|
54161aaf39 | ||
|
|
4054519f38 | ||
|
|
e5d5d8b434 | ||
|
|
519fd212d9 | ||
|
|
4b21660fd6 | ||
|
|
ac5c9e7242 | ||
|
|
4c8431bd5b | ||
|
|
a4a93f0999 | ||
|
|
b6a4efa7ba | ||
|
|
a4fbd521e3 | ||
|
|
6fe5e89ecc | ||
|
|
bc40c95f20 | ||
|
|
acd35ac8a2 | ||
|
|
c9d9ec1c77 | ||
|
|
08c4e2d465 | ||
|
|
f300d1bafd | ||
|
|
d395115cc9 | ||
|
|
8571755daa | ||
|
|
9f3368ba1f | ||
|
|
919df1edd5 | ||
|
|
c180422e8b | ||
|
|
e90501a986 | ||
|
|
545af007b4 | ||
|
|
e189ece487 | ||
|
|
cebc2b5bdb | ||
|
|
444d48a259 | ||
|
|
4fd70ad252 | ||
|
|
293326b647 | ||
|
|
b071238eda | ||
|
|
09ef1b66cc | ||
|
|
c06df3889b | ||
|
|
280fc78f7e | ||
|
|
7b9fc04704 | ||
|
|
00e60f2592 | ||
|
|
45e9c762a7 | ||
|
|
77dcb91741 | ||
|
|
383c683716 | ||
|
|
ca3c380493 | ||
|
|
57ec5cb036 | ||
|
|
177b48ac90 | ||
|
|
b4e7fd6fa8 | ||
|
|
baf785d9f1 | ||
|
|
25b75fd6e4 | ||
|
|
0c4c8534b4 | ||
|
|
a559dbfe06 | ||
|
|
de20bb22d9 | ||
|
|
45c0ec9035 | ||
|
|
b16da90e42 | ||
|
|
ce7bcfa666 | ||
|
|
f6833699a6 | ||
|
|
040dc72877 | ||
|
|
056bce3dd9 | ||
|
|
5d6575e97b | ||
|
|
f092d4ffc3 | ||
|
|
5bae15831b | ||
|
|
cf19bd88f0 | ||
|
|
38ac6a1082 | ||
|
|
b88e2bd3ce | ||
|
|
fad24c4308 | ||
|
|
018fd83dba | ||
|
|
aa95da167f | ||
|
|
24e6a0be68 | ||
|
|
a2c962c2f6 | ||
|
|
aa61331181 | ||
|
|
00f0a7589c | ||
|
|
d39609351a | ||
|
|
6985ccf076 | ||
|
|
b448cad4de | ||
|
|
14540b4cc0 | ||
|
|
898b76a549 | ||
|
|
5cf6e382d8 | ||
|
|
e2ba56a227 | ||
|
|
ec9960e28e | ||
|
|
dc59283160 | ||
|
|
d255d44be5 | ||
|
|
b2f68a5a7e | ||
|
|
ec32679ab1 | ||
|
|
8b2471c128 | ||
|
|
022eba2c05 | ||
|
|
029c6fcfe3 | ||
|
|
faaa0b2488 | ||
|
|
daa2ca876b | ||
|
|
81700cfb44 | ||
|
|
6e58db95ed | ||
|
|
9b54862450 | ||
|
|
f79efadd82 | ||
|
|
615a7670bd | ||
|
|
155b8b472f | ||
|
|
b35e3454f0 | ||
|
|
51b4716d45 | ||
|
|
b62803a03a | ||
|
|
616893955f | ||
|
|
0f387a139b | ||
|
|
219c81aac5 | ||
|
|
083003d34f | ||
|
|
699f76c29e | ||
|
|
b670280688 | ||
|
|
37ea84ffe9 | ||
|
|
40b861acbe | ||
|
|
783c4d104c | ||
|
|
9bbddd6aeb | ||
|
|
e753acbc3f | ||
|
|
92b7b1d603 | ||
|
|
b07dc8443e | ||
|
|
3f99c513f3 | ||
|
|
793241523d | ||
|
|
7cff22fb9e | ||
|
|
214f308027 | ||
|
|
c1ce971adb | ||
|
|
f5896be699 | ||
|
|
186f839569 | ||
|
|
4879d906d9 | ||
|
|
09412f0b78 | ||
|
|
2f2d85576f | ||
|
|
362ddd0339 | ||
|
|
9499b7f562 | ||
|
|
d8bb12b5f1 | ||
|
|
5d464f4477 | ||
|
|
aaea0b2659 | ||
|
|
c9ceb09906 | ||
|
|
3b44ede67e | ||
|
|
b48e8eeb0e | ||
|
|
1fafc29ec3 | ||
|
|
1a9d0576c8 | ||
|
|
bc04211b79 | ||
|
|
cfe34355bd | ||
|
|
e3e833d8c0 | ||
|
|
5606a0a968 | ||
|
|
f0358f1da8 | ||
|
|
a3129e9e17 | ||
|
|
7435ede254 | ||
|
|
84e79e92b4 | ||
|
|
6268130998 | ||
|
|
7ad639599a | ||
|
|
caff67b77d | ||
|
|
c45a77d538 | ||
|
|
4b24fe1bf4 | ||
|
|
73e5fb6314 | ||
|
|
84ea28adfa | ||
|
|
955fc97cb2 | ||
|
|
e4012e4f87 | ||
|
|
2c662c428c | ||
|
|
da199deed1 | ||
|
|
abf75cffd9 | ||
|
|
184f13b148 | ||
|
|
d1c7309b29 | ||
|
|
62db6552d2 | ||
|
|
a019b9e1d3 | ||
|
|
cb22572f2b | ||
|
|
b52134e9ee | ||
|
|
44ef82219b | ||
|
|
8c89b0e587 | ||
|
|
322b251def | ||
|
|
0a6767209d | ||
|
|
1694b5d6fd | ||
|
|
0dd9ad43e8 | ||
|
|
c1ae3f1fb2 | ||
|
|
d84627aa2c | ||
|
|
0e020924ff | ||
|
|
4f5e238685 | ||
|
|
72ff680114 | ||
|
|
849ec6fa8f | ||
|
|
36ee3aaec6 | ||
|
|
497d4f50dd | ||
|
|
74a40b2274 | ||
|
|
75e85541a6 | ||
|
|
1d8fbac796 | ||
|
|
daf6d1936f | ||
|
|
1768e8cb62 | ||
|
|
d2d6bfc065 | ||
|
|
d4f6e9c587 | ||
|
|
6d06f2212e | ||
|
|
73b310d59e | ||
|
|
3dc705a7a9 | ||
|
|
8fc8d03cc4 | ||
|
|
df77f42145 | ||
|
|
0dea5bdbea | ||
|
|
5c7f939440 | ||
|
|
09bef28362 | ||
|
|
1f0f94746b | ||
|
|
c057be17d0 | ||
|
|
301aaf9c68 | ||
|
|
ab7093f962 | ||
|
|
29b2d67fb6 | ||
|
|
d4cd2b8be8 | ||
|
|
fea94f956d | ||
|
|
a656aa21f8 | ||
|
|
3b235f2ca2 | ||
|
|
376841f619 | ||
|
|
746a7c404b | ||
|
|
2d126300d8 | ||
|
|
ed7e43ed6e | ||
|
|
7c56f1a773 | ||
|
|
6ba396440f | ||
|
|
8970525861 | ||
|
|
5a88a66709 | ||
|
|
3ae6e3ee53 | ||
|
|
5c0d4700f9 | ||
|
|
7b354f5b8c | ||
|
|
a197c0219e | ||
|
|
05f4036309 | ||
|
|
37974c7ec8 | ||
|
|
5cb3e15201 | ||
|
|
54b4766680 | ||
|
|
cc0bb65096 | ||
|
|
296c9dc055 | ||
|
|
70aa2309b7 | ||
|
|
d2468d144e | ||
|
|
ebbe704672 | ||
|
|
d146870a74 | ||
|
|
58ebabf74c | ||
|
|
8f8a3b6387 | ||
|
|
df616cfe3e | ||
|
|
dd96608bb1 | ||
|
|
264f2ab316 | ||
|
|
773f156785 | ||
|
|
7cd3e2a5b9 | ||
|
|
0ec22a4639 | ||
|
|
74ac9cbbbe | ||
|
|
0020bd0fb7 | ||
|
|
1d6ec0f953 | ||
|
|
37f05f0a12 | ||
|
|
9a22a1dbf4 | ||
|
|
b768c8b28a | ||
|
|
bcbdbb4932 | ||
|
|
04e42c4a75 | ||
|
|
6040c7768f | ||
|
|
6da0d3e88d | ||
|
|
7c6cc7b246 | ||
|
|
d5da1d6f3f | ||
|
|
de5ee90e21 | ||
|
|
8a0c9ab3db | ||
|
|
e901a1f231 | ||
|
|
e4c47aca9e | ||
|
|
a43a3db098 | ||
|
|
d651606800 | ||
|
|
5501ab9083 | ||
|
|
660a21deb1 | ||
|
|
be7949b909 | ||
|
|
a688656f6d | ||
|
|
62365529cc | ||
|
|
dcea869098 | ||
|
|
634a8702cd | ||
|
|
fee993c309 | ||
|
|
bf76707e92 | ||
|
|
da847f6567 | ||
|
|
7a5d25f2e3 | ||
|
|
bf0dedd447 | ||
|
|
3f7dcc6acf | ||
|
|
2efe8b4186 | ||
|
|
068f5771b2 | ||
|
|
c2b1be288e | ||
|
|
163ad248af | ||
|
|
4598c3d852 | ||
|
|
a1dec131c7 | ||
|
|
133585f46a | ||
|
|
3ea81ce2fb | ||
|
|
590fe211c4 | ||
|
|
78cda03d61 | ||
|
|
e126cbf644 | ||
|
|
cc12ae7712 | ||
|
|
e8486abccf | ||
|
|
15f074a45b | ||
|
|
a426d98e92 | ||
|
|
45d171e0e3 | ||
|
|
5950c33a43 | ||
|
|
ea1b584436 | ||
|
|
a24ede364d | ||
|
|
c6fe456cac | ||
|
|
4008fb3a53 | ||
|
|
96588089ef | ||
|
|
e4c96dc6d8 | ||
|
|
c205e0da1b | ||
|
|
7b61605834 | ||
|
|
e7fb05d7e0 | ||
|
|
8f0680f5fc | ||
|
|
9c03dd001c | ||
|
|
30407f5b4e | ||
|
|
3a5378d201 | ||
|
|
d4f3577f5e | ||
|
|
408e9bf3fc | ||
|
|
f5dd91afe5 | ||
|
|
8922459418 | ||
|
|
caeadbc41e | ||
|
|
99143c0e3b | ||
|
|
1b145e38a3 | ||
|
|
f59cce15c0 | ||
|
|
7655c251a2 | ||
|
|
5608cb542f | ||
|
|
62add53c08 | ||
|
|
43bae6c05b | ||
|
|
55777d33ad | ||
|
|
0f5d14b589 | ||
|
|
00703d1570 | ||
|
|
fd03c33f4d | ||
|
|
c20f91b6d8 | ||
|
|
10b22e9e42 | ||
|
|
329f0871d5 | ||
|
|
66996f491c | ||
|
|
9ae39f3900 | ||
|
|
9d0db3c1e5 | ||
|
|
5932dd99ad | ||
|
|
910f0083cd | ||
|
|
32a8676572 | ||
|
|
801829ccbf | ||
|
|
b5107d21dd | ||
|
|
158bf873bd | ||
|
|
40cfb9876d | ||
|
|
12e3214f70 | ||
|
|
0eb68ec461 | ||
|
|
f231565163 | ||
|
|
7cca53bcc5 | ||
|
|
be94c94309 | ||
|
|
8e2d654b40 | ||
|
|
2ed5c0c5cc | ||
|
|
745ad3b9e9 | ||
|
|
3ce114760f | ||
|
|
bae7d1fc1d | ||
|
|
e4d9dfc128 | ||
|
|
7490ba3179 | ||
|
|
45da12ad55 | ||
|
|
75f99bf899 | ||
|
|
bd2b1cc166 | ||
|
|
5fa8d64994 | ||
|
|
034957b556 | ||
|
|
a9d7c73b04 | ||
|
|
b09fe05fe6 | ||
|
|
ed146549ef | ||
|
|
86c11db1a1 | ||
|
|
580cd57433 | ||
|
|
9854ce82bd | ||
|
|
af11df97f5 | ||
|
|
9b4e664908 | ||
|
|
567e1ee116 | ||
|
|
ef7fa5363a | ||
|
|
f8bd7c2e64 | ||
|
|
de46c9ee36 | ||
|
|
5969e2d7ed | ||
|
|
83047558d5 | ||
|
|
f239868299 | ||
|
|
e4b962a3a6 | ||
|
|
b68a94c0e5 | ||
|
|
ec53ca8423 | ||
|
|
1ba0729e34 | ||
|
|
73425c0052 | ||
|
|
679859fb37 | ||
|
|
dbdc660464 | ||
|
|
aa22e7e952 | ||
|
|
b920e7e95c | ||
|
|
d14b23ca82 | ||
|
|
4e8f69f692 | ||
|
|
c96cf2b0e5 | ||
|
|
4921cfb593 | ||
|
|
395545f7b1 | ||
|
|
f9d336a3a6 | ||
|
|
b32603b472 | ||
|
|
1124c48c8d | ||
|
|
98e429505c | ||
|
|
d0b616ba24 | ||
|
|
dac4ffcb98 | ||
|
|
680310cf70 | ||
|
|
67ff82810f | ||
|
|
87e71ea860 | ||
|
|
26c110291e | ||
|
|
9879f074b4 | ||
|
|
65168c71c0 | ||
|
|
4c4996ee2a | ||
|
|
e0c67f87b0 | ||
|
|
352c8ee867 | ||
|
|
fe5cc1f8f3 | ||
|
|
eec4be1845 | ||
|
|
2f86b5c7b0 | ||
|
|
0d672c4f99 | ||
|
|
ac3fdbc2cd | ||
|
|
0a7ad44d23 | ||
|
|
18a86d3f12 | ||
|
|
665e66a9a6 | ||
|
|
06dc4117c7 | ||
|
|
2651afcef0 | ||
|
|
ce4d828380 | ||
|
|
74fba486bd | ||
|
|
56075cb7d9 | ||
|
|
d71bc775d5 | ||
|
|
45c5801538 | ||
|
|
cf41b524b0 | ||
|
|
e2a3e55a17 | ||
|
|
ae35bd2047 | ||
|
|
2f0ca6f7c0 | ||
|
|
37428c01dd | ||
|
|
4116d95a3e | ||
|
|
35ae2b783f | ||
|
|
8a24a6d192 | ||
|
|
19374a5df4 | ||
|
|
12da6fbd18 | ||
|
|
573ff15925 | ||
|
|
1b2abbe321 | ||
|
|
4a03da6b96 | ||
|
|
cf3998942f | ||
|
|
0c71f783fc | ||
|
|
d30b30b24f | ||
|
|
7823ec3fc8 | ||
|
|
1e5883f028 | ||
|
|
33c3cf4c4f | ||
|
|
f41ace4d7c | ||
|
|
65d2d45a82 | ||
|
|
47ca483459 | ||
|
|
ee759af078 | ||
|
|
872037cf4d | ||
|
|
6aaa083157 | ||
|
|
6a88524f8e | ||
|
|
82d93d2602 | ||
|
|
d62037ef6a | ||
|
|
7314b5a339 | ||
|
|
62bc230521 | ||
|
|
3e0d34d148 | ||
|
|
aff1cc1cc3 | ||
|
|
6ddc7fa4cc | ||
|
|
957db1ec11 | ||
|
|
ae806da3f1 | ||
|
|
6a03c3e77d | ||
|
|
72b18eadf3 | ||
|
|
67aa583709 | ||
|
|
21f3755e44 | ||
|
|
c9b6df846e | ||
|
|
7e23a8169f | ||
|
|
b139eadf0b | ||
|
|
71ad648331 | ||
|
|
b8c7752356 | ||
|
|
b157f2085f | ||
|
|
2fda7b8011 | ||
|
|
5b24d19630 | ||
|
|
76652f6c6b | ||
|
|
724ae51110 | ||
|
|
1503124108 | ||
|
|
007125a071 | ||
|
|
b5f5b0b4aa | ||
|
|
cbda59e547 | ||
|
|
a885e16049 | ||
|
|
07eabad18d | ||
|
|
cf079a159f | ||
|
|
93176989fd | ||
|
|
7a56141894 | ||
|
|
31cc0ff6e9 | ||
|
|
8719b3eb64 | ||
|
|
5347624455 | ||
|
|
25210339d9 | ||
|
|
72c7cd2536 | ||
|
|
d018eeb376 | ||
|
|
d1424276bc | ||
|
|
cf9696a8cf | ||
|
|
a7cbe526e3 | ||
|
|
fe1c58ad27 | ||
|
|
753d01d413 | ||
|
|
feacb3ed14 | ||
|
|
f5b1e6d03a | ||
|
|
46fc2dd8d0 | ||
|
|
b063aae130 | ||
|
|
655a729143 | ||
|
|
5d2138b95e | ||
|
|
0b24cc29c1 | ||
|
|
2fa7b532b1 | ||
|
|
aa1ed52f64 | ||
|
|
29dddd7d62 | ||
|
|
6ddbea316a | ||
|
|
8da80f0710 | ||
|
|
24382b8607 | ||
|
|
65438e837d | ||
|
|
1a3cb8b623 | ||
|
|
6bf4a0d09d | ||
|
|
9ae734672b | ||
|
|
cfa84476c8 | ||
|
|
5b0d160df4 | ||
|
|
41f858eb04 | ||
|
|
c5753b898a | ||
|
|
c6810409c7 | ||
|
|
f6c16ec53d | ||
|
|
84a6ee8cbf | ||
|
|
e651a13980 | ||
|
|
f494570725 | ||
|
|
5955ca74d2 | ||
|
|
eb4fa8620d | ||
|
|
34fe7dd6d1 | ||
|
|
4cbb3cb43c | ||
|
|
050acdf580 | ||
|
|
358da4051e | ||
|
|
ffb51c1515 | ||
|
|
72d4952812 | ||
|
|
04bf86c21d | ||
|
|
d392dc82a1 | ||
|
|
f7f4289614 | ||
|
|
72f9951cb1 | ||
|
|
8450f56093 | ||
|
|
cb2a25ad46 | ||
|
|
a028172cf6 | ||
|
|
91aa48ac9a | ||
|
|
218320749f | ||
|
|
6a1ff56e7b | ||
|
|
8f7c4951b8 | ||
|
|
6215a7d65e | ||
|
|
0e28b1ffe1 | ||
|
|
7dd435d677 | ||
|
|
7fd5209cdb | ||
|
|
ed5b6962d7 | ||
|
|
98718c0693 | ||
|
|
f02588855a | ||
|
|
c63841fdee | ||
|
|
b49b4601cd | ||
|
|
ed352d2d21 | ||
|
|
dab56121a2 | ||
|
|
df02afaed9 | ||
|
|
e6fe121c1e | ||
|
|
b37fbc1284 | ||
|
|
f5ac554022 | ||
|
|
df76c82449 | ||
|
|
8f1f978800 | ||
|
|
bf3cc6690c | ||
|
|
20ba7eaaf3 | ||
|
|
95708cd5ab | ||
|
|
fba58bba71 | ||
|
|
bc6ff3e3bc | ||
|
|
3415be4c56 | ||
|
|
05d6f5d806 | ||
|
|
ed8266bb43 | ||
|
|
759f35ff9c | ||
|
|
bcac8f1599 | ||
|
|
0abf054825 | ||
|
|
825b76e28e | ||
|
|
0a13ac142e | ||
|
|
566e6634a6 | ||
|
|
4b888e6911 | ||
|
|
0cfc89f574 | ||
|
|
337382b7e6 | ||
|
|
4ed657c930 | ||
|
|
5895b37965 | ||
|
|
6979b8e11e | ||
|
|
20713cf158 | ||
|
|
13ff0846b1 | ||
|
|
e92d091cb3 | ||
|
|
6b1a435cdc | ||
|
|
3f04b465f3 | ||
|
|
3f5c8fe2cb | ||
|
|
d1cf6c68f3 | ||
|
|
7117f00480 | ||
|
|
d4f37343a2 | ||
|
|
71e15e9cab | ||
|
|
eadf00feba | ||
|
|
95f28fad2b | ||
|
|
9753137a72 | ||
|
|
e4f7436dfb | ||
|
|
d39211310d | ||
|
|
0a6fb3ec0a | ||
|
|
5232cf7cec | ||
|
|
6e16ffe05f | ||
|
|
2d6895aeea | ||
|
|
b5311e1448 | ||
|
|
cc63eb383d | ||
|
|
01736ca685 | ||
|
|
be47bb7263 | ||
|
|
bcb7d88ed7 | ||
|
|
cf58c1b4b5 | ||
|
|
70c57928e7 | ||
|
|
c8219b29c0 | ||
|
|
15a9f80430 | ||
|
|
0684dfe869 | ||
|
|
83a89566ac | ||
|
|
04f486b003 | ||
|
|
f135c92434 | ||
|
|
78b095d01a | ||
|
|
1b8bd494e2 | ||
|
|
481925ac78 | ||
|
|
4854b2b1c0 | ||
|
|
2d7b33459e | ||
|
|
27e0c7421b | ||
|
|
b26c3d050c | ||
|
|
439370e25a | ||
|
|
1be4f6e20c | ||
|
|
2714c7cce9 | ||
|
|
952935de23 | ||
|
|
bdb8b5ea39 | ||
|
|
3ad4e28a2c | ||
|
|
48d0d068d1 | ||
|
|
56e166d61a | ||
|
|
672d753adf | ||
|
|
0d9ba92db4 | ||
|
|
8cf25d3602 | ||
|
|
a6bc44dc10 | ||
|
|
408d66ee74 | ||
|
|
b136bb74b8 | ||
|
|
18b2b6f447 | ||
|
|
490d1775a2 | ||
|
|
458de2d2e0 | ||
|
|
51ae3fc62f | ||
|
|
58c5c55d09 | ||
|
|
4c2bcb9e6b | ||
|
|
498379bb7e | ||
|
|
e7f3b115a4 | ||
|
|
0ebfe85d8e | ||
|
|
8e29a990cb | ||
|
|
a960ccd786 | ||
|
|
6b86e836d7 | ||
|
|
fb35b9b10a | ||
|
|
a45773e1ca | ||
|
|
2405a6f21e | ||
|
|
533dd6135e | ||
|
|
efc25543ca | ||
|
|
82d4745da3 | ||
|
|
ac6e95c442 | ||
|
|
375f23ac9e | ||
|
|
8e5a01d82c | ||
|
|
910658aa93 | ||
|
|
d766ffa040 | ||
|
|
b960640e03 | ||
|
|
c984617b1c | ||
|
|
a12a7127c0 | ||
|
|
98a6a5c93d | ||
|
|
27202fd740 | ||
|
|
c01d02de27 | ||
|
|
1d23bcc979 | ||
|
|
ac8abdaa17 | ||
|
|
613977c6f9 | ||
|
|
54159c9d05 | ||
|
|
8d5d477b4a | ||
|
|
2c73906ad3 | ||
|
|
079fb34120 | ||
|
|
17ed1cdc00 | ||
|
|
d53ea584ba | ||
|
|
b435256911 | ||
|
|
27e996dba0 | ||
|
|
22f3bd1073 | ||
|
|
fb564fa817 | ||
|
|
be9db2930f | ||
|
|
5bce95a686 | ||
|
|
f6ca9b9d0f | ||
|
|
88f186907b | ||
|
|
9faf1d9de5 | ||
|
|
8b1d1d0f6d | ||
|
|
8c19e2c3f2 | ||
|
|
d2d8ee504d | ||
|
|
d96b279beb | ||
|
|
f5e7f9249c | ||
|
|
56c33ee82b | ||
|
|
b05dd4cc2c | ||
|
|
36d4ce8718 | ||
|
|
ddec7ab643 | ||
|
|
75201c9b30 | ||
|
|
99c81e5a5d | ||
|
|
b84ad39133 | ||
|
|
4a19e2b673 | ||
|
|
475c3559f6 | ||
|
|
58246f72dd | ||
|
|
b90ce2a2af | ||
|
|
4a0fc5ca0e | ||
|
|
c29d902b8e | ||
|
|
ab629c2048 | ||
|
|
e970ca49e8 | ||
|
|
99e78092ed | ||
|
|
4af91b5ab6 | ||
|
|
539121070a | ||
|
|
2a1bd92e1a | ||
|
|
2c1ebc0439 | ||
|
|
2d605f5dfb | ||
|
|
0cd09cf03a | ||
|
|
3ad1e8a3ba | ||
|
|
230722945e | ||
|
|
a429dcf978 | ||
|
|
0131031ac4 | ||
|
|
a418fc810a | ||
|
|
e71adbd26d | ||
|
|
8a525aee8a | ||
|
|
463b0fa28a | ||
|
|
007ebadf16 | ||
|
|
c7af81bf0c | ||
|
|
749508871b | ||
|
|
d112e0ea42 | ||
|
|
54f8771a9c | ||
|
|
0a3c83288e | ||
|
|
52a866147e | ||
|
|
6629eaf485 | ||
|
|
74239521cd | ||
|
|
8ae95c4e30 | ||
|
|
c31e191d7e | ||
|
|
c3134f779d | ||
|
|
d4749c139b | ||
|
|
63d6c32063 | ||
|
|
08299902e3 | ||
|
|
db04d6e642 | ||
|
|
6ddbd77009 | ||
|
|
4a4779fc63 | ||
|
|
46bb8d2cb5 | ||
|
|
31b2eeb293 | ||
|
|
8e9becd579 | ||
|
|
d067de086d | ||
|
|
8c6d395d89 | ||
|
|
f66b26a866 | ||
|
|
83f00d69ce | ||
|
|
8b2923b56d | ||
|
|
46af313c25 | ||
|
|
85dda759ec | ||
|
|
27fb44277f | ||
|
|
ea1aafbab2 | ||
|
|
2c446f939e | ||
|
|
47e427a851 | ||
|
|
95b8efae20 | ||
|
|
53774735d4 | ||
|
|
36c6c5a35e | ||
|
|
0beb07c87e | ||
|
|
64fd8e3be9 | ||
|
|
45c516ea3f | ||
|
|
26667c0a59 | ||
|
|
61e0379eb3 | ||
|
|
759df9bdd5 | ||
|
|
33e7ca08d8 | ||
|
|
c3d0d8bf63 | ||
|
|
8387f1e204 | ||
|
|
fe778293c1 | ||
|
|
991afb7722 | ||
|
|
a176542114 | ||
|
|
a3f555e816 | ||
|
|
dae5453e13 | ||
|
|
082826287e | ||
|
|
7418691cf3 | ||
|
|
29e72de64b | ||
|
|
4955b4a4a8 | ||
|
|
7c76595314 | ||
|
|
1495003103 | ||
|
|
fc1b74d48f | ||
|
|
830d0e9e7a | ||
|
|
7310c06162 | ||
|
|
045ccaa219 | ||
|
|
9d6a276342 | ||
|
|
9204d25b62 | ||
|
|
6c847292c7 | ||
|
|
b2712119d1 | ||
|
|
7728046309 | ||
|
|
17e18a2a7a | ||
|
|
ce8bedb340 | ||
|
|
14dc42e148 | ||
|
|
442c2294e9 | ||
|
|
5334514d55 | ||
|
|
0d5b431e6a | ||
|
|
8b10ee0028 | ||
|
|
9682abdded | ||
|
|
62cef0d141 | ||
|
|
548132ce7e | ||
|
|
4c19450f04 | ||
|
|
b4ee44ca00 | ||
|
|
f2db2ae474 | ||
|
|
f211b3a4da | ||
|
|
936f65ecc9 | ||
|
|
83985965f2 | ||
|
|
7bc38a35e8 | ||
|
|
9879f7fa0a | ||
|
|
7c856d08c4 | ||
|
|
6c554b4d51 | ||
|
|
187bc83db9 | ||
|
|
9a08379a5b | ||
|
|
e807d61bd7 | ||
|
|
f3724d6314 | ||
|
|
be8e393c13 | ||
|
|
0357f1461e | ||
|
|
8f99d80ac1 | ||
|
|
2c05b3b89f | ||
|
|
07bec16539 | ||
|
|
9938fdd4a2 | ||
|
|
320d2c5c96 | ||
|
|
6860cca9bb | ||
|
|
8e98eb439c | ||
|
|
29c4b8e6ee | ||
|
|
d8559a81f4 | ||
|
|
8322e49305 | ||
|
|
c0b6bf9f89 | ||
|
|
620d421a4b | ||
|
|
071ec61683 | ||
|
|
c0a532a0fe | ||
|
|
feb484dc9f | ||
|
|
4b819bbcc4 | ||
|
|
0257c5b30d | ||
|
|
3b1bb02e41 | ||
|
|
229dc03b23 | ||
|
|
2e883c2050 | ||
|
|
65abb1dfaa | ||
|
|
c72b551e80 | ||
|
|
9718e5aace | ||
|
|
db6ceea711 | ||
|
|
4a0e3227fc | ||
|
|
428e35237f | ||
|
|
74972336c6 | ||
|
|
fc1b825f46 | ||
|
|
8f1a8e3ce9 | ||
|
|
4efec0b266 | ||
|
|
9c0c819dce | ||
|
|
bb37372be0 | ||
|
|
fe8240c47a | ||
|
|
0b5def0f39 | ||
|
|
b60be97b1f | ||
|
|
23274ef914 | ||
|
|
713fdaeac1 | ||
|
|
2a44937d09 | ||
|
|
4751cc04fc | ||
|
|
5daeb0ee95 | ||
|
|
1bcfd57193 | ||
|
|
dbd697a473 |
112
.editorconfig
Normal file
112
.editorconfig
Normal file
@@ -0,0 +1,112 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Don't use tabs for indentation.
|
||||
[*]
|
||||
indent_style = space
|
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.)
|
||||
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
charset = utf-8-bom
|
||||
|
||||
# Xml project files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
|
||||
# Xml config files
|
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
# Dotnet code style settings:
|
||||
[*.{cs,vb}]
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
# Avoid "this." and "Me." if not necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# Use language keywords instead of framework type names for type references
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
# Suggest more modern language features when available
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
|
||||
# Prefix private members with underscore
|
||||
dotnet_naming_rule.private_members_with_underscore.symbols = private_members
|
||||
dotnet_naming_rule.private_members_with_underscore.style = underscore_prefix
|
||||
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
|
||||
|
||||
dotnet_naming_symbols.private_members.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_members.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_members.required_modifiers = readonly
|
||||
|
||||
dotnet_naming_style.underscore_prefix.capitalization = camel_case
|
||||
dotnet_naming_style.underscore_prefix.required_prefix = _
|
||||
dotnet_naming_style.underscore_prefix.required_suffix =
|
||||
dotnet_naming_style.underscore_prefix.word_separator =
|
||||
|
||||
# Async methods should have "Async" suffix
|
||||
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods
|
||||
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async
|
||||
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion
|
||||
|
||||
dotnet_naming_symbols.any_async_methods.applicable_kinds = method
|
||||
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = *
|
||||
dotnet_naming_symbols.any_async_methods.required_modifiers = async
|
||||
|
||||
dotnet_naming_style.end_in_async.required_prefix =
|
||||
dotnet_naming_style.end_in_async.required_suffix = Async
|
||||
dotnet_naming_style.end_in_async.capitalization = pascal_case
|
||||
dotnet_naming_style.end_in_async.word_separator =
|
||||
|
||||
# CSharp code style settings:
|
||||
[*.cs]
|
||||
# Prefer "var" everywhere
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
|
||||
# Prefer method-like constructs to have a expression-body
|
||||
csharp_style_expression_bodied_methods = true:none
|
||||
csharp_style_expression_bodied_constructors = true:none
|
||||
csharp_style_expression_bodied_operators = true:none
|
||||
|
||||
# Prefer property-like constructs to have an expression-body
|
||||
csharp_style_expression_bodied_properties = true:none
|
||||
csharp_style_expression_bodied_indexers = true:none
|
||||
csharp_style_expression_bodied_accessors = true:none
|
||||
|
||||
# Suggest more modern language features when available
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
|
||||
# All files
|
||||
[*]
|
||||
guidelines = 120
|
||||
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
17
.github/resources/export-options-ad-hoc.plist
vendored
Normal file
17
.github/resources/export-options-ad-hoc.plist
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
<string>ad-hoc</string>
|
||||
<key>provisioningProfiles</key>
|
||||
<dict>
|
||||
<key>com.8bit.bitwarden</key>
|
||||
<string>Ad hoc: Bitwarden 2021</string>
|
||||
<key>com.8bit.bitwarden.autofill</key>
|
||||
<string>Ad hoc: Autofill 2021</string>
|
||||
<key>com.8bit.bitwarden.find-login-action-extension</key>
|
||||
<string>Ad hoc: Extension 2021</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
17
.github/resources/export-options-app-store.plist
vendored
Normal file
17
.github/resources/export-options-app-store.plist
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
<string>app-store</string>
|
||||
<key>provisioningProfiles</key>
|
||||
<dict>
|
||||
<key>com.8bit.bitwarden</key>
|
||||
<string>Dist: Bitwarden 2021</string>
|
||||
<key>com.8bit.bitwarden.autofill</key>
|
||||
<string>Dist: Autofill 2021</string>
|
||||
<key>com.8bit.bitwarden.find-login-action-extension</key>
|
||||
<string>Dist: Extension 2021</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
13
.github/scripts/android/build.ps1
vendored
Normal file
13
.github/scripts/android/build.ps1
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $configuration
|
||||
)
|
||||
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$androidPath = $($rootPath + "/src/Android/Android.csproj");
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Build $configuration Configuration"
|
||||
Write-Output "########################################"
|
||||
|
||||
msbuild "$($androidPath)" "/p:Configuration=$configuration"
|
||||
69
.github/scripts/android/clean-fdroid.ps1
vendored
Normal file
69
.github/scripts/android/clean-fdroid.ps1
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
|
||||
$androidPath = $($rootPath + "/src/Android/Android.csproj");
|
||||
$appPath = $($rootPath + "/src/App/App.csproj");
|
||||
|
||||
$androidManifest = $($rootPath + "/src/Android/Properties/AndroidManifest.xml");
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Clean Android and App"
|
||||
Write-Output "########################################"
|
||||
|
||||
msbuild "$($androidPath)" "/t:Clean" "/p:Configuration=FDroid"
|
||||
msbuild "$($appPath)" "/t:Clean" "/p:Configuration=FDroid"
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Backup project files"
|
||||
Write-Output "########################################"
|
||||
|
||||
Copy-Item $androidManifest $($androidManifest + ".original");
|
||||
Copy-Item $androidPath $($androidPath + ".original");
|
||||
Copy-Item $appPath $($appPath + ".original");
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Cleanup Android Manifest"
|
||||
Write-Output "########################################"
|
||||
|
||||
$xml=New-Object XML;
|
||||
$xml.Load($androidManifest);
|
||||
|
||||
$nsAndroid=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
|
||||
$nsAndroid.AddNamespace("android", "http://schemas.android.com/apk/res/android");
|
||||
|
||||
$xml.Save($androidManifest);
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Uninstall from Android.csproj"
|
||||
Write-Output "########################################"
|
||||
|
||||
$xml=New-Object XML;
|
||||
$xml.Load($androidPath);
|
||||
|
||||
$ns=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
|
||||
$ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI);
|
||||
|
||||
$firebaseNode=$xml.SelectSingleNode(`
|
||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Firebase.Messaging']", $ns);
|
||||
$firebaseNode.ParentNode.RemoveChild($firebaseNode);
|
||||
|
||||
$daggerNode=$xml.SelectSingleNode(`
|
||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Google.Dagger']", $ns);
|
||||
$daggerNode.ParentNode.RemoveChild($daggerNode);
|
||||
|
||||
$safetyNetNode=$xml.SelectSingleNode(`
|
||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.GooglePlayServices.SafetyNet']", $ns);
|
||||
$safetyNetNode.ParentNode.RemoveChild($safetyNetNode);
|
||||
|
||||
$xml.Save($androidPath);
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Uninstall from App.csproj"
|
||||
Write-Output "########################################"
|
||||
|
||||
$xml=New-Object XML;
|
||||
$xml.Load($appPath);
|
||||
|
||||
$appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
|
||||
$appCenterNode.ParentNode.RemoveChild($appCenterNode);
|
||||
|
||||
$xml.Save($appPath);
|
||||
24
.github/scripts/android/compile-fdroid.sh
vendored
Normal file
24
.github/scripts/android/compile-fdroid.sh
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd $GITHUB_WORKSPACE
|
||||
mkdir dist
|
||||
cp CNAME ./dist
|
||||
cd store
|
||||
chmod 600 fdroid/config.py fdroid/keystore.jks
|
||||
mkdir -p temp/fdroid
|
||||
TEMP_DIR="$GITHUB_WORKSPACE/store/temp/fdroid"
|
||||
cd fdroid
|
||||
echo "keypass=\"$FDROID_STORE_KEYSTORE_PASSWORD\"" >>config.py
|
||||
echo "keystorepass=\"$FDROID_STORE_KEYSTORE_PASSWORD\"" >>config.py
|
||||
echo "local_copy_dir=\"$TEMP_DIR\"" >>config.py
|
||||
mkdir -p repo
|
||||
curl -Lo repo/com.x8bit.bitwarden-fdroid.apk \
|
||||
https://github.com/bitwarden/mobile/releases/download/$RELEASE_TAG_NAME/com.x8bit.bitwarden-fdroid.apk
|
||||
fdroid update
|
||||
fdroid server update
|
||||
cd ..
|
||||
rm -rf temp/fdroid/archive
|
||||
mv -v temp/fdroid ../dist
|
||||
cd fdroid
|
||||
cp index.html btn.png qr.png ../../dist/fdroid
|
||||
cd $GITHUB_WORKSPACE
|
||||
22
.github/scripts/android/decrypt-secrets.ps1
vendored
Normal file
22
.github/scripts/android/decrypt-secrets.ps1
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
|
||||
$decryptSecretPath = $($rootPath + "/.github/scripts/decrypt-secret.ps1");
|
||||
|
||||
$appKeystorePlayFilename = "app_play-keystore.jks";
|
||||
$appKeystorePlayPath = $($rootPath + "/src/Android/$appKeystorePlayFilename");
|
||||
$appKeystoreUploadFilename = "app_upload-keystore.jks";
|
||||
$appKeystoreUploadPath = $($rootPath + "/src/Android/$appKeystoreUploadFilename");
|
||||
$appKeystoreFdroidFilename = "app_fdroid-keystore.jks";
|
||||
$appKeystoreFdroidPath = $($rootPath + "/src/Android/$appKeystoreFdroidFilename");
|
||||
$googleServicesFilename = "google-services.json";
|
||||
$googleServicesPath = $($rootPath + "/src/Android/$googleServicesFilename");
|
||||
|
||||
Invoke-Expression `
|
||||
"& `"$decryptSecretPath`" -filename $($appKeystorePlayFilename + ".gpg") -output $($appKeystorePlayPath)"
|
||||
Invoke-Expression `
|
||||
"& `"$decryptSecretPath`" -filename $($appKeystoreUploadFilename + ".gpg") -output $($appKeystoreUploadPath)"
|
||||
Invoke-Expression `
|
||||
"& `"$decryptSecretPath`" -filename $($appKeystoreFdroidFilename + ".gpg") -output $($appKeystoreFdroidPath)"
|
||||
Invoke-Expression `
|
||||
"& `"$decryptSecretPath`" -filename $($googleServicesFilename + ".gpg") -output $($googleServicesPath)"
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename play_creds.json.gpg"
|
||||
9
.github/scripts/android/deploy-play.ps1
vendored
Normal file
9
.github/scripts/android/deploy-play.ps1
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$homePath = Resolve-Path "~" | Select-Object -ExpandProperty Path;
|
||||
|
||||
$publisherPath = $($rootPath + "/store/google/Publisher/bin/Release/netcoreapp2.0/Publisher.dll");
|
||||
$credsPath = $($homePath + "/secrets/play_creds.json");
|
||||
$aabPath = $($rootPath + "/com.x8bit.bitwarden.aab");
|
||||
$track = "internal";
|
||||
|
||||
dotnet $publisherPath $credsPath $aabPath $track
|
||||
16
.github/scripts/android/increment-version.ps1
vendored
Normal file
16
.github/scripts/android/increment-version.ps1
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$buildNumber = 3000 + [int]$env:GITHUB_RUN_NUMBER;
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Setting Version Code $buildNumber"
|
||||
Write-Output "########################################"
|
||||
|
||||
$androidManifest = $($rootPath + "/src/Android/Properties/AndroidManifest.xml");
|
||||
|
||||
$xml=New-Object XML;
|
||||
$xml.Load($androidManifest);
|
||||
|
||||
$node=$xml.SelectNodes("/manifest");
|
||||
$node.SetAttribute("android:versionCode", [string]$buildNumber);
|
||||
|
||||
$xml.Save($androidManifest);
|
||||
23
.github/scripts/android/sign-fdroid.ps1
vendored
Normal file
23
.github/scripts/android/sign-fdroid.ps1
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
|
||||
$androidPath = $($rootPath + "/src/Android/Android.csproj");
|
||||
|
||||
$appKeystoreFdroidFilename = "app_fdroid-keystore.jks";
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Sign FDroid Configuration"
|
||||
Write-Output "########################################"
|
||||
|
||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=FDroid" "/p:AndroidKeyStore=true" `
|
||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:FDROID_KEYSTORE_PASSWORD)" `
|
||||
"/p:AndroidSigningKeyStore=$($appKeystoreFdroidFilename)" `
|
||||
"/p:AndroidSigningStorePass=$($env:FDROID_KEYSTORE_PASSWORD)" "/v:quiet"
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Copy FDroid apk to project root"
|
||||
Write-Output "########################################"
|
||||
|
||||
$signedApkPath = $($rootPath + "/src/Android/bin/FDroid/com.x8bit.bitwarden-Signed.apk");
|
||||
$signedApkDestPath = $($rootPath + "/com.x8bit.bitwarden-fdroid.apk");
|
||||
|
||||
Copy-Item $signedApkPath $signedApkDestPath
|
||||
42
.github/scripts/android/sign-play.ps1
vendored
Normal file
42
.github/scripts/android/sign-play.ps1
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
|
||||
$androidPath = $($rootPath + "/src/Android/Android.csproj");
|
||||
|
||||
$appKeystorePlayFilename = "app_play-keystore.jks";
|
||||
$appKeystoreUploadFilename = "app_upload-keystore.jks";
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Sign Google Play Bundle Release Configuration"
|
||||
Write-Output "########################################"
|
||||
|
||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
||||
"/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:UPLOAD_KEYSTORE_PASSWORD)" `
|
||||
"/p:AndroidSigningKeyStore=$($appKeystoreUploadFilename)" `
|
||||
"/p:AndroidSigningStorePass=$($env:UPLOAD_KEYSTORE_PASSWORD)" "/p:AndroidPackageFormat=aab" "/v:quiet"
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Copy Google Play Bundle to project root"
|
||||
Write-Output "########################################"
|
||||
|
||||
$signedAabPath = $($rootPath + "/src/Android/bin/Release/com.x8bit.bitwarden-Signed.aab");
|
||||
$signedAabDestPath = $($rootPath + "/com.x8bit.bitwarden.aab");
|
||||
|
||||
Copy-Item $signedAabPath $signedAabDestPath
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Sign APK Release Configuration"
|
||||
Write-Output "########################################"
|
||||
|
||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:PLAY_KEYSTORE_PASSWORD)" `
|
||||
"/p:AndroidSigningKeyStore=$($appKeystorePlayFilename)" `
|
||||
"/p:AndroidSigningStorePass=$($env:PLAY_KEYSTORE_PASSWORD)" "/v:quiet"
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Copy Release APK to project root"
|
||||
Write-Output "########################################"
|
||||
|
||||
$signedApkPath = $($rootPath + "/src/Android/bin/Release/com.x8bit.bitwarden-Signed.apk");
|
||||
$signedApkDestPath = $($rootPath + "/com.x8bit.bitwarden.apk");
|
||||
|
||||
Copy-Item $signedApkPath $signedApkDestPath
|
||||
29
.github/scripts/decrypt-secret.ps1
vendored
Normal file
29
.github/scripts/decrypt-secret.ps1
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $filename,
|
||||
[string] $output
|
||||
)
|
||||
|
||||
$homePath = Resolve-Path "~" | Select-Object -ExpandProperty Path
|
||||
$rootPath = $env:GITHUB_WORKSPACE
|
||||
|
||||
$secretInputPath = $rootPath + "/.github/secrets"
|
||||
$input = $secretInputPath + "/" + $filename
|
||||
|
||||
$passphrase = $env:DECRYPT_FILE_PASSWORD
|
||||
$secretOutputPath = $homePath + "/secrets"
|
||||
|
||||
if ([string]::IsNullOrEmpty($output)) {
|
||||
if ($filename.EndsWith(".gpg")) {
|
||||
$output = $secretOutputPath + "/" + $filename.TrimEnd(".gpg")
|
||||
} else {
|
||||
$output = $secretOutputPath + "/" + $filename + ".plaintext"
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Test-Path -Path $secretOutputPath))
|
||||
{
|
||||
New-Item -ItemType Directory -Path $secretOutputPath
|
||||
}
|
||||
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$passphrase" --output $output $input
|
||||
29
.github/scripts/ios/build.ps1
vendored
Normal file
29
.github/scripts/ios/build.ps1
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $configuration,
|
||||
[string] $platform = "iPhone",
|
||||
[switch] $archive
|
||||
)
|
||||
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$iosPath = $($rootPath + "/src/iOS/iOS.csproj");
|
||||
|
||||
if ($archive)
|
||||
{
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Archive $configuration Configuration for $platform Platform"
|
||||
Write-Output "########################################"
|
||||
msbuild "$($iosPath)" "/p:Platform=$platform" "/p:Configuration=$configuration" `
|
||||
"/p:ArchiveOnBuild=true" "/t:`"Build`""
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Done"
|
||||
Write-Output "########################################"
|
||||
ls ~/Library/Developer/Xcode/Archives
|
||||
} else
|
||||
{
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Build $configuration Configuration for $platform Platform"
|
||||
Write-Output "########################################"
|
||||
msbuild "$($iosPath)" "/p:Platform=$platform" "/p:Configuration=$configuration" "/t:`"Build`""
|
||||
}
|
||||
9
.github/scripts/ios/decrypt-secrets.ps1
vendored
Normal file
9
.github/scripts/ios/decrypt-secrets.ps1
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
|
||||
$decryptSecretPath = $($rootPath + "/.github/scripts/decrypt-secret.ps1");
|
||||
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename bitwarden-mobile-key.p12.gpg"
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename iphone-distribution-cert.p12.gpg"
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename dist_autofill.mobileprovision.gpg"
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename dist_bitwarden.mobileprovision.gpg"
|
||||
Invoke-Expression "& `"$decryptSecretPath`" -filename dist_extension.mobileprovision.gpg"
|
||||
5
.github/scripts/ios/deploy-app-store.ps1
vendored
Normal file
5
.github/scripts/ios/deploy-app-store.ps1
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$ipaPath = "$rootPath/bitwarden-export/Bitwarden.ipa"
|
||||
|
||||
xcrun altool --upload-app --type ios --file "$ipaPath" `
|
||||
--username "$env:APPLE_ID_USERNAME" --password "$env:APPLE_ID_PASSWORD"
|
||||
13
.github/scripts/ios/export-ipa.ps1
vendored
Normal file
13
.github/scripts/ios/export-ipa.ps1
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $method
|
||||
)
|
||||
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$homePath = Resolve-Path "~" | Select-Object -ExpandProperty Path
|
||||
|
||||
$exportOptionsPath = "$rootPath/.github/resources/export-options-$method.plist";
|
||||
$archivePath = "$homePath/Library/Developer/Xcode/Archives/*/*.xcarchive";
|
||||
$exportPath = "$rootPath/bitwarden-export";
|
||||
|
||||
xcodebuild -exportArchive -archivePath $archivePath -exportPath $exportPath -exportOptionsPlist $exportOptionsPath
|
||||
26
.github/scripts/ios/increment-version.ps1
vendored
Normal file
26
.github/scripts/ios/increment-version.ps1
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$buildNumber = 100 + [int]$env:GITHUB_RUN_NUMBER;
|
||||
|
||||
$bitwardenInfo = $($rootPath + "/src/iOS/Info.plist");
|
||||
$extensionInfo = $($rootPath + "/src/iOS.Extension/Info.plist");
|
||||
$autofillInfo = $($rootPath + "/src/iOS.Autofill/Info.plist");
|
||||
|
||||
Write-Output "########################################"
|
||||
Write-Output "##### Setting CFBundleVersion $buildNumber"
|
||||
Write-Output "########################################"
|
||||
|
||||
function Update-Version($file) {
|
||||
$xml=New-Object XML;
|
||||
$xml.Load($file);
|
||||
|
||||
Select-Xml -xml $xml -XPath "//dict/key[. = 'CFBundleVersion']/following-sibling::string[1]" |
|
||||
%{
|
||||
$_.Node.InnerXml = $buildNumber
|
||||
}
|
||||
|
||||
$xml.Save($file);
|
||||
}
|
||||
|
||||
Update-Version $bitwardenInfo
|
||||
Update-Version $extensionInfo
|
||||
Update-Version $autofillInfo
|
||||
13
.github/scripts/ios/setup-keychain.ps1
vendored
Normal file
13
.github/scripts/ios/setup-keychain.ps1
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
$homePath = Resolve-Path "~" | Select-Object -ExpandProperty Path;
|
||||
$secretsPath = $homePath + "/secrets"
|
||||
|
||||
$mobileKeyPath = $($secretsPath + "/bitwarden-mobile-key.p12");
|
||||
$distCertPath = $($secretsPath + "/iphone-distribution-cert.p12");
|
||||
|
||||
security create-keychain -p $env:KEYCHAIN_PASSWORD build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $env:KEYCHAIN_PASSWORD build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
security import $mobileKeyPath -k build.keychain -P $env:MOBILE_KEY_PASSWORD -T /usr/bin/codesign -T /usr/bin/security
|
||||
security import $distCertPath -k build.keychain -P $env:DIST_CERT_PASSWORD -T /usr/bin/codesign -T /usr/bin/security
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $env:KEYCHAIN_PASSWORD build.keychain
|
||||
21
.github/scripts/ios/setup-profiles.ps1
vendored
Normal file
21
.github/scripts/ios/setup-profiles.ps1
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
$homePath = Resolve-Path "~" | Select-Object -ExpandProperty Path;
|
||||
$secretsPath = $homePath + "/secrets"
|
||||
|
||||
$autofillProfilePath = $($secretsPath + "/dist_autofill.mobileprovision");
|
||||
$bitwardenProfilePath = $($secretsPath + "/dist_bitwarden.mobileprovision");
|
||||
$extensionProfilePath = $($secretsPath + "/dist_extension.mobileprovision");
|
||||
$profilesDirPath = "~/Library/MobileDevice/Provisioning Profiles"
|
||||
|
||||
if (!(Test-Path -Path $profilesDirPath))
|
||||
{
|
||||
New-Item -ItemType Directory -Path $profilesDirPath
|
||||
}
|
||||
|
||||
$autofill_uuid = grep UUID -A1 -a $autofillProfilePath | grep -io "[-A-F0-9]\{36\}"
|
||||
Copy-Item $autofillProfilePath -destination "$profilesDirPath/$autofill_uuid.mobileprovision"
|
||||
|
||||
$bitwarden_uuid = grep UUID -A1 -a $bitwardenProfilePath | grep -io "[-A-F0-9]\{36\}"
|
||||
Copy-Item $bitwardenProfilePath -destination "$profilesDirPath/$bitwarden_uuid.mobileprovision"
|
||||
|
||||
$extension_uuid = grep UUID -A1 -a $extensionProfilePath | grep -io "[-A-F0-9]\{36\}"
|
||||
Copy-Item $extensionProfilePath -destination "$profilesDirPath/$extension_uuid.mobileprovision"
|
||||
BIN
.github/secrets/app_fdroid-keystore.jks.gpg
vendored
Normal file
BIN
.github/secrets/app_fdroid-keystore.jks.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/app_play-keystore.jks.gpg
vendored
Normal file
BIN
.github/secrets/app_play-keystore.jks.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/app_upload-keystore.jks.gpg
vendored
Normal file
BIN
.github/secrets/app_upload-keystore.jks.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/bitwarden-mobile-key.p12.gpg
vendored
Normal file
BIN
.github/secrets/bitwarden-mobile-key.p12.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
Normal file
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
Normal file
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
Normal file
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
Normal file
Binary file not shown.
3
.github/secrets/google-services.json.gpg
vendored
Normal file
3
.github/secrets/google-services.json.gpg
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<EFBFBD>
|
||||
K<>Y#<23>(<28><><EFBFBD><EFBFBD>EI߄T?)l<><6C><EFBFBD><18><><10>"=<3D>|<7C>'e<><0E>m<EFBFBD>/~<7E><>'F<><46>><3E><><EFBFBD><EFBFBD>l<EFBFBD>b<EFBFBD>[<5B>+R<><52>iL<69><4C>"<22><><EFBFBD>~V:<3A><>p<EFBFBD>a<17>ڵel%8t<38><74>튖<EFBFBD>y<<3C>n<EFBFBD><6E><EFBFBD>aU<61>w<16>JD<4A><44><1F><>We<57>9<EFBFBD><39><EFBFBD><EFBFBD><x8d<38>O<EFBFBD>j\<14>ד<EFBFBD><D793><EFBFBD>Vq<56><71>
|
||||
Ǻ<EFBFBD>-<2D>#<23><><11><>]$<24>(<28>l,<2C>Br<42><02><>d<><64><EFBFBD>a-<2D><><EFBFBD>:<3A><>:<3A><04>9b,!Em<02><19><>Qf<>D<EFBFBD>g<EFBFBD><06><0E>x(P<>ȡ~<7E><EFBFBD><CDB9> <09><>[<06><>!:<3A>;f<><66>
|
||||
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
Normal file
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/play_creds.json.gpg
vendored
Normal file
BIN
.github/secrets/play_creds.json.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/store_fdroid-keystore.jks.gpg
vendored
Normal file
BIN
.github/secrets/store_fdroid-keystore.jks.gpg
vendored
Normal file
Binary file not shown.
295
.github/workflows/build.yml
vendored
Normal file
295
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'l10n_master'
|
||||
- 'gh-pages'
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
|
||||
cloc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Set up cloc
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install cloc
|
||||
|
||||
- name: Print lines of code
|
||||
run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML
|
||||
|
||||
android:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@c26a08ba26249b81327e26f6ef381897b6a8754d
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
nuget help | grep Version
|
||||
msbuild -version
|
||||
dotnet --info
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GITHUB_EVENT: ${{ github.event_name }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Decrypt secrets
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/android/decrypt-secrets.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
||||
|
||||
- name: Increment version
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/android/increment-version.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Restore packages
|
||||
run: nuget restore
|
||||
|
||||
- name: Run Core Tests
|
||||
run: dotnet test test/Core.Test/Core.Test.csproj
|
||||
|
||||
- name: Build Play Store publisher
|
||||
run: dotnet build ./store/google/Publisher/Publisher.csproj -p:Configuration=Release
|
||||
|
||||
- name: Build for Play Store
|
||||
run: ./.github/scripts/android/build.ps1 -configuration Release
|
||||
shell: pwsh
|
||||
|
||||
- name: Sign for Play Store
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/android/sign-play.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }}
|
||||
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
|
||||
|
||||
- name: Upload Play Store .aab artifact
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
|
||||
with:
|
||||
name: com.x8bit.bitwarden.aab
|
||||
path: ./com.x8bit.bitwarden.aab
|
||||
|
||||
- name: Upload Play Store .apk artifact
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
|
||||
with:
|
||||
name: com.x8bit.bitwarden.apk
|
||||
path: ./com.x8bit.bitwarden.apk
|
||||
|
||||
- name: Clean for F-Droid
|
||||
run: ./.github/scripts/android/clean-fdroid.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Restore packages
|
||||
run: nuget restore
|
||||
|
||||
- name: Build for F-Droid
|
||||
run: ./.github/scripts/android/build.ps1 -configuration FDroid
|
||||
shell: pwsh
|
||||
|
||||
- name: Sign for F-Droid
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/android/sign-fdroid.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
|
||||
|
||||
- name: Upload F-Droid .apk artifact
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
|
||||
with:
|
||||
name: com.x8bit.bitwarden-fdroid.apk
|
||||
path: ./com.x8bit.bitwarden-fdroid.apk
|
||||
|
||||
- name: Deploy to Play Store
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/android/deploy-play.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload release assets
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
hub release edit `
|
||||
-a ./com.x8bit.bitwarden.aab `
|
||||
-a ./com.x8bit.bitwarden.apk `
|
||||
-a ./com.x8bit.bitwarden-fdroid.apk `
|
||||
-m "Version $($env:RELEASE_TAG_NAME.TrimStart('v'))" `
|
||||
$env:RELEASE_TAG_NAME
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
|
||||
android-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
needs: android
|
||||
|
||||
steps:
|
||||
- name: Set up Node
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||
with:
|
||||
node-version: '10.x'
|
||||
|
||||
- name: Set up F-Droid server
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qqy install --no-install-recommends fdroidserver wget
|
||||
|
||||
- name: Set up git credentials
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
run: |
|
||||
git config --global credential.helper store
|
||||
echo "https://${ACCESS_TOKEN}:x-oauth-basic@github.com" >> ~/.git-credentials
|
||||
git config --global user.email "ci@bitwarden.com"
|
||||
git config --global user.name "Bitwarden CI"
|
||||
|
||||
- name: Print environment
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
node --version
|
||||
npm --version
|
||||
git --version
|
||||
Write-Output "GitHub ref: $env:GITHUB_REF"
|
||||
Write-Output "GitHub event: $env:GITHUB_EVENT"
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GITHUB_EVENT: ${{ github.event_name }}
|
||||
|
||||
- name: Checkout repo
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Install Node dependencies
|
||||
if: github.event_name == 'release'
|
||||
run: npm install
|
||||
|
||||
- name: Decrypt secrets
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
./.github/scripts/decrypt-secret.ps1 -filename store_fdroid-keystore.jks.gpg `
|
||||
-output ./store/fdroid/keystore.jks
|
||||
shell: pwsh
|
||||
env:
|
||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
||||
|
||||
- name: Compile for F-Droid Store
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
sudo chmod +x ./.github/scripts/android/compile-fdroid.sh
|
||||
./.github/scripts/android/compile-fdroid.sh
|
||||
env:
|
||||
FDROID_STORE_KEYSTORE_PASSWORD: ${{ secrets.FDROID_STORE_KEYSTORE_PASSWORD }}
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Deploy to gh-pages
|
||||
if: github.event_name == 'release'
|
||||
run: npm run deploy
|
||||
|
||||
ios:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Print environment
|
||||
run: |
|
||||
nuget help | grep Version
|
||||
msbuild -version
|
||||
dotnet --info
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
GITHUB_EVENT: ${{ github.event_name }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Decrypt secrets
|
||||
run: ./.github/scripts/ios/decrypt-secrets.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
||||
|
||||
- name: Increment version
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/ios/increment-version.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Set up keychain
|
||||
run: ./.github/scripts/ios/setup-keychain.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
|
||||
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }}
|
||||
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
|
||||
|
||||
- name: Set up provisioning profiles
|
||||
run: ./.github/scripts/ios/setup-profiles.ps1
|
||||
shell: pwsh
|
||||
|
||||
- name: Restore packages
|
||||
run: nuget restore
|
||||
|
||||
- name: Archive Build for App Store
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/ios/build.ps1 -configuration AppStore -platform iPhone -archive
|
||||
shell: pwsh
|
||||
|
||||
- name: Build for App Store
|
||||
if: github.ref != 'refs/heads/master'
|
||||
run: ./.github/scripts/ios/build.ps1 -configuration AppStore -platform iPhone
|
||||
shell: pwsh
|
||||
|
||||
- name: Export .ipa for App Store
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/ios/export-ipa.ps1 -method app-store
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload App Store .ipa artifact
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
|
||||
with:
|
||||
name: Bitwarden.ipa
|
||||
path: ./bitwarden-export/Bitwarden.ipa
|
||||
|
||||
- name: Deploy to App Store
|
||||
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
|
||||
run: ./.github/scripts/ios/deploy-app-store.ps1
|
||||
shell: pwsh
|
||||
env:
|
||||
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
- name: Upload release assets
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
hub release edit `
|
||||
-a ./bitwarden-export/Bitwarden.ipa `
|
||||
-m "Version $($env:RELEASE_TAG_NAME.TrimStart('v'))" `
|
||||
$env:RELEASE_TAG_NAME
|
||||
shell: pwsh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,15 +1,28 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# Visual Studio (>=2015) project-specific, machine local files
|
||||
.vs/
|
||||
|
||||
# JetBrains Rider project-specific, machine local files
|
||||
.idea
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# ignore Xamarin.Android Resource.Designer.cs files
|
||||
**/*.Droid/**/[Rr]esource.[Dd]esigner.cs
|
||||
**/*.Android/**/[Rr]esource.[Dd]esigner.cs
|
||||
**/Android/**/[Rr]esource.[Dd]esigner.cs
|
||||
**/Droid/**/[Rr]esource.[Dd]esigner.cs
|
||||
|
||||
# Xamarin Components
|
||||
Components/
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
@@ -22,9 +35,6 @@ bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studo 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
@@ -197,4 +207,5 @@ FakesAssemblies/
|
||||
|
||||
# Other
|
||||
project.lock.json
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
src/App/Css
|
||||
40
CONTRIBUTING.md
Normal file
40
CONTRIBUTING.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# How to Contribute
|
||||
|
||||
Contributions of all kinds are welcome!
|
||||
|
||||
Please visit our [Community Forums](https://community.bitwarden.com/) for general community discussion and the development roadmap.
|
||||
|
||||
Here is how you can get involved:
|
||||
|
||||
* **Request a new feature:** Go to the [Feature Requests category](https://community.bitwarden.com/c/feature-requests/) of the Community Forums. Please search existing feature requests before making a new one
|
||||
|
||||
* **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code
|
||||
|
||||
* **Report a bug or submit a bugfix:** Use Github issues and pull requests
|
||||
|
||||
* **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help)
|
||||
|
||||
* **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums
|
||||
|
||||
* **Translate:** See the localization (i10n) section below
|
||||
|
||||
## Contributor Agreement
|
||||
|
||||
Please sign the [Contributor Agreement](https://cla-assistant.io/bitwarden/mobile) if you intend on contributing to any Github repository. Pull requests cannot be accepted and merged unless the author has signed the Contributor Agreement.
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
* commit any pull requests against the `master` branch
|
||||
* include a link to your Community Forums post
|
||||
|
||||
# Localization (l10n)
|
||||
|
||||
[](https://crowdin.com/project/bitwarden-mobile)
|
||||
|
||||
We use a translation tool called [Crowdin](https://crowdin.com) to help manage our localization efforts across many different languages.
|
||||
|
||||
If you are interested in helping translate the Bitwarden mobile app into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-mobile
|
||||
|
||||
If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/kspearrin).
|
||||
|
||||
You can read Crowdin's getting started guide for translators here: https://support.crowdin.com/crowdin-intro/
|
||||
53
ISSUE_TEMPLATE.md
Normal file
53
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,53 @@
|
||||
<!-- Comment:
|
||||
Please do not submit feature requests. The [Community Forums][1] has a
|
||||
section for submitting, voting for, and discussing product feature requests.
|
||||
[1]: https://community.bitwarden.com
|
||||
-->
|
||||
|
||||
## Describe the Bug
|
||||
|
||||
<!-- Comment:
|
||||
A clear and concise description of what the bug is.
|
||||
-->
|
||||
|
||||
## Steps To Reproduce
|
||||
|
||||
<!-- Comment:
|
||||
How can we reproduce the behavior:
|
||||
-->
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. Click on '...'
|
||||
|
||||
## Expected Result
|
||||
|
||||
<!-- Comment:
|
||||
A clear and concise description of what you expected to happen.
|
||||
-->
|
||||
|
||||
## Actual Result
|
||||
|
||||
<!-- Comment:
|
||||
A clear and concise description of what is happening.
|
||||
-->
|
||||
|
||||
## Screenshots or Videos
|
||||
|
||||
<!-- Comment:
|
||||
If applicable, add screenshots and/or a short video to help explain your problem.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- Operating system: [e.g. iOS 8.1]
|
||||
- Build Version (go to "Settings" → "About" in the app): [e.g. 2.3.0 (2221)]
|
||||
- Is this a Beta release? [Y/N]
|
||||
|
||||
## Additional Context
|
||||
|
||||
<!-- Comment:
|
||||
Add any other context about the problem here.
|
||||
-->
|
||||
674
LICENSE.txt
Normal file
674
LICENSE.txt
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
30
README.md
30
README.md
@@ -1,11 +1,31 @@
|
||||
# bitwarden mobile
|
||||
[](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:master)
|
||||
[](https://crowdin.com/project/bitwarden-mobile)
|
||||
[](https://gitter.im/bitwarden/Lobby)
|
||||
|
||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://developer.android.com/images/brand/en_generic_rgb_wo_45.png"width="129" height="45"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://linkmaker.itunes.apple.com/images/badges/en-us/badge_appstore-lrg.svg" width="165" height="40"></a>
|
||||
# Bitwarden Mobile Application
|
||||
|
||||
The bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://mobileapp.bitwarden.com/fdroid/" target="_blank"><img alt="Get it on Google Play" src="https://i.imgur.com/HDicnzz.png" width="154" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
|
||||
|
||||
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android-myvault.png" alt="" width="300" height="533" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios-myvault.png" alt="" width="300" height="533" />
|
||||
|
||||
# Build/Run
|
||||
|
||||
**Requirements**
|
||||
|
||||
- [Visual Studio](https://visualstudio.microsoft.com/)
|
||||
- [Xamarin](https://docs.microsoft.com/en-us/xamarin/get-started/installation/?pivots=windows)
|
||||
|
||||
**Run the app**
|
||||
|
||||
- Open the solution file in Visual Studio.
|
||||
- Restore the nuget packages.
|
||||
- Build and run the app.
|
||||
|
||||
# Contribute
|
||||
|
||||
Code contributions are welcome! Visual Studio or Xamarin Studio is required to work on this project. Please commit any pull requests against the `master` branch.
|
||||
Code contributions are welcome! Visual Studio with Xamarin is required to work on this project. Please commit any pull requests against the `master` branch.
|
||||
Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.
|
||||
|
||||
Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature.
|
||||
Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file.
|
||||
|
||||
45
SECURITY.md
Normal file
45
SECURITY.md
Normal file
@@ -0,0 +1,45 @@
|
||||
Bitwarden believes that working with security researchers across the globe is crucial to keeping our
|
||||
users safe. If you believe you've found a security issue in our product or service, we encourage you to
|
||||
notify us. We welcome working with you to resolve the issue promptly. Thanks in advance!
|
||||
|
||||
# Disclosure Policy
|
||||
|
||||
- Let us know as soon as possible upon discovery of a potential security issue, and we'll make every
|
||||
effort to quickly resolve the issue.
|
||||
- Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a
|
||||
third-party. We may publicly disclose the issue before resolving it, if appropriate.
|
||||
- Make a good faith effort to avoid privacy violations, destruction of data, and interruption or
|
||||
degradation of our service. Only interact with accounts you own or with explicit permission of the
|
||||
account holder.
|
||||
- If you would like to encrypt your report, please use the PGP key with long ID
|
||||
`0xDE6887086F892325FEC04CC0D847525B6931381F` (available in the public keyserver pool).
|
||||
|
||||
# In-scope
|
||||
|
||||
- Security issues in any current release of Bitwarden. This includes the web vault, browser extension,
|
||||
and mobile apps (iOS and Android). Product downloads are available at https://bitwarden.com. Source
|
||||
code is available at https://github.com/bitwarden.
|
||||
|
||||
# Exclusions
|
||||
|
||||
The following bug classes are out-of scope:
|
||||
|
||||
- Bugs that are already reported on any of Bitwarden's issue trackers (https://github.com/bitwarden),
|
||||
or that we already know of. Note that some of our issue tracking is private.
|
||||
- Issues in an upstream software dependency (ex: Xamarin, ASP.NET) which are already reported to the
|
||||
upstream maintainer.
|
||||
- Attacks requiring physical access to a user's device.
|
||||
- Self-XSS
|
||||
- Issues related to software or protocols not under Bitwarden's control
|
||||
- Vulnerabilities in outdated versions of Bitwarden
|
||||
- Missing security best practices that do not directly lead to a vulnerability
|
||||
- Issues that do not have any impact on the general public
|
||||
|
||||
While researching, we'd like to ask you to refrain from:
|
||||
|
||||
- Denial of service
|
||||
- Spamming
|
||||
- Social engineering (including phishing) of Bitwarden staff or contractors
|
||||
- Any physical attempts against Bitwarden property or data centers
|
||||
|
||||
Thank you for helping keep Bitwarden and our users safe!
|
||||
@@ -1,428 +1,438 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29009.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{04B18ED2-B76D-4947-8474-191F8FD2B5E0}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{1F78403F-9A28-405B-9289-B9DBEB55F074}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{B490C5DA-639E-4994-ABD2-54222B8A348E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "test\Playground\Playground.csproj", "{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EC730FD9-F623-4B6C-B503-95CDCFBCF277}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D10CA4A9-F866-40E1-B658-F69051236C71}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App.Test", "test\App.Test\App.Test.csproj", "{A300DCE1-8D10-4267-B96A-CB01AEB7C220}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8904C536-C67D-420F-9971-51B26574C3AA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{B2538ADA-B605-4D6F-ACD2-62A409680F84}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Test", "test\iOS.Test\iOS.Test.csproj", "{6702027A-F726-4149-863E-7CB924674B9A}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
.github\workflows\build.yml = .github\workflows\build.yml
|
||||
CONTRIBUTING.md = CONTRIBUTING.md
|
||||
crowdin.yml = crowdin.yml
|
||||
README.md = README.md
|
||||
SECURITY.md = SECURITY.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android.Test", "test\Android.Test\Android.Test.csproj", "{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{599E0201-420A-4C3E-A7BA-5349F72E0B15}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
Ad-Hoc|ARM = Ad-Hoc|ARM
|
||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||
Ad-Hoc|x64 = Ad-Hoc|x64
|
||||
Ad-Hoc|x86 = Ad-Hoc|x86
|
||||
AppStore|Any CPU = AppStore|Any CPU
|
||||
AppStore|ARM = AppStore|ARM
|
||||
AppStore|iPhone = AppStore|iPhone
|
||||
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||
AppStore|x64 = AppStore|x64
|
||||
AppStore|x86 = AppStore|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
FDroid|Any CPU = FDroid|Any CPU
|
||||
FDroid|iPhone = FDroid|iPhone
|
||||
FDroid|iPhoneSimulator = FDroid|iPhoneSimulator
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|iPhone = Release|iPhone
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.Deploy.0 = Debug|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.Deploy.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.Deploy.0 = Release|Any CPU
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|ARM.ActiveCfg = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|x64.ActiveCfg = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|x86.ActiveCfg = AppStore|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|ARM.ActiveCfg = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x64.ActiveCfg = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x64.Build.0 = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x86.ActiveCfg = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x86.Build.0 = Debug|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|ARM.ActiveCfg = Release|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|x64.ActiveCfg = Release|iPhone
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|x86.ActiveCfg = Release|iPhone
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x86.Build.0 = Release|Any CPU
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|ARM.ActiveCfg = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|x64.ActiveCfg = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.AppStore|x86.ActiveCfg = AppStore|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|ARM.ActiveCfg = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x64.ActiveCfg = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x64.Build.0 = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x86.ActiveCfg = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x86.Build.0 = Debug|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|ARM.ActiveCfg = Release|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|x64.ActiveCfg = Release|iPhone
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|x86.ActiveCfg = Release|iPhone
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|ARM.ActiveCfg = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|x64.ActiveCfg = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.AppStore|x86.ActiveCfg = AppStore|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|ARM.ActiveCfg = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|x64.ActiveCfg = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Debug|x86.ActiveCfg = Debug|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|ARM.ActiveCfg = Release|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|x64.ActiveCfg = Release|iPhone
|
||||
{6702027A-F726-4149-863E-7CB924674B9A}.Release|x86.ActiveCfg = Release|iPhone
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|ARM.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x64.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|ARM.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x64.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.AppStore|x86.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.Deploy.0 = Debug|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x64.Deploy.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Deploy.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Deploy.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Deploy.0 = FDroid|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.ActiveCfg = AppStore|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.Build.0 = AppStore|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.ActiveCfg = FDroid|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.Build.0 = FDroid|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.Build.0 = FDroid|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.Build.0 = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.Build.0 = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.Build.0 = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{04B18ED2-B76D-4947-8474-191F8FD2B5E0} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{1F78403F-9A28-405B-9289-B9DBEB55F074} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{B490C5DA-639E-4994-ABD2-54222B8A348E} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{A300DCE1-8D10-4267-B96A-CB01AEB7C220} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{6702027A-F726-4149-863E-7CB924674B9A} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
|
||||
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
|
||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{4B8A8C41-9820-4341-974C-41E65B7F4366} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
|
||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
|
||||
{E71F3053-056C-4381-9638-048ED73BDFF6} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
34
crowdin.yml
Normal file
34
crowdin.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
files:
|
||||
- source: /src/App/Resources/AppResources.resx
|
||||
translation: /src/App/Resources/AppResources.%two_letters_code%.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
zh-TW: zh-Hant
|
||||
pt-PT: pt-PT
|
||||
pt-BR: pt-BR
|
||||
en-GB: en-GB
|
||||
en-IN: en-IN
|
||||
- source: /store/apple/en/copy.resx
|
||||
translation: /store/apple/%two_letters_code%/copy.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
zh-TW: zh-Hant
|
||||
pt-PT: pt-PT
|
||||
pt-BR: pt-BR
|
||||
en-GB: en-GB
|
||||
en-IN: en-IN
|
||||
- source: /store/google/en/copy.resx
|
||||
translation: /store/google/%two_letters_code%/copy.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
zh-TW: zh-Hant
|
||||
pt-BR: pt-BR
|
||||
pt-PT: pt-PT
|
||||
en-GB: en-GB
|
||||
en-IN: en-IN
|
||||
344
package-lock.json
generated
Normal file
344
package-lock.json
generated
Normal file
@@ -0,0 +1,344 @@
|
||||
{
|
||||
"name": "bitwarden-mobile",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"array-union": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-uniq": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"array-uniq": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
|
||||
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
|
||||
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.10"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"filename-reserved-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz",
|
||||
"integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=",
|
||||
"dev": true
|
||||
},
|
||||
"filenamify": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz",
|
||||
"integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"filename-reserved-regex": "^1.0.0",
|
||||
"strip-outer": "^1.0.0",
|
||||
"trim-repeated": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"filenamify-url": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/filenamify-url/-/filenamify-url-1.0.0.tgz",
|
||||
"integrity": "sha1-syvYExnvWGO3MHi+1Q9GpPeXX1A=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"filenamify": "^1.0.0",
|
||||
"humanize-url": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"gh-pages": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-1.2.0.tgz",
|
||||
"integrity": "sha512-cGLYAvxtlQ1iTwAS4g7FreZPXoE/g62Fsxln2mmR19mgs4zZI+XJ+wVVUhBFCF/0+Nmvbq+abyTWue1m1BSnmg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async": "2.6.1",
|
||||
"commander": "2.15.1",
|
||||
"filenamify-url": "^1.0.0",
|
||||
"fs-extra": "^5.0.0",
|
||||
"globby": "^6.1.0",
|
||||
"graceful-fs": "4.1.11",
|
||||
"rimraf": "^2.6.2"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"globby": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
|
||||
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^1.0.1",
|
||||
"glob": "^7.0.3",
|
||||
"object-assign": "^4.0.1",
|
||||
"pify": "^2.0.0",
|
||||
"pinkie-promise": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||
"dev": true
|
||||
},
|
||||
"humanize-url": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz",
|
||||
"integrity": "sha1-9KuZ4NKIF0yk4eUEB8VfuuRk7/8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-url": "^1.0.0",
|
||||
"strip-url-auth": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"is-plain-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"normalize-url": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
||||
"integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.0.1",
|
||||
"prepend-http": "^1.0.0",
|
||||
"query-string": "^4.1.0",
|
||||
"sort-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||
"dev": true
|
||||
},
|
||||
"pinkie": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
|
||||
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
|
||||
"dev": true
|
||||
},
|
||||
"pinkie-promise": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
||||
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pinkie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"prepend-http": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
|
||||
"dev": true
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"sort-keys": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-plain-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-outer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
|
||||
"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"escape-string-regexp": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"strip-url-auth": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-url-auth/-/strip-url-auth-1.0.1.tgz",
|
||||
"integrity": "sha1-IrD6OkE4WzO+PzMVUbu4N/oM164=",
|
||||
"dev": true
|
||||
},
|
||||
"trim-repeated": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
|
||||
"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"escape-string-regexp": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
11
package.json
Normal file
11
package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "bitwarden-mobile",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"deploy": "gh-pages --dist dist",
|
||||
"clean:l10n": "git push origin --delete l10n_master"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gh-pages": "^1.2.0"
|
||||
}
|
||||
}
|
||||
BIN
src/Android/8bit.keystore.enc
Normal file
BIN
src/Android/8bit.keystore.enc
Normal file
Binary file not shown.
121
src/Android/Accessibility/AccessibilityActivity.cs
Normal file
121
src/Android/Accessibility/AccessibilityActivity.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using System;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
[Activity(Theme = "@style/LightTheme.Splash", WindowSoftInputMode = SoftInput.StateHidden)]
|
||||
public class AccessibilityActivity : Activity
|
||||
{
|
||||
private DateTime? _lastLaunch = null;
|
||||
private string _lastQueriedUri;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
HandleIntent(Intent, 932473);
|
||||
}
|
||||
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
{
|
||||
base.OnNewIntent(intent);
|
||||
HandleIntent(intent, 489729);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
if (!Intent.HasExtra("uri"))
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
Intent.RemoveExtra("uri");
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if (data == null)
|
||||
{
|
||||
AccessibilityHelpers.LastCredentials = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (data.GetStringExtra("canceled") != null)
|
||||
{
|
||||
AccessibilityHelpers.LastCredentials = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var uri = data.GetStringExtra("uri");
|
||||
var username = data.GetStringExtra("username");
|
||||
var password = data.GetStringExtra("password");
|
||||
AccessibilityHelpers.LastCredentials = new Credentials
|
||||
{
|
||||
Username = username,
|
||||
Password = password,
|
||||
Uri = uri,
|
||||
LastUri = _lastQueriedUri
|
||||
};
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
AccessibilityHelpers.LastCredentials = null;
|
||||
}
|
||||
}
|
||||
Finish();
|
||||
}
|
||||
|
||||
private void HandleIntent(Intent callingIntent, int requestCode)
|
||||
{
|
||||
if (callingIntent?.GetBooleanExtra("autofillTileClicked", false) ?? false)
|
||||
{
|
||||
Intent.RemoveExtra("autofillTileClicked");
|
||||
var messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||
messagingService.Send("OnAutofillTileClick");
|
||||
Finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
LaunchMainActivity(callingIntent, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchMainActivity(Intent callingIntent, int requestCode)
|
||||
{
|
||||
_lastQueriedUri = callingIntent?.GetStringExtra("uri");
|
||||
if (_lastQueriedUri == null)
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
var now = DateTime.UtcNow;
|
||||
if (_lastLaunch.HasValue && (now - _lastLaunch.Value) <= TimeSpan.FromSeconds(2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastLaunch = now;
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
if (!callingIntent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
|
||||
{
|
||||
intent.PutExtra("uri", _lastQueriedUri);
|
||||
}
|
||||
StartActivityForResult(intent, requestCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
902
src/Android/Accessibility/AccessibilityHelpers.cs
Normal file
902
src/Android/Accessibility/AccessibilityHelpers.cs
Normal file
@@ -0,0 +1,902 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Views.Accessibility;
|
||||
using Android.Widget;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core;
|
||||
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
public static class AccessibilityHelpers
|
||||
{
|
||||
public static Credentials LastCredentials = null;
|
||||
public static string SystemUiPackage = "com.android.systemui";
|
||||
public static string BitwardenTag = "bw_access";
|
||||
public static bool IsAutofillTileAdded = false;
|
||||
public static bool IsAccessibilityBroadcastReady = false;
|
||||
|
||||
// Be sure to keep these two sections sorted alphabetically
|
||||
public static Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
|
||||
{
|
||||
// [Section A] Entries also present in the list of Autofill Framework
|
||||
//
|
||||
// So keep them in sync with:
|
||||
// - AutofillHelpers.{TrustedBrowsers,CompatBrowsers}
|
||||
// - Resources/xml/autofillservice.xml
|
||||
new Browser("alook.browser", "search_fragment_input_view"),
|
||||
new Browser("com.amazon.cloud9", "url"),
|
||||
new Browser("com.android.browser", "url"),
|
||||
new Browser("com.android.chrome", "url_bar"),
|
||||
// Rem. for "com.android.htmlviewer": doesn't have a URL bar, therefore not present here.
|
||||
new Browser("com.avast.android.secure.browser", "editor"),
|
||||
new Browser("com.avg.android.secure.browser", "editor"),
|
||||
new Browser("com.brave.browser", "url_bar"),
|
||||
new Browser("com.brave.browser_beta", "url_bar"),
|
||||
new Browser("com.brave.browser_default", "url_bar"),
|
||||
new Browser("com.brave.browser_dev", "url_bar"),
|
||||
new Browser("com.brave.browser_nightly", "url_bar"),
|
||||
new Browser("com.chrome.beta", "url_bar"),
|
||||
new Browser("com.chrome.canary", "url_bar"),
|
||||
new Browser("com.chrome.dev", "url_bar"),
|
||||
new Browser("com.cookiegames.smartcookie", "search"),
|
||||
new Browser("com.cookiejarapps.android.smartcookieweb", "mozac_browser_toolbar_url_view"),
|
||||
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
|
||||
new Browser("com.ecosia.android", "url_bar"),
|
||||
new Browser("com.google.android.apps.chrome", "url_bar"),
|
||||
new Browser("com.google.android.apps.chrome_dev", "url_bar"),
|
||||
new Browser("com.jamal2367.styx", "search"),
|
||||
new Browser("com.kiwibrowser.browser", "url_bar"),
|
||||
new Browser("com.microsoft.emmx", "url_bar"),
|
||||
new Browser("com.microsoft.emmx.beta", "url_bar"),
|
||||
new Browser("com.microsoft.emmx.canary", "url_bar"),
|
||||
new Browser("com.microsoft.emmx.dev", "url_bar"),
|
||||
new Browser("com.mmbox.browser", "search_box"),
|
||||
new Browser("com.mmbox.xbrowser", "search_box"),
|
||||
new Browser("com.mycompany.app.soulbrowser", "edit_text"),
|
||||
new Browser("com.naver.whale", "url_bar"),
|
||||
new Browser("com.opera.browser", "url_field"),
|
||||
new Browser("com.opera.browser.beta", "url_field"),
|
||||
new Browser("com.opera.mini.native", "url_field"),
|
||||
new Browser("com.opera.mini.native.beta", "url_field"),
|
||||
new Browser("com.opera.touch", "addressbarEdit"),
|
||||
new Browser("com.qwant.liberty", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy (before v4)
|
||||
new Browser("com.sec.android.app.sbrowser", "location_bar_edit_text"),
|
||||
new Browser("com.sec.android.app.sbrowser.beta", "location_bar_edit_text"),
|
||||
new Browser("com.stoutner.privacybrowser.free", "url_edittext"),
|
||||
new Browser("com.stoutner.privacybrowser.standard", "url_edittext"),
|
||||
new Browser("com.vivaldi.browser", "url_bar"),
|
||||
new Browser("com.vivaldi.browser.snapshot", "url_bar"),
|
||||
new Browser("com.vivaldi.browser.sopranos", "url_bar"),
|
||||
new Browser("com.yandex.browser", "bro_omnibar_address_title_text,bro_omnibox_collapsed_title",
|
||||
(s) => s.Split(new char[]{' ', ' '}).FirstOrDefault()), // 0 = Regular Space, 1 = No-break space (00A0)
|
||||
new Browser("com.z28j.feel", "g2"),
|
||||
new Browser("idm.internet.download.manager", "search"),
|
||||
new Browser("idm.internet.download.manager.adm.lite", "search"),
|
||||
new Browser("idm.internet.download.manager.plus", "search"),
|
||||
new Browser("io.github.forkmaintainers.iceraven", "mozac_browser_toolbar_url_view"),
|
||||
new Browser("mark.via", "am,an"),
|
||||
new Browser("mark.via.gp", "as"),
|
||||
new Browser("net.slions.fulguris.full.download", "search"),
|
||||
new Browser("net.slions.fulguris.full.download.debug", "search"),
|
||||
new Browser("net.slions.fulguris.full.playstore", "search"),
|
||||
new Browser("net.slions.fulguris.full.playstore.debug", "search"),
|
||||
new Browser("org.adblockplus.browser", "url_bar,url_bar_title"), // 2nd = Legacy (before v2)
|
||||
new Browser("org.adblockplus.browser.beta", "url_bar,url_bar_title"), // 2nd = Legacy (before v2)
|
||||
new Browser("org.bromite.bromite", "url_bar"),
|
||||
new Browser("org.bromite.chromium", "url_bar"),
|
||||
new Browser("org.chromium.chrome", "url_bar"),
|
||||
new Browser("org.codeaurora.swe.browser", "url_bar"),
|
||||
new Browser("org.gnu.icecat", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
|
||||
new Browser("org.mozilla.fenix", "mozac_browser_toolbar_url_view"),
|
||||
new Browser("org.mozilla.fenix.nightly", "mozac_browser_toolbar_url_view"), // [DEPRECATED ENTRY]
|
||||
new Browser("org.mozilla.fennec_aurora", "mozac_browser_toolbar_url_view,url_bar_title"), // [DEPRECATED ENTRY]
|
||||
new Browser("org.mozilla.fennec_fdroid", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy
|
||||
new Browser("org.mozilla.firefox", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy
|
||||
new Browser("org.mozilla.firefox_beta", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy
|
||||
new Browser("org.mozilla.focus", "display_url"),
|
||||
new Browser("org.mozilla.klar", "display_url"),
|
||||
new Browser("org.mozilla.reference.browser", "mozac_browser_toolbar_url_view"),
|
||||
new Browser("org.mozilla.rocket", "display_url"),
|
||||
new Browser("org.torproject.torbrowser", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy (before v10.0.3)
|
||||
new Browser("org.torproject.torbrowser_alpha", "mozac_browser_toolbar_url_view,url_bar_title"), // 2nd = Legacy (before v10.0a8)
|
||||
new Browser("org.ungoogled.chromium.extensions.stable", "url_bar"),
|
||||
new Browser("org.ungoogled.chromium.stable", "url_bar"),
|
||||
|
||||
// [Section B] Entries only present here
|
||||
//
|
||||
// FIXME: Test the compatibility of these with Autofill Framework
|
||||
new Browser("acr.browser.barebones", "search"),
|
||||
new Browser("acr.browser.lightning", "search"),
|
||||
new Browser("com.feedback.browser.wjbrowser", "addressbar_url"),
|
||||
new Browser("com.ghostery.android.ghostery", "search_field"),
|
||||
new Browser("com.htc.sense.browser", "title"),
|
||||
new Browser("com.jerky.browser2", "enterUrl"),
|
||||
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
|
||||
new Browser("com.linkbubble.playstore", "url_text"),
|
||||
new Browser("com.mx.browser", "address_editor_with_progress"),
|
||||
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
|
||||
new Browser("com.nubelacorp.javelin", "enterUrl"),
|
||||
new Browser("jp.co.fenrir.android.sleipnir", "url_text"),
|
||||
new Browser("jp.co.fenrir.android.sleipnir_black", "url_text"),
|
||||
new Browser("jp.co.fenrir.android.sleipnir_test", "url_text"),
|
||||
new Browser("mobi.mgeek.TunnyBrowser", "title"),
|
||||
new Browser("org.iron.srware", "url_bar"),
|
||||
}.ToDictionary(n => n.PackageName);
|
||||
|
||||
// Known packages to skip
|
||||
public static HashSet<string> FilteredPackageNames => new HashSet<string>
|
||||
{
|
||||
SystemUiPackage,
|
||||
"com.google.android.googlequicksearchbox",
|
||||
"com.google.android.apps.nexuslauncher",
|
||||
"com.google.android.launcher",
|
||||
"com.computer.desktop.ui.launcher",
|
||||
"com.launcher.notelauncher",
|
||||
"com.anddoes.launcher",
|
||||
"com.actionlauncher.playstore",
|
||||
"ch.deletescape.lawnchair.plah",
|
||||
"com.microsoft.launcher",
|
||||
"com.teslacoilsw.launcher",
|
||||
"com.teslacoilsw.launcher.prime",
|
||||
"is.shortcut",
|
||||
"me.craftsapp.nlauncher",
|
||||
"com.ss.squarehome2",
|
||||
"com.treydev.pns"
|
||||
};
|
||||
|
||||
// Be sure to keep these sections sorted alphabetically
|
||||
public static Dictionary<string, KnownUsernameField> KnownUsernameFields => new List<KnownUsernameField>
|
||||
{
|
||||
/**************************************************************************************
|
||||
* SECTION A ——— World-renowned web sites/applications
|
||||
*************************************************************************************/
|
||||
|
||||
// REM.: For this type of web sites/applications, the Top 100 (SimilarWeb, 2019)
|
||||
// and the Top 50 (Alexa Internet, 2020) are covered. National variants
|
||||
// have been added when available. Mobile and desktop versions supported.
|
||||
//
|
||||
// A few other popular web sites/applications have also been added.
|
||||
//
|
||||
// Could not be added, however:
|
||||
// web sites/applications that don't use an "id" attribute for their login field.
|
||||
|
||||
// NOTE: The case of OAuth compatible web sites/applications that also provide
|
||||
// a "user ID only" login page in this situation
|
||||
// was taken into account in the tests as well.
|
||||
|
||||
/*
|
||||
* A
|
||||
*/
|
||||
|
||||
// Amazon ——— ap_email_login = mobile / ap_email = desktop (amazon.co.jp currently uses ap_email in both cases, as of July 2020).
|
||||
new KnownUsernameField("amazon.ae", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.ca", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.cn", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.co.jp", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.co.uk", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.com", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.com.au", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.com.br", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.com.mx", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.com.tr", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.de", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.es", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.fr", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.in", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.it", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.nl", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.pl", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.sa", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.se", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
new KnownUsernameField("amazon.sg", new (string, string)[] { ("contains:/ap/signin", "ap_email_login,ap_email") }),
|
||||
|
||||
// Amazon Web Services
|
||||
new KnownUsernameField("signin.aws.amazon.com", new (string, string)[] { ("signin", "resolving_input") }),
|
||||
|
||||
// Atlassian
|
||||
new KnownUsernameField("id.atlassian.com", new (string, string)[] { ("login", "username") }),
|
||||
|
||||
/*
|
||||
* B
|
||||
*/
|
||||
|
||||
// Bitly ——— enterprise users.
|
||||
new KnownUsernameField("bitly.com", new (string, string)[] { ("/sso/url_slug", "url_slug") }),
|
||||
|
||||
/*
|
||||
* E
|
||||
*/
|
||||
|
||||
// eBay ——— 1st = traditional access / 2nd = direct access (i.e. https://signin.ebay.tld/).
|
||||
new KnownUsernameField("signin.befr.ebay.be", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.benl.ebay.be", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.cafr.ebay.ca", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.at", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.be", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.ca", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.ch", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.co.uk", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.com", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.com.au", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.com.hk", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.com.my", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.com.sg", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.de", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.es", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.fr", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.ie", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.in", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.it", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.nl", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.ph", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
new KnownUsernameField("signin.ebay.pl", new (string, string)[] { ("iendswith:eBayISAPI.dll", "userid"), ("icontains:/signin/", "userid") }),
|
||||
|
||||
/*
|
||||
* G
|
||||
*/
|
||||
|
||||
// Google ——— 1st = used in most cases (v2) / 2nd = used in some cases (v1).
|
||||
new KnownUsernameField("accounts.google.com", new (string, string)[] { ("identifier", "identifierId"), ("ServiceLogin", "Email") }),
|
||||
|
||||
/*
|
||||
* P
|
||||
*/
|
||||
|
||||
// PayPal ——— 1st = traditional access / 2nd = access using OAuth.
|
||||
new KnownUsernameField("paypal.com", new (string, string)[] { ("signin", "email"), ("contains:/connect/", "email") }),
|
||||
|
||||
/*
|
||||
* T
|
||||
*/
|
||||
|
||||
// Tumblr ——— despite "signup" in its ID, it's the login field (the website offers registration if the account doesn't exist).
|
||||
new KnownUsernameField("tumblr.com", new (string, string)[] { ("login", "signup_determine_email") }),
|
||||
|
||||
/*
|
||||
* Y
|
||||
*/
|
||||
|
||||
// Yandex
|
||||
new KnownUsernameField("passport.yandex.az", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.by", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.co.il", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.com", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.com.am", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.com.ge", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.com.tr", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.ee", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.fi", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.fr", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.kg", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.kz", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.lt", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.lv", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.md", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.pl", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.ru", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.tj", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.tm", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.ua", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
new KnownUsernameField("passport.yandex.uz", new (string, string)[] { ("auth", "passp-field-login") }),
|
||||
|
||||
/**************************************************************************************
|
||||
* SECTION B ——— Top 100 worldwide
|
||||
*************************************************************************************/
|
||||
|
||||
// As of July 2020, all entries that needed to be added from
|
||||
// Top 100 (SimilarWeb, 2019) and Top 50 (Alexa Internet, 2020)
|
||||
// matched section A.
|
||||
//
|
||||
// Therefore, no entry currently.
|
||||
|
||||
/**************************************************************************************
|
||||
* SECTION C ——— Top 20 for selected countries
|
||||
*************************************************************************************/
|
||||
|
||||
// REM.: For these selected countries, the Top 20 (SimilarWeb, 2020)
|
||||
// and the Top 20 (Alexa Internet, 2020) are covered.
|
||||
// Mobile and desktop versions supported.
|
||||
//
|
||||
// Could not be added, however:
|
||||
// web sites/applications that don't use an "id" attribute for their login field.
|
||||
|
||||
/*
|
||||
* Japan
|
||||
*/
|
||||
|
||||
// NTT DOCOMO ——— mainly used for "My docomo".
|
||||
new KnownUsernameField("cfg.smt.docomo.ne.jp", new (string, string)[] { ("contains:/auth/", "Di_Uid") }),
|
||||
new KnownUsernameField("id.smt.docomo.ne.jp", new (string, string)[] { ("contains:/cgi7/", "Di_Uid") }),
|
||||
|
||||
/**************************************************************************************
|
||||
* SECTION D ——— Miscellaneous
|
||||
*************************************************************************************/
|
||||
|
||||
/*
|
||||
* Various entries ——— Following user requests, etc.
|
||||
*/
|
||||
|
||||
// No entry, currently.
|
||||
|
||||
/**************************************************************************************
|
||||
* SECTION Z ——— Special forms
|
||||
*
|
||||
* Despite "user ID + password" fields both visible, detection rules required.
|
||||
*************************************************************************************/
|
||||
|
||||
/*
|
||||
* Main
|
||||
*/
|
||||
|
||||
// No entry, currently.
|
||||
|
||||
/*
|
||||
* Test/example purposes only
|
||||
*/
|
||||
|
||||
// GitHub ——— VERY special case (signup form, just to test the proper functioning of special forms).
|
||||
new KnownUsernameField("github.com", new (string, string)[] { ("", "user[login]-footer") }),
|
||||
}.ToDictionary(n => n.UriAuthority);
|
||||
|
||||
public static void PrintTestData(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||
{
|
||||
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
|
||||
var testNodesData = testNodes.Select(n => new { id = n.ViewIdResourceName, text = n.Text });
|
||||
foreach (var node in testNodesData)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Node: {0} = {1}", node.id, node.text);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetUri(AccessibilityNodeInfo root)
|
||||
{
|
||||
var uri = string.Concat(Constants.AndroidAppProtocol, root.PackageName);
|
||||
if (SupportedBrowsers.ContainsKey(root.PackageName))
|
||||
{
|
||||
var browser = SupportedBrowsers[root.PackageName];
|
||||
AccessibilityNodeInfo addressNode = null;
|
||||
foreach (var uriViewId in browser.UriViewId.Split(","))
|
||||
{
|
||||
addressNode = root.FindAccessibilityNodeInfosByViewId(
|
||||
$"{root.PackageName}:id/{uriViewId}").FirstOrDefault();
|
||||
if (addressNode != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addressNode != null)
|
||||
{
|
||||
uri = ExtractUri(uri, addressNode, browser);
|
||||
addressNode.Recycle();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return null to prevent overwriting notification pendingIntent uri with browser packageName
|
||||
// (we login to pages, not browsers)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
private static string ExtractUri(string uri, AccessibilityNodeInfo addressNode, Browser browser)
|
||||
{
|
||||
if (addressNode?.Text == null)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
if (addressNode.Text == null)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
uri = browser.GetUriFunction(addressNode.Text)?.Trim();
|
||||
if (uri != null && uri.Contains("."))
|
||||
{
|
||||
var hasHttpProtocol = uri.StartsWith("http://") || uri.StartsWith("https://");
|
||||
if (!hasHttpProtocol && uri.Contains("."))
|
||||
{
|
||||
if (Uri.TryCreate("https://" + uri, UriKind.Absolute, out var _))
|
||||
{
|
||||
return string.Concat("https://", uri);
|
||||
}
|
||||
}
|
||||
if (Uri.TryCreate(uri, UriKind.Absolute, out var _))
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to make sure it is ok to autofill still on the current screen
|
||||
/// </summary>
|
||||
public static bool NeedToAutofill(Credentials credentials, string currentUriString)
|
||||
{
|
||||
if (credentials == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Uri.TryCreate(credentials.LastUri, UriKind.Absolute, out Uri lastUri) &&
|
||||
Uri.TryCreate(currentUriString, UriKind.Absolute, out Uri currentUri))
|
||||
{
|
||||
return lastUri.Host == currentUri.Host;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool EditText(AccessibilityNodeInfo n)
|
||||
{
|
||||
return n?.ClassName?.Contains("EditText") ?? false;
|
||||
}
|
||||
|
||||
public static void FillCredentials(AccessibilityNodeInfo usernameNode,
|
||||
IEnumerable<AccessibilityNodeInfo> passwordNodes)
|
||||
{
|
||||
FillEditText(usernameNode, LastCredentials?.Username);
|
||||
foreach (var n in passwordNodes)
|
||||
{
|
||||
FillEditText(n, LastCredentials?.Password);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FillEditText(AccessibilityNodeInfo editTextNode, string value)
|
||||
{
|
||||
if (editTextNode == null || value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var bundle = new Bundle();
|
||||
bundle.PutString(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, value);
|
||||
editTextNode.PerformAction(Android.Views.Accessibility.Action.SetText, bundle);
|
||||
}
|
||||
|
||||
public static NodeList GetWindowNodes(AccessibilityNodeInfo n, AccessibilityEvent e,
|
||||
Func<AccessibilityNodeInfo, bool> condition, bool disposeIfUnused, NodeList nodes = null,
|
||||
int recursionDepth = 0)
|
||||
{
|
||||
if (nodes == null)
|
||||
{
|
||||
nodes = new NodeList();
|
||||
}
|
||||
var dispose = disposeIfUnused;
|
||||
if (n != null && recursionDepth < 100)
|
||||
{
|
||||
var add = n.WindowId == e.WindowId &&
|
||||
!(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) &&
|
||||
condition(n);
|
||||
if (add)
|
||||
{
|
||||
dispose = false;
|
||||
nodes.Add(n);
|
||||
}
|
||||
|
||||
for (var i = 0; i < n.ChildCount; i++)
|
||||
{
|
||||
var childNode = n.GetChild(i);
|
||||
if (childNode == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (i > 100)
|
||||
{
|
||||
Android.Util.Log.Info(BitwardenTag, "Too many child iterations.");
|
||||
break;
|
||||
}
|
||||
else if (childNode.GetHashCode() == n.GetHashCode())
|
||||
{
|
||||
Android.Util.Log.Info(BitwardenTag, "Child node is the same as parent for some reason.");
|
||||
}
|
||||
else
|
||||
{
|
||||
GetWindowNodes(childNode, e, condition, true, nodes, recursionDepth++);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dispose)
|
||||
{
|
||||
n?.Recycle();
|
||||
n?.Dispose();
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public static AccessibilityNodeInfo GetUsernameEditText(string uriString,
|
||||
IEnumerable<AccessibilityNodeInfo> allEditTexts)
|
||||
{
|
||||
string uriAuthority = null;
|
||||
string uriKey = null;
|
||||
string uriLocalPath = null;
|
||||
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||
{
|
||||
uriAuthority = uri.Authority;
|
||||
uriKey = uriAuthority.StartsWith("www.", StringComparison.Ordinal) ? uriAuthority.Substring(4) : uriAuthority;
|
||||
uriLocalPath = uri.LocalPath;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(uriKey))
|
||||
{
|
||||
// Uncomment this to log values necessary for username field discovery
|
||||
// foreach (var editText in allEditTexts)
|
||||
// {
|
||||
// System.Diagnostics.Debug.WriteLine(">>> uriKey: {0}, uriLocalPath: {1}, viewId: {2}", uriKey,
|
||||
// uriLocalPath, editText.ViewIdResourceName);
|
||||
// }
|
||||
|
||||
if (KnownUsernameFields.ContainsKey(uriKey))
|
||||
{
|
||||
var usernameField = KnownUsernameFields[uriKey];
|
||||
(string UriPathWanted, string UsernameViewId)[] accessOptions = usernameField.AccessOptions;
|
||||
|
||||
for (int i = 0; i < accessOptions.Length; i++)
|
||||
{
|
||||
string curUriPathWanted = accessOptions[i].UriPathWanted;
|
||||
string curUsernameViewId = accessOptions[i].UsernameViewId;
|
||||
bool uriLocalPathMatches = false;
|
||||
|
||||
// Case-sensitive comparison
|
||||
if (curUriPathWanted.StartsWith("startswith:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(11);
|
||||
uriLocalPathMatches = uriLocalPath.StartsWith(curUriPathWanted, StringComparison.Ordinal);
|
||||
}
|
||||
else if (curUriPathWanted.StartsWith("contains:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(9);
|
||||
uriLocalPathMatches = uriLocalPath.Contains(curUriPathWanted, StringComparison.Ordinal);
|
||||
}
|
||||
else if (curUriPathWanted.StartsWith("endswith:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(9);
|
||||
uriLocalPathMatches = uriLocalPath.EndsWith(curUriPathWanted, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
// Case-insensitive comparison
|
||||
else if (curUriPathWanted.StartsWith("istartswith:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(12);
|
||||
uriLocalPathMatches = uriLocalPath.StartsWith(curUriPathWanted, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (curUriPathWanted.StartsWith("icontains:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(10);
|
||||
uriLocalPathMatches = uriLocalPath.Contains(curUriPathWanted, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (curUriPathWanted.StartsWith("iendswith:", StringComparison.Ordinal))
|
||||
{
|
||||
curUriPathWanted = curUriPathWanted.Substring(10);
|
||||
uriLocalPathMatches = uriLocalPath.EndsWith(curUriPathWanted, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// Default type of comparison
|
||||
else
|
||||
{
|
||||
uriLocalPathMatches = uriLocalPath.EndsWith(curUriPathWanted, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
if (uriLocalPathMatches)
|
||||
{
|
||||
foreach (var editText in allEditTexts)
|
||||
{
|
||||
foreach (var usernameViewId in curUsernameViewId.Split(","))
|
||||
{
|
||||
if (usernameViewId == editText.ViewIdResourceName)
|
||||
{
|
||||
return editText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no match found, attempt to establish username field based on password field
|
||||
return GetUsernameEditTextIfPasswordExists(allEditTexts);
|
||||
}
|
||||
|
||||
private static AccessibilityNodeInfo GetUsernameEditTextIfPasswordExists(
|
||||
IEnumerable<AccessibilityNodeInfo> allEditTexts)
|
||||
{
|
||||
AccessibilityNodeInfo previousEditText = null;
|
||||
foreach (var editText in allEditTexts)
|
||||
{
|
||||
if (editText.Password)
|
||||
{
|
||||
return previousEditText;
|
||||
}
|
||||
previousEditText = editText;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsUsernameEditText(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||
{
|
||||
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
|
||||
var uriString = GetUri(root);
|
||||
var usernameEditText = GetUsernameEditText(uriString, allEditTexts);
|
||||
|
||||
var isUsernameEditText = false;
|
||||
if (usernameEditText != null)
|
||||
{
|
||||
isUsernameEditText = IsSameNode(usernameEditText, e.Source);
|
||||
}
|
||||
allEditTexts.Dispose();
|
||||
|
||||
return isUsernameEditText;
|
||||
}
|
||||
|
||||
public static bool IsSameNode(AccessibilityNodeInfo node1, AccessibilityNodeInfo node2)
|
||||
{
|
||||
if (node1 != null && node2 != null)
|
||||
{
|
||||
return node1.Equals(node2) || node1.GetHashCode() == node2.GetHashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool OverlayPermitted()
|
||||
{
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
||||
{
|
||||
if (Settings.CanDrawOverlays(Application.Context))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var appOpsMgr = (AppOpsManager)Application.Context.GetSystemService(Context.AppOpsService);
|
||||
var mode = appOpsMgr.CheckOpNoThrow("android:system_alert_window", Process.MyUid(),
|
||||
Application.Context.PackageName);
|
||||
if (mode == AppOpsManagerMode.Allowed || mode == AppOpsManagerMode.Ignored)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var wm = Application.Context.GetSystemService(Context.WindowService)
|
||||
.JavaCast<IWindowManager>();
|
||||
if (wm == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var testView = new View(Application.Context);
|
||||
var layoutParams = GetOverlayLayoutParams();
|
||||
wm.AddView(testView, layoutParams);
|
||||
wm.RemoveView(testView);
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// older android versions are always true
|
||||
return true;
|
||||
}
|
||||
|
||||
public static LinearLayout GetOverlayView(Context context)
|
||||
{
|
||||
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
||||
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
|
||||
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
||||
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
||||
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
||||
text1.Text = AppResources.AutofillWithBitwarden;
|
||||
text2.Text = AppResources.GoToMyVault;
|
||||
icon.SetImageResource(Resource.Drawable.shield);
|
||||
return view;
|
||||
}
|
||||
|
||||
public static WindowManagerLayoutParams GetOverlayLayoutParams()
|
||||
{
|
||||
WindowManagerTypes windowManagerType;
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||
{
|
||||
windowManagerType = WindowManagerTypes.ApplicationOverlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
windowManagerType = WindowManagerTypes.Phone;
|
||||
}
|
||||
|
||||
var layoutParams = new WindowManagerLayoutParams(
|
||||
ViewGroup.LayoutParams.WrapContent,
|
||||
ViewGroup.LayoutParams.WrapContent,
|
||||
windowManagerType,
|
||||
WindowManagerFlags.NotFocusable | WindowManagerFlags.NotTouchModal,
|
||||
Format.Transparent);
|
||||
layoutParams.Gravity = GravityFlags.Top | GravityFlags.Left;
|
||||
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorView,
|
||||
int overlayViewHeight, bool isOverlayAboveAnchor)
|
||||
{
|
||||
var anchorViewRect = new Rect();
|
||||
anchorView.GetBoundsInScreen(anchorViewRect);
|
||||
var anchorViewX = anchorViewRect.Left;
|
||||
var anchorViewY = isOverlayAboveAnchor ? anchorViewRect.Top : anchorViewRect.Bottom;
|
||||
anchorViewRect.Dispose();
|
||||
|
||||
if (isOverlayAboveAnchor)
|
||||
{
|
||||
anchorViewY -= overlayViewHeight;
|
||||
}
|
||||
anchorViewY -= GetStatusBarHeight(service);
|
||||
|
||||
return new Point(anchorViewX, anchorViewY);
|
||||
}
|
||||
|
||||
public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorNode,
|
||||
AccessibilityNodeInfo root, IEnumerable<AccessibilityWindowInfo> windows, int overlayViewHeight,
|
||||
bool isOverlayAboveAnchor)
|
||||
{
|
||||
Point point = null;
|
||||
if (anchorNode != null)
|
||||
{
|
||||
// Update node's info since this is still a reference from an older event
|
||||
anchorNode.Refresh();
|
||||
if (!anchorNode.VisibleToUser)
|
||||
{
|
||||
return new Point(-1, -1);
|
||||
}
|
||||
if (!anchorNode.Focused)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// node.VisibleToUser doesn't always give us exactly what we want, so attempt to tighten up the range
|
||||
// of visibility
|
||||
var inputMethodHeight = 0;
|
||||
if (windows != null)
|
||||
{
|
||||
if (IsStatusBarExpanded(windows))
|
||||
{
|
||||
return new Point(-1, -1);
|
||||
}
|
||||
inputMethodHeight = GetInputMethodHeight(windows);
|
||||
}
|
||||
var minY = 0;
|
||||
var rootNodeHeight = GetNodeHeight(root);
|
||||
if (rootNodeHeight == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var maxY = rootNodeHeight - GetNavigationBarHeight(service) - GetStatusBarHeight(service) -
|
||||
inputMethodHeight;
|
||||
|
||||
point = GetOverlayAnchorPosition(service, anchorNode, overlayViewHeight, isOverlayAboveAnchor);
|
||||
if (point.Y < minY)
|
||||
{
|
||||
if (isOverlayAboveAnchor)
|
||||
{
|
||||
// view nearing bounds, anchor to bottom
|
||||
point.X = -1;
|
||||
point.Y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// view out of bounds, hide overlay
|
||||
point.X = -1;
|
||||
point.Y = -1;
|
||||
}
|
||||
}
|
||||
else if (point.Y > (maxY - overlayViewHeight))
|
||||
{
|
||||
if (isOverlayAboveAnchor)
|
||||
{
|
||||
// view out of bounds, hide overlay
|
||||
point.X = -1;
|
||||
point.Y = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// view nearing bounds, anchor to top
|
||||
point.X = 0;
|
||||
point.Y = -1;
|
||||
}
|
||||
}
|
||||
else if (isOverlayAboveAnchor && point.Y < (maxY - (overlayViewHeight * 2) - GetNodeHeight(anchorNode)))
|
||||
{
|
||||
// This else block forces the overlay to return to bottom alignment as soon as space is available
|
||||
// below the anchor view. Removing this will change the behavior to wait until there isn't enough
|
||||
// space above the anchor view before returning to bottom alignment.
|
||||
point.X = -1;
|
||||
point.Y = 0;
|
||||
}
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
public static bool IsStatusBarExpanded(IEnumerable<AccessibilityWindowInfo> windows)
|
||||
{
|
||||
if (windows != null && windows.Any())
|
||||
{
|
||||
var isSystemWindowsOnly = true;
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.Type != AccessibilityWindowType.System)
|
||||
{
|
||||
isSystemWindowsOnly = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isSystemWindowsOnly;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int GetInputMethodHeight(IEnumerable<AccessibilityWindowInfo> windows)
|
||||
{
|
||||
var inputMethodWindowHeight = 0;
|
||||
if (windows != null)
|
||||
{
|
||||
foreach (var window in windows)
|
||||
{
|
||||
if (window.Type == AccessibilityWindowType.InputMethod)
|
||||
{
|
||||
var windowRect = new Rect();
|
||||
window.GetBoundsInScreen(windowRect);
|
||||
inputMethodWindowHeight = windowRect.Height();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return inputMethodWindowHeight;
|
||||
}
|
||||
|
||||
public static bool IsAutofillServicePromptVisible(IEnumerable<AccessibilityWindowInfo> windows)
|
||||
{
|
||||
// Autofill framework not available until API 26
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||
{
|
||||
return windows?.Any(w => w.Title?.ToLower().Contains("autofill") ?? false) ?? false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int GetNodeHeight(AccessibilityNodeInfo node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var nodeRect = new Rect();
|
||||
node.GetBoundsInScreen(nodeRect);
|
||||
var nodeRectHeight = nodeRect.Height();
|
||||
nodeRect.Dispose();
|
||||
return nodeRectHeight;
|
||||
}
|
||||
|
||||
private static int GetStatusBarHeight(AccessibilityService service)
|
||||
{
|
||||
return GetSystemResourceDimenPx(service, "status_bar_height");
|
||||
}
|
||||
|
||||
private static int GetNavigationBarHeight(AccessibilityService service)
|
||||
{
|
||||
return GetSystemResourceDimenPx(service, "navigation_bar_height");
|
||||
}
|
||||
|
||||
private static int GetSystemResourceDimenPx(AccessibilityService service, string resName)
|
||||
{
|
||||
var resourceId = service.Resources.GetIdentifier(resName, "dimen", "android");
|
||||
if (resourceId > 0)
|
||||
{
|
||||
return service.Resources.GetDimensionPixelSize(resourceId);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
473
src/Android/Accessibility/AccessibilityService.cs
Normal file
473
src/Android/Accessibility/AccessibilityService.cs
Normal file
@@ -0,0 +1,473 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Views.Accessibility;
|
||||
using Android.Widget;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
[Service(Permission = Android.Manifest.Permission.BindAccessibilityService, Label = "Bitwarden")]
|
||||
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
|
||||
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
|
||||
[Register("com.x8bit.bitwarden.Accessibility.AccessibilityService")]
|
||||
public class AccessibilityService : Android.AccessibilityServices.AccessibilityService
|
||||
{
|
||||
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
||||
private const string BitwardenWebsite = "vault.bitwarden.com";
|
||||
|
||||
private IStorageService _storageService;
|
||||
private IBroadcasterService _broadcasterService;
|
||||
private DateTime? _lastSettingsReload = null;
|
||||
private TimeSpan _settingsReloadSpan = TimeSpan.FromMinutes(1);
|
||||
private HashSet<string> _blacklistedUris;
|
||||
private AccessibilityNodeInfo _anchorNode = null;
|
||||
private int _lastAnchorX = 0;
|
||||
private int _lastAnchorY = 0;
|
||||
private bool _isOverlayAboveAnchor = false;
|
||||
private static bool _overlayAnchorObserverRunning = false;
|
||||
private IWindowManager _windowManager = null;
|
||||
private LinearLayout _overlayView = null;
|
||||
private int _overlayViewHeight = 0;
|
||||
private long _lastAutoFillTime = 0;
|
||||
private Java.Lang.Runnable _overlayAnchorObserverRunnable = null;
|
||||
private Handler _handler = new Handler(Looper.MainLooper);
|
||||
|
||||
private HashSet<string> _launcherPackageNames = null;
|
||||
private DateTime? _lastLauncherSetBuilt = null;
|
||||
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
|
||||
|
||||
public override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
LoadServices();
|
||||
var settingsTask = LoadSettingsAsync();
|
||||
_broadcasterService.Subscribe(nameof(AccessibilityService), (message) =>
|
||||
{
|
||||
if (message.Command == "OnAutofillTileClick")
|
||||
{
|
||||
var runnable = new Java.Lang.Runnable(OnAutofillTileClick);
|
||||
_handler.PostDelayed(runnable, 250);
|
||||
}
|
||||
});
|
||||
AccessibilityHelpers.IsAccessibilityBroadcastReady = true;
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
AccessibilityHelpers.IsAccessibilityBroadcastReady = false;
|
||||
_broadcasterService.Unsubscribe(nameof(AccessibilityService));
|
||||
}
|
||||
|
||||
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var powerManager = GetSystemService(PowerService) as PowerManager;
|
||||
if (Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch && !powerManager.IsInteractive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop && !powerManager.IsScreenOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SkipPackage(e?.PackageName))
|
||||
{
|
||||
if (e?.PackageName != "com.android.systemui")
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// AccessibilityHelpers.PrintTestData(RootInActiveWindow, e);
|
||||
|
||||
LoadServices();
|
||||
var settingsTask = LoadSettingsAsync();
|
||||
AccessibilityNodeInfo root = null;
|
||||
|
||||
switch (e.EventType)
|
||||
{
|
||||
case EventTypes.ViewFocused:
|
||||
case EventTypes.ViewClicked:
|
||||
if (e.Source == null || e.PackageName == BitwardenPackage)
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
break;
|
||||
}
|
||||
|
||||
root = RootInActiveWindow;
|
||||
if (root == null || root.PackageName != e.PackageName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(e.Source?.Password ?? false) && !AccessibilityHelpers.IsUsernameEditText(root, e))
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
break;
|
||||
}
|
||||
if (ScanAndAutofill(root, e))
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
}
|
||||
else
|
||||
{
|
||||
OverlayPromptToAutofill(root, e);
|
||||
}
|
||||
break;
|
||||
case EventTypes.WindowContentChanged:
|
||||
case EventTypes.WindowStateChanged:
|
||||
if (AccessibilityHelpers.LastCredentials == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (e.PackageName == BitwardenPackage)
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
break;
|
||||
}
|
||||
|
||||
root = RootInActiveWindow;
|
||||
if (root == null || root.PackageName != e.PackageName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ScanAndAutofill(root, e))
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Suppress exceptions so that service doesn't crash.
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", ex.GetType(), ex.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInterrupt()
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||
{
|
||||
var filled = false;
|
||||
var uri = AccessibilityHelpers.GetUri(root);
|
||||
if (uri != null && !uri.Contains(BitwardenWebsite) &&
|
||||
AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
|
||||
{
|
||||
var allEditTexts = AccessibilityHelpers.GetWindowNodes(root, e, n => AccessibilityHelpers.EditText(n), false);
|
||||
var usernameEditText = AccessibilityHelpers.GetUsernameEditText(uri, allEditTexts);
|
||||
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
|
||||
if (usernameEditText != null || passwordNodes.Count > 0)
|
||||
{
|
||||
AccessibilityHelpers.FillCredentials(usernameEditText, passwordNodes);
|
||||
filled = true;
|
||||
_lastAutoFillTime = Java.Lang.JavaSystem.CurrentTimeMillis();
|
||||
AccessibilityHelpers.LastCredentials = null;
|
||||
}
|
||||
allEditTexts.Dispose();
|
||||
passwordNodes.Dispose();
|
||||
}
|
||||
if (AccessibilityHelpers.LastCredentials != null)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
AccessibilityHelpers.LastCredentials = null;
|
||||
});
|
||||
}
|
||||
return filled;
|
||||
}
|
||||
|
||||
private void OnAutofillTileClick()
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
|
||||
var root = RootInActiveWindow;
|
||||
if (root != null && root.PackageName != BitwardenPackage &&
|
||||
root.PackageName != AccessibilityHelpers.SystemUiPackage &&
|
||||
!SkipPackage(root.PackageName))
|
||||
{
|
||||
var uri = AccessibilityHelpers.GetUri(root);
|
||||
if (!string.IsNullOrWhiteSpace(uri))
|
||||
{
|
||||
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||
intent.PutExtra("uri", uri);
|
||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||
StartActivity(intent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Toast.MakeText(this, AppResources.AutofillTileUriNotFound, ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
private void CancelOverlayPrompt()
|
||||
{
|
||||
_overlayAnchorObserverRunning = false;
|
||||
|
||||
if (_windowManager != null && _overlayView != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_windowManager.RemoveViewImmediate(_overlayView);
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Removed");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
_overlayView = null;
|
||||
_lastAnchorX = 0;
|
||||
_lastAnchorY = 0;
|
||||
_isOverlayAboveAnchor = false;
|
||||
|
||||
if (_anchorNode != null)
|
||||
{
|
||||
_anchorNode.Recycle();
|
||||
_anchorNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OverlayPromptToAutofill(AccessibilityNodeInfo root, AccessibilityEvent e)
|
||||
{
|
||||
if (Java.Lang.JavaSystem.CurrentTimeMillis() - _lastAutoFillTime < 1000 ||
|
||||
AccessibilityHelpers.IsAutofillServicePromptVisible(Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AccessibilityHelpers.OverlayPermitted())
|
||||
{
|
||||
if (Build.VERSION.SdkInt <= BuildVersionCodes.M)
|
||||
{
|
||||
// The user has the option of only using the autofill tile and leaving the overlay permission
|
||||
// disabled, so only show this toast if they're using accessibility without overlay permission on
|
||||
// a version of Android without quick-action tile support
|
||||
System.Diagnostics.Debug.WriteLine(">>> Overlay Permission not granted");
|
||||
Toast.MakeText(this, AppResources.AccessibilityDrawOverPermissionAlert, ToastLength.Long).Show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_overlayView != null || _anchorNode != null || _overlayAnchorObserverRunning)
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
}
|
||||
|
||||
var uri = AccessibilityHelpers.GetUri(root);
|
||||
var fillable = !string.IsNullOrWhiteSpace(uri);
|
||||
if (fillable)
|
||||
{
|
||||
if (_blacklistedUris != null && _blacklistedUris.Any())
|
||||
{
|
||||
if (Uri.TryCreate(uri, UriKind.Absolute, out var parsedUri) && parsedUri.Scheme.StartsWith("http"))
|
||||
{
|
||||
fillable = !_blacklistedUris.Contains(
|
||||
string.Format("{0}://{1}", parsedUri.Scheme, parsedUri.Host));
|
||||
}
|
||||
else
|
||||
{
|
||||
fillable = !_blacklistedUris.Contains(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fillable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var intent = new Intent(this, typeof(AccessibilityActivity));
|
||||
intent.PutExtra("uri", uri);
|
||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||
|
||||
_overlayView = AccessibilityHelpers.GetOverlayView(this);
|
||||
_overlayView.Measure(View.MeasureSpec.MakeMeasureSpec(0, 0),
|
||||
View.MeasureSpec.MakeMeasureSpec(0, 0));
|
||||
_overlayViewHeight = _overlayView.MeasuredHeight;
|
||||
_overlayView.Click += (sender, eventArgs) =>
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
StartActivity(intent);
|
||||
};
|
||||
|
||||
var layoutParams = AccessibilityHelpers.GetOverlayLayoutParams();
|
||||
var anchorPosition = AccessibilityHelpers.GetOverlayAnchorPosition(this, e.Source,
|
||||
_overlayViewHeight, _isOverlayAboveAnchor);
|
||||
layoutParams.X = anchorPosition.X;
|
||||
layoutParams.Y = anchorPosition.Y;
|
||||
|
||||
if (_windowManager == null)
|
||||
{
|
||||
_windowManager = GetSystemService(WindowService).JavaCast<IWindowManager>();
|
||||
}
|
||||
|
||||
_anchorNode = e.Source;
|
||||
_lastAnchorX = anchorPosition.X;
|
||||
_lastAnchorY = anchorPosition.Y;
|
||||
|
||||
_windowManager.AddView(_overlayView, layoutParams);
|
||||
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Added at X:{0} Y:{1}",
|
||||
layoutParams.X, layoutParams.Y);
|
||||
|
||||
StartOverlayAnchorObserver();
|
||||
}
|
||||
|
||||
private void StartOverlayAnchorObserver()
|
||||
{
|
||||
if (_overlayAnchorObserverRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_overlayAnchorObserverRunning = true;
|
||||
_overlayAnchorObserverRunnable = new Java.Lang.Runnable(() =>
|
||||
{
|
||||
if (_overlayAnchorObserverRunning)
|
||||
{
|
||||
AdjustOverlayForScroll();
|
||||
_handler.PostDelayed(_overlayAnchorObserverRunnable, 250);
|
||||
}
|
||||
});
|
||||
|
||||
_handler.PostDelayed(_overlayAnchorObserverRunnable, 250);
|
||||
}
|
||||
|
||||
private void AdjustOverlayForScroll()
|
||||
{
|
||||
if (_overlayView == null || _anchorNode == null ||
|
||||
AccessibilityHelpers.IsAutofillServicePromptVisible(Windows))
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
return;
|
||||
}
|
||||
|
||||
var root = RootInActiveWindow;
|
||||
IEnumerable<AccessibilityWindowInfo> windows = null;
|
||||
if (Build.VERSION.SdkInt > BuildVersionCodes.Kitkat)
|
||||
{
|
||||
windows = Windows;
|
||||
}
|
||||
|
||||
var anchorPosition = AccessibilityHelpers.GetOverlayAnchorPosition(this, _anchorNode, root,
|
||||
windows, _overlayViewHeight, _isOverlayAboveAnchor);
|
||||
if (anchorPosition == null)
|
||||
{
|
||||
CancelOverlayPrompt();
|
||||
return;
|
||||
}
|
||||
else if (anchorPosition.X == -1 && anchorPosition.Y == -1)
|
||||
{
|
||||
if (_overlayView.Visibility != ViewStates.Gone)
|
||||
{
|
||||
_overlayView.Visibility = ViewStates.Gone;
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Hidden");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (anchorPosition.X == -1)
|
||||
{
|
||||
_isOverlayAboveAnchor = false;
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Below Anchor");
|
||||
return;
|
||||
}
|
||||
else if (anchorPosition.Y == -1)
|
||||
{
|
||||
_isOverlayAboveAnchor = true;
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Above Anchor");
|
||||
return;
|
||||
}
|
||||
else if (anchorPosition.X == _lastAnchorX && anchorPosition.Y == _lastAnchorY)
|
||||
{
|
||||
if (_overlayView.Visibility != ViewStates.Visible)
|
||||
{
|
||||
_overlayView.Visibility = ViewStates.Visible;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var layoutParams = AccessibilityHelpers.GetOverlayLayoutParams();
|
||||
layoutParams.X = anchorPosition.X;
|
||||
layoutParams.Y = anchorPosition.Y;
|
||||
|
||||
_lastAnchorX = anchorPosition.X;
|
||||
_lastAnchorY = anchorPosition.Y;
|
||||
|
||||
_windowManager.UpdateViewLayout(_overlayView, layoutParams);
|
||||
|
||||
if (_overlayView.Visibility != ViewStates.Visible)
|
||||
{
|
||||
_overlayView.Visibility = ViewStates.Visible;
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine(">>> Accessibility Overlay View Updated to X:{0} Y:{1}",
|
||||
layoutParams.X, layoutParams.Y);
|
||||
}
|
||||
|
||||
private bool SkipPackage(string eventPackageName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(eventPackageName) ||
|
||||
AccessibilityHelpers.FilteredPackageNames.Contains(eventPackageName) ||
|
||||
eventPackageName.Contains("launcher"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (_launcherPackageNames == null || _lastLauncherSetBuilt == null ||
|
||||
(DateTime.Now - _lastLauncherSetBuilt.Value) > _rebuildLauncherSpan)
|
||||
{
|
||||
// refresh launcher list every now and then
|
||||
_lastLauncherSetBuilt = DateTime.Now;
|
||||
var intent = new Intent(Intent.ActionMain);
|
||||
intent.AddCategory(Intent.CategoryHome);
|
||||
var resolveInfo = PackageManager.QueryIntentActivities(intent, 0);
|
||||
_launcherPackageNames = resolveInfo.Select(ri => ri.ActivityInfo.PackageName).ToHashSet();
|
||||
}
|
||||
return _launcherPackageNames.Contains(eventPackageName);
|
||||
}
|
||||
|
||||
private void LoadServices()
|
||||
{
|
||||
if (_storageService == null)
|
||||
{
|
||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
}
|
||||
if (_broadcasterService == null)
|
||||
{
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadSettingsAsync()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (_lastSettingsReload == null || (now - _lastSettingsReload.Value) > _settingsReloadSpan)
|
||||
{
|
||||
_lastSettingsReload = now;
|
||||
var uris = await _storageService.GetAsync<List<string>>(Constants.AutofillBlacklistedUrisKey);
|
||||
if (uris != null)
|
||||
{
|
||||
_blacklistedUris = new HashSet<string>(uris);
|
||||
}
|
||||
var isAutoFillTileAdded = await _storageService.GetAsync<bool?>(Constants.AutofillTileAdded);
|
||||
AccessibilityHelpers.IsAutofillTileAdded = isAutoFillTileAdded.GetValueOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Android/Accessibility/Browser.cs
Normal file
23
src/Android/Accessibility/Browser.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
public class Browser
|
||||
{
|
||||
public Browser(string packageName, string uriViewId)
|
||||
{
|
||||
PackageName = packageName;
|
||||
UriViewId = uriViewId;
|
||||
}
|
||||
|
||||
public Browser(string packageName, string uriViewId, Func<string, string> getUriFunction)
|
||||
: this(packageName, uriViewId)
|
||||
{
|
||||
GetUriFunction = getUriFunction;
|
||||
}
|
||||
|
||||
public string PackageName { get; set; }
|
||||
public string UriViewId { get; set; }
|
||||
public Func<string, string> GetUriFunction { get; set; } = (s) => s;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace Bit.App.Models.Api
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
public class SiteDataModel
|
||||
public class Credentials
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Uri { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public string Uri { get; set; }
|
||||
public string LastUri { get; set; }
|
||||
}
|
||||
}
|
||||
14
src/Android/Accessibility/KnownUsernameField.cs
Normal file
14
src/Android/Accessibility/KnownUsernameField.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
public class KnownUsernameField
|
||||
{
|
||||
public KnownUsernameField(string uriAuthority, (string UriPathWanted, string UsernameViewId)[] accessOptions)
|
||||
{
|
||||
UriAuthority = uriAuthority;
|
||||
AccessOptions = accessOptions;
|
||||
}
|
||||
|
||||
public string UriAuthority { get; set; }
|
||||
public (string UriPathWanted, string UsernameViewId)[] AccessOptions { get; set; }
|
||||
}
|
||||
}
|
||||
18
src/Android/Accessibility/NodeList.cs
Normal file
18
src/Android/Accessibility/NodeList.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Android.Views.Accessibility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bit.Droid.Accessibility
|
||||
{
|
||||
public class NodeList : List<AccessibilityNodeInfo>, IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var item in this)
|
||||
{
|
||||
item.Recycle();
|
||||
item.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,739 +1,272 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{04B18ED2-B76D-4947-8474-191F8FD2B5E0}</ProjectGuid>
|
||||
<ProjectGuid>{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Bit.Android</RootNamespace>
|
||||
<RootNamespace>Bit.Droid</RootNamespace>
|
||||
<AssemblyName>BitwardenAndroid</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AndroidApplication>true</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
|
||||
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
|
||||
<AndroidStoreUncompressedFileExtensions />
|
||||
<MandroidI18n />
|
||||
<JavaMaximumHeapSize />
|
||||
<JavaOptions />
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
<AndroidLinkSkip>Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;Microsoft.Practices.Unity;SQLite-net</AndroidLinkSkip>
|
||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||
<BundleAssemblies>False</BundleAssemblies>
|
||||
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
|
||||
<Debugger>Xamarin</Debugger>
|
||||
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
|
||||
<AndroidSupportedAbis />
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||
<AndroidLinkMode>Full</AndroidLinkMode>
|
||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||
<BundleAssemblies>False</BundleAssemblies>
|
||||
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
|
||||
<Debugger>Xamarin</Debugger>
|
||||
<AotAssemblies>False</AotAssemblies>
|
||||
<EnableLLVM>False</EnableLLVM>
|
||||
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
|
||||
<EnableProguard>False</EnableProguard>
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
<AndroidLinkSkip>PushNotification.Plugin;PushNotification.Plugin.Abstractions;Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;Microsoft.Practices.Unity;SQLite-net</AndroidLinkSkip>
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<OutputPath>bin\FDroid\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<DefineConstants>FDROID</DefineConstants>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Acr.Support.Android, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Acr.Support.2.1.0\lib\MonoAndroid10\Acr.Support.Android.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Acr.UserDialogs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Acr.UserDialogs.6.0.1\lib\MonoAndroid10\Acr.UserDialogs.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Acr.UserDialogs.Interface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Acr.UserDialogs.6.0.1\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AndHUD, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\AndHUD.1.2.0\lib\MonoAndroid\AndHUD.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BouncyCastle.Crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
|
||||
<HintPath>..\..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Forms.2.3.1.114\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HockeySDK, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0-beta3\lib\MonoAndroid403\HockeySDK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HockeySDK.AndroidBindings, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0-beta3\lib\MonoAndroid403\HockeySDK.AndroidBindings.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.Unity, Version=3.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Unity.3.5.1405-prerelease\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ModernHttpClient, Version=2.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\ModernHttpClient.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OkHttp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PCLCrypto, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d4421c8a4786956c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PCLCrypto.2.0.147\lib\MonoAndroid23\PCLCrypto.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PInvoke.BCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PInvoke.BCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PInvoke.Kernel32, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PInvoke.Kernel32.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PInvoke.NCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PInvoke.NCrypt.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PInvoke.Windows.Core, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Connectivity, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Fingerprint, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Plugin.Fingerprint.1.2.0\lib\MonoAndroid\Plugin.Fingerprint.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Fingerprint.Abstractions, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Plugin.Fingerprint.1.2.0\lib\MonoAndroid\Plugin.Fingerprint.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Settings, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Settings.Abstractions, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.2\lib\MonoAndroid10\PushNotification.Plugin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.2\lib\MonoAndroid10\PushNotification.Plugin.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\sqlite-net-pcl.1.1.2\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCL.batteries, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\SQLitePCL.bundle_green.0.9.3\lib\MonoAndroid\SQLitePCL.batteries.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCL.raw, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\SQLitePCL.raw.0.9.3\lib\MonoAndroid\SQLitePCL.raw.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLPlugin_esqlite3, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\SQLitePCL.plugin.sqlite3.android.0.9.3\lib\MonoAndroid\SQLitePCLPlugin_esqlite3.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Android.Export" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Validation, Version=2.2.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.Design, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v4, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.AppCompat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.CardView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.MediaRouter, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Forms.2.3.1.114\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Forms.2.3.1.114\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Platform.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Forms.2.3.1.114\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Forms.2.3.1.114\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Analytics, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Analytics.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Analytics.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Base, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Base.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Basement, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Basement.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Gcm, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Gcm.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Gcm.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Measurement, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Measurement.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Measurement.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="XLabs.Ioc.Unity, Version=2.0.5782.12230, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\XLabs.IoC.Unity.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.Unity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Controls\CustomSearchBarRenderer.cs" />
|
||||
<Compile Include="Controls\CustomButtonRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedButtonRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedTabbedPageRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedTableViewRenderer.cs" />
|
||||
<Compile Include="HockeyAppCrashManagerListener.cs" />
|
||||
<Compile Include="AutofillService.cs" />
|
||||
<Compile Include="Controls\ExtendedEditorRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedSwitchCellRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedViewCellRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedTextCellRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedPickerRenderer.cs" />
|
||||
<Compile Include="Controls\ExtendedEntryRenderer.cs" />
|
||||
<PackageReference Include="Plugin.CurrentActivity">
|
||||
<Version>2.1.0.4</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Portable.BouncyCastle">
|
||||
<Version>1.8.10</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.6" />
|
||||
<PackageReference Include="Xamarin.Essentials">
|
||||
<Version>1.6.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
||||
<Version>121.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.3.0.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.2.0.7" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0.7" />
|
||||
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.8" />
|
||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.2.2.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.8" />
|
||||
<PackageReference Include="Xamarin.Google.Dagger" Version="2.27.0" />
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||
<Version>117.0.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Accessibility\AccessibilityActivity.cs" />
|
||||
<Compile Include="Accessibility\AccessibilityHelpers.cs" />
|
||||
<Compile Include="Accessibility\Credentials.cs" />
|
||||
<Compile Include="Accessibility\AccessibilityService.cs" />
|
||||
<Compile Include="Accessibility\Browser.cs" />
|
||||
<Compile Include="Accessibility\NodeList.cs" />
|
||||
<Compile Include="Accessibility\KnownUsernameField.cs" />
|
||||
<Compile Include="Autofill\AutofillHelpers.cs" />
|
||||
<Compile Include="Autofill\AutofillService.cs" />
|
||||
<Compile Include="Autofill\Field.cs" />
|
||||
<Compile Include="Autofill\FieldCollection.cs" />
|
||||
<Compile Include="Autofill\FilledItem.cs" />
|
||||
<Compile Include="Autofill\Parser.cs" />
|
||||
<Compile Include="Autofill\SavedItem.cs" />
|
||||
<Compile Include="Effects\FabShadowEffect.cs" />
|
||||
<Compile Include="Effects\FixedSizeEffect.cs" />
|
||||
<Compile Include="Effects\SelectableLabelEffect.cs" />
|
||||
<Compile Include="Effects\TabBarEffect.cs" />
|
||||
<Compile Include="Push\FirebaseMessagingService.cs" />
|
||||
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
|
||||
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
|
||||
<Compile Include="Receivers\EventUploadReceiver.cs" />
|
||||
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
|
||||
<Compile Include="Renderers\ExtendedGridRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedStackLayoutRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedSliderRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEditorRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomPickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEntryRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
|
||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
||||
<Compile Include="Services\AndroidPushNotificationService.cs" />
|
||||
<Compile Include="Services\AndroidLogService.cs" />
|
||||
<Compile Include="MainApplication.cs" />
|
||||
<Compile Include="Resources\Resource.Designer.cs" />
|
||||
<Compile Include="Services\DeviceInfoService.cs" />
|
||||
<Compile Include="Services\GoogleAnalyticsService.cs" />
|
||||
<Compile Include="Services\AppInfoService.cs" />
|
||||
<Compile Include="Services\ClipboardService.cs" />
|
||||
<Compile Include="Services\BouncyCastleKeyDerivationService.cs" />
|
||||
<Compile Include="Services\KeyStoreStorageService.cs" />
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\ReflectionService.cs" />
|
||||
<Compile Include="Services\SqlService.cs" />
|
||||
<Compile Include="SplashActivity.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<AndroidResource Include="Resources\layout\tabs.axml">
|
||||
<SubType>AndroidResource</SubType>
|
||||
</AndroidResource>
|
||||
<AndroidResource Include="Resources\layout\toolbar.axml">
|
||||
<SubType>AndroidResource</SubType>
|
||||
</AndroidResource>
|
||||
<Compile Include="Services\BiometricService.cs" />
|
||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||
<Compile Include="Services\DeviceActionService.cs" />
|
||||
<Compile Include="Services\LocalizeService.cs" />
|
||||
<Compile Include="Tiles\AutofillTileService.cs" />
|
||||
<Compile Include="Tiles\GeneratorTileService.cs" />
|
||||
<Compile Include="Tiles\MyVaultTileService.cs" />
|
||||
<Compile Include="Utilities\AndroidHelpers.cs" />
|
||||
<Compile Include="Utilities\AppCenterHelper.cs" />
|
||||
<Compile Include="WebAuthCallbackActivity.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
||||
<AndroidAsset Include="Assets\RobotoMono_Regular.ttf" />
|
||||
<AndroidAsset Include="Assets\MaterialIcons_Regular.ttf" />
|
||||
<None Include="8bit.keystore.enc" />
|
||||
<GoogleServicesJson Include="google-services.json" />
|
||||
<GoogleServicesJson Include="google-services.json.enc" />
|
||||
<None Include="fdroid-keystore.jks.enc" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
<None Include="upload-keystore.jks.enc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\App\App.csproj">
|
||||
<Project>{b490c5da-639e-4994-abd2-54222b8a348e}</Project>
|
||||
<Name>App</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values-v21\styles.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\logo_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\logo_white_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\logo_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\logo_white_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo_white_legacy.png" />
|
||||
<AndroidResource Include="Resources\drawable\card.xml" />
|
||||
<AndroidResource Include="Resources\drawable\cog.xml" />
|
||||
<AndroidResource Include="Resources\drawable\icon.xml" />
|
||||
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
|
||||
<AndroidResource Include="Resources\drawable\id.xml" />
|
||||
<AndroidResource Include="Resources\drawable\info.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg_dark.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg_nord.xml" />
|
||||
<AndroidResource Include="Resources\drawable\lock.xml" />
|
||||
<AndroidResource Include="Resources\drawable\login.xml" />
|
||||
<AndroidResource Include="Resources\drawable\logo.xml" />
|
||||
<AndroidResource Include="Resources\drawable\logo_white.xml" />
|
||||
<AndroidResource Include="Resources\drawable\paper_plane.xml" />
|
||||
<AndroidResource Include="Resources\drawable\pencil.xml" />
|
||||
<AndroidResource Include="Resources\drawable\plus.xml" />
|
||||
<AndroidResource Include="Resources\drawable\refresh.xml" />
|
||||
<AndroidResource Include="Resources\drawable\search.xml" />
|
||||
<AndroidResource Include="Resources\drawable\shield.xml" />
|
||||
<AndroidResource Include="Resources\drawable-v23\splash_screen.xml" />
|
||||
<AndroidResource Include="Resources\drawable-v23\splash_screen_dark.xml" />
|
||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||
<AndroidResource Include="Resources\values-night\styles.xml" />
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\xml\accessibilityservice.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\logo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\logo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\more.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\more.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\more.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\more.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\fingerprint.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\folder.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\folder.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\folder.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\folder.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\folder.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\eye_slash.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\eye_slash.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\eye_slash.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\eye_slash.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\eye_slash.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\eye.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\eye.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\eye.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\eye.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\eye.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\user.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\user.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\user.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\user.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\user.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\lightbulb.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\lightbulb.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\lightbulb.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\lightbulb.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\lightbulb.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\envelope.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\envelope.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\envelope.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\envelope.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\envelope.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\more.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\upload.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\globe.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\cloudup.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\fingerprint.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\ion_chevron_right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ion_chevron_right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ion_chevron_right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ion_chevron_right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ion_chevron_right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\fingerprint.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\fingerprint.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\fingerprint.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\globe.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\globe.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\cloudup.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\cloudup.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\upload.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\upload.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\cloudup.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\upload.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\globe.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\cloudup.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\upload.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\globe.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\splash_screen.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\tools_selected.png" />
|
||||
<ProjectReference Include="..\App\App.csproj">
|
||||
<Project>{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}</Project>
|
||||
<Name>App</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Core\Core.csproj">
|
||||
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
||||
<Name>Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\cogs_selected.png" />
|
||||
<AndroidResource Include="Resources\xml\accessibilityservice.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\fa_lock_selected.png" />
|
||||
<AndroidResource Include="Resources\xml\autofillservice.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\star_selected.png" />
|
||||
<AndroidResource Include="Resources\xml\filepaths.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\fa_lock_selected.png" />
|
||||
<AndroidResource Include="Resources\xml\network_security_config.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\star_selected.png" />
|
||||
<AndroidResource Include="Resources\values\strings.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\cogs_selected.png" />
|
||||
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\cogs_selected.png" />
|
||||
<AndroidResource Include="Resources\layout\autofill_listitem.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\fa_lock_selected.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\yubikey.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\star_selected.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\yubikey.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\cogs_selected.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\yubikey.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\fa_lock_selected.png" />
|
||||
<AndroidResource Include="Resources\drawable\slider_thumb.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\star_selected.png" />
|
||||
<AndroidResource Include="Resources\drawable\splash_screen_dark.xml">
|
||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\fa_lock_selected.png" />
|
||||
<AndroidResource Include="Resources\values\dimens.xml">
|
||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\star_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\cogs_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\tools_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\tools_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\tools_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\tools_selected.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\cogs.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\cogs.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\cogs.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\cogs.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\cogs.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\star.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\fa_lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\star.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\fa_lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\star.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\fa_lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\star.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\fa_lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\fa_lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\star.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\tools.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\tools.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\tools.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\tools.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\tools.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\list_selector.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
||||
<AndroidResource Include="Resources\xml\app_restrictions.xml">
|
||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.1.114\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.1.114\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets" Condition="Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" />
|
||||
<Import Project="..\..\packages\Xamarin.Forms.2.3.1.114\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.1.114\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||
|
||||
These files will be deployed with you package and will be accessible using Android's
|
||||
AssetManager, like this:
|
||||
|
||||
public class ReadAsset : Activity
|
||||
{
|
||||
protected override void OnCreate (Bundle bundle)
|
||||
{
|
||||
base.OnCreate (bundle);
|
||||
|
||||
InputStream input = Assets.Open ("my_asset.txt");
|
||||
}
|
||||
}
|
||||
|
||||
Additionally, some Android functions will automatically load asset files:
|
||||
|
||||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
||||
BIN
src/Android/Assets/FontAwesome.ttf
Normal file
BIN
src/Android/Assets/FontAwesome.ttf
Normal file
Binary file not shown.
BIN
src/Android/Assets/MaterialIcons_Regular.ttf
Normal file
BIN
src/Android/Assets/MaterialIcons_Regular.ttf
Normal file
Binary file not shown.
BIN
src/Android/Assets/RobotoMono_Regular.ttf
Normal file
BIN
src/Android/Assets/RobotoMono_Regular.ttf
Normal file
Binary file not shown.
411
src/Android/Autofill/AutofillHelpers.cs
Normal file
411
src/Android/Autofill/AutofillHelpers.cs
Normal file
@@ -0,0 +1,411 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Android.Content;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Widget;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App.Slices;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Widget.Inline;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Enums;
|
||||
using Android.Views.Autofill;
|
||||
using AndroidX.AutoFill.Inline;
|
||||
using AndroidX.AutoFill.Inline.V1;
|
||||
using Bit.Core.Abstractions;
|
||||
using SaveFlags = Android.Service.Autofill.SaveFlags;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public static class AutofillHelpers
|
||||
{
|
||||
private static int _pendingIntentId = 0;
|
||||
|
||||
// These browsers work natively with the Autofill Framework
|
||||
//
|
||||
// Be sure:
|
||||
// - to keep these entries sorted alphabetically and
|
||||
//
|
||||
// - ... to keep this list in sync with values in AccessibilityHelpers.SupportedBrowsers [Section A], too.
|
||||
public static HashSet<string> TrustedBrowsers = new HashSet<string>
|
||||
{
|
||||
"com.duckduckgo.mobile.android",
|
||||
"org.mozilla.focus",
|
||||
"org.mozilla.klar",
|
||||
};
|
||||
|
||||
// These browsers work using the compatibility shim for the Autofill Framework
|
||||
//
|
||||
// Be sure:
|
||||
// - to keep these entries sorted alphabetically,
|
||||
// - to keep this list in sync with values in Resources/xml/autofillservice.xml, and
|
||||
//
|
||||
// - ... to keep this list in sync with values in AccessibilityHelpers.SupportedBrowsers [Section A], too.
|
||||
public static HashSet<string> CompatBrowsers = new HashSet<string>
|
||||
{
|
||||
"alook.browser",
|
||||
"com.amazon.cloud9",
|
||||
"com.android.browser",
|
||||
"com.android.chrome",
|
||||
"com.android.htmlviewer",
|
||||
"com.avast.android.secure.browser",
|
||||
"com.avg.android.secure.browser",
|
||||
"com.brave.browser",
|
||||
"com.brave.browser_beta",
|
||||
"com.brave.browser_default",
|
||||
"com.brave.browser_dev",
|
||||
"com.brave.browser_nightly",
|
||||
"com.chrome.beta",
|
||||
"com.chrome.canary",
|
||||
"com.chrome.dev",
|
||||
"com.cookiegames.smartcookie",
|
||||
"com.cookiejarapps.android.smartcookieweb",
|
||||
"com.ecosia.android",
|
||||
"com.google.android.apps.chrome",
|
||||
"com.google.android.apps.chrome_dev",
|
||||
"com.jamal2367.styx",
|
||||
"com.kiwibrowser.browser",
|
||||
"com.microsoft.emmx",
|
||||
"com.microsoft.emmx.beta",
|
||||
"com.microsoft.emmx.canary",
|
||||
"com.microsoft.emmx.dev",
|
||||
"com.mmbox.browser",
|
||||
"com.mmbox.xbrowser",
|
||||
"com.mycompany.app.soulbrowser",
|
||||
"com.naver.whale",
|
||||
"com.opera.browser",
|
||||
"com.opera.browser.beta",
|
||||
"com.opera.mini.native",
|
||||
"com.opera.mini.native.beta",
|
||||
"com.opera.touch",
|
||||
"com.qwant.liberty",
|
||||
"com.sec.android.app.sbrowser",
|
||||
"com.sec.android.app.sbrowser.beta",
|
||||
"com.stoutner.privacybrowser.free",
|
||||
"com.stoutner.privacybrowser.standard",
|
||||
"com.vivaldi.browser",
|
||||
"com.vivaldi.browser.snapshot",
|
||||
"com.vivaldi.browser.sopranos",
|
||||
"com.yandex.browser",
|
||||
"com.z28j.feel",
|
||||
"idm.internet.download.manager",
|
||||
"idm.internet.download.manager.adm.lite",
|
||||
"idm.internet.download.manager.plus",
|
||||
"io.github.forkmaintainers.iceraven",
|
||||
"mark.via",
|
||||
"mark.via.gp",
|
||||
"net.slions.fulguris.full.download",
|
||||
"net.slions.fulguris.full.download.debug",
|
||||
"net.slions.fulguris.full.playstore",
|
||||
"net.slions.fulguris.full.playstore.debug",
|
||||
"org.adblockplus.browser",
|
||||
"org.adblockplus.browser.beta",
|
||||
"org.bromite.bromite",
|
||||
"org.bromite.chromium",
|
||||
"org.chromium.chrome",
|
||||
"org.codeaurora.swe.browser",
|
||||
"org.gnu.icecat",
|
||||
"org.mozilla.fenix",
|
||||
"org.mozilla.fenix.nightly",
|
||||
"org.mozilla.fennec_aurora",
|
||||
"org.mozilla.fennec_fdroid",
|
||||
"org.mozilla.firefox",
|
||||
"org.mozilla.firefox_beta",
|
||||
"org.mozilla.reference.browser",
|
||||
"org.mozilla.rocket",
|
||||
"org.torproject.torbrowser",
|
||||
"org.torproject.torbrowser_alpha",
|
||||
"org.ungoogled.chromium.extensions.stable",
|
||||
"org.ungoogled.chromium.stable",
|
||||
};
|
||||
|
||||
// The URLs are blacklisted from autofilling
|
||||
public static HashSet<string> BlacklistedUris = new HashSet<string>
|
||||
{
|
||||
"androidapp://android",
|
||||
"androidapp://com.android.settings",
|
||||
"androidapp://com.x8bit.bitwarden",
|
||||
"androidapp://com.oneplus.applocker",
|
||||
};
|
||||
|
||||
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService cipherService)
|
||||
{
|
||||
if (parser.FieldCollection.FillableForLogin)
|
||||
{
|
||||
var ciphers = await cipherService.GetAllDecryptedByUrlAsync(parser.Uri);
|
||||
if (ciphers.Item1.Any() || ciphers.Item2.Any())
|
||||
{
|
||||
var allCiphers = ciphers.Item1.ToList();
|
||||
allCiphers.AddRange(ciphers.Item2.ToList());
|
||||
var nonPromptCiphers = allCiphers.Where(cipher => cipher.Reprompt == CipherRepromptType.None);
|
||||
return nonPromptCiphers.Select(c => new FilledItem(c)).ToList();
|
||||
}
|
||||
}
|
||||
else if (parser.FieldCollection.FillableForCard)
|
||||
{
|
||||
var ciphers = await cipherService.GetAllDecryptedAsync();
|
||||
return ciphers.Where(c => c.Type == CipherType.Card && c.Reprompt == CipherRepromptType.None).Select(c => new FilledItem(c)).ToList();
|
||||
}
|
||||
return new List<FilledItem>();
|
||||
}
|
||||
|
||||
public static FillResponse BuildFillResponse(Parser parser, List<FilledItem> items, bool locked,
|
||||
bool inlineAutofillEnabled, FillRequest fillRequest = null)
|
||||
{
|
||||
// Acquire inline presentation specs on Android 11+
|
||||
IList<InlinePresentationSpec> inlinePresentationSpecs = null;
|
||||
var inlinePresentationSpecsCount = 0;
|
||||
var inlineMaxSuggestedCount = 0;
|
||||
if (inlineAutofillEnabled && fillRequest != null && (int)Build.VERSION.SdkInt >= 30)
|
||||
{
|
||||
var inlineSuggestionsRequest = fillRequest.InlineSuggestionsRequest;
|
||||
inlineMaxSuggestedCount = inlineSuggestionsRequest?.MaxSuggestionCount ?? 0;
|
||||
inlinePresentationSpecs = inlineSuggestionsRequest?.InlinePresentationSpecs;
|
||||
inlinePresentationSpecsCount = inlinePresentationSpecs?.Count ?? 0;
|
||||
}
|
||||
|
||||
// Build response
|
||||
var responseBuilder = new FillResponse.Builder();
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
var maxItems = items.Count;
|
||||
if (inlineMaxSuggestedCount > 0)
|
||||
{
|
||||
// -1 to adjust for 'open vault' option
|
||||
maxItems = Math.Min(maxItems, inlineMaxSuggestedCount - 1);
|
||||
}
|
||||
for (int i = 0; i < maxItems; i++)
|
||||
{
|
||||
InlinePresentationSpec inlinePresentationSpec = null;
|
||||
if (inlinePresentationSpecs != null)
|
||||
{
|
||||
if (i < inlinePresentationSpecsCount)
|
||||
{
|
||||
inlinePresentationSpec = inlinePresentationSpecs[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the max suggestion count is larger than the number of specs in the list, then
|
||||
// the last spec is used for the remainder of the suggestions
|
||||
inlinePresentationSpec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1];
|
||||
}
|
||||
}
|
||||
var dataset = BuildDataset(parser.ApplicationContext, parser.FieldCollection, items[i],
|
||||
inlinePresentationSpec);
|
||||
if (dataset != null)
|
||||
{
|
||||
responseBuilder.AddDataset(dataset);
|
||||
}
|
||||
}
|
||||
}
|
||||
responseBuilder.AddDataset(BuildVaultDataset(parser.ApplicationContext, parser.FieldCollection,
|
||||
parser.Uri, locked, inlinePresentationSpecs));
|
||||
AddSaveInfo(parser, fillRequest, responseBuilder, parser.FieldCollection);
|
||||
responseBuilder.SetIgnoredIds(parser.FieldCollection.IgnoreAutofillIds.ToArray());
|
||||
return responseBuilder.Build();
|
||||
}
|
||||
|
||||
public static Dataset BuildDataset(Context context, FieldCollection fields, FilledItem filledItem,
|
||||
InlinePresentationSpec inlinePresentationSpec = null)
|
||||
{
|
||||
var overlayPresentation = BuildOverlayPresentation(
|
||||
filledItem.Name,
|
||||
filledItem.Subtitle,
|
||||
filledItem.Icon,
|
||||
context);
|
||||
|
||||
var inlinePresentation = BuildInlinePresentation(
|
||||
inlinePresentationSpec,
|
||||
filledItem.Name,
|
||||
filledItem.Subtitle,
|
||||
filledItem.Icon,
|
||||
null,
|
||||
context);
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(overlayPresentation);
|
||||
if (inlinePresentation != null)
|
||||
{
|
||||
datasetBuilder.SetInlinePresentation(inlinePresentation);
|
||||
}
|
||||
if (filledItem.ApplyToFields(fields, datasetBuilder))
|
||||
{
|
||||
return datasetBuilder.Build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Dataset BuildVaultDataset(Context context, FieldCollection fields, string uri, bool locked,
|
||||
IList<InlinePresentationSpec> inlinePresentationSpecs = null)
|
||||
{
|
||||
var intent = new Intent(context, typeof(MainActivity));
|
||||
intent.PutExtra("autofillFramework", true);
|
||||
if (fields.FillableForLogin)
|
||||
{
|
||||
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Login);
|
||||
}
|
||||
else if (fields.FillableForCard)
|
||||
{
|
||||
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Card);
|
||||
}
|
||||
else if (fields.FillableForIdentity)
|
||||
{
|
||||
intent.PutExtra("autofillFrameworkFillType", (int)CipherType.Identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
intent.PutExtra("autofillFrameworkUri", uri);
|
||||
var pendingIntent = PendingIntent.GetActivity(context, ++_pendingIntentId, intent,
|
||||
PendingIntentFlags.CancelCurrent);
|
||||
|
||||
var overlayPresentation = BuildOverlayPresentation(
|
||||
AppResources.AutofillWithBitwarden,
|
||||
locked ? AppResources.VaultIsLocked : AppResources.GoToMyVault,
|
||||
Resource.Drawable.icon,
|
||||
context);
|
||||
|
||||
var inlinePresentation = BuildInlinePresentation(
|
||||
inlinePresentationSpecs?.Last(),
|
||||
AppResources.Bitwarden,
|
||||
locked ? AppResources.VaultIsLocked : AppResources.MyVault,
|
||||
Resource.Drawable.icon,
|
||||
pendingIntent,
|
||||
context);
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(overlayPresentation);
|
||||
if (inlinePresentation != null)
|
||||
{
|
||||
datasetBuilder.SetInlinePresentation(inlinePresentation);
|
||||
}
|
||||
datasetBuilder.SetAuthentication(pendingIntent?.IntentSender);
|
||||
|
||||
// Dataset must have a value set. We will reset this in the main activity when the real item is chosen.
|
||||
foreach (var autofillId in fields.AutofillIds)
|
||||
{
|
||||
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
|
||||
}
|
||||
return datasetBuilder.Build();
|
||||
}
|
||||
|
||||
public static RemoteViews BuildOverlayPresentation(string text, string subtext, int iconId, Context context)
|
||||
{
|
||||
var packageName = context.PackageName;
|
||||
var view = new RemoteViews(packageName, Resource.Layout.autofill_listitem);
|
||||
view.SetTextViewText(Resource.Id.text1, text);
|
||||
view.SetTextViewText(Resource.Id.text2, subtext);
|
||||
view.SetImageViewResource(Resource.Id.icon, iconId);
|
||||
return view;
|
||||
}
|
||||
|
||||
public static InlinePresentation BuildInlinePresentation(InlinePresentationSpec inlinePresentationSpec,
|
||||
string text, string subtext, int iconId, PendingIntent pendingIntent, Context context)
|
||||
{
|
||||
if ((int)Build.VERSION.SdkInt < 30 || inlinePresentationSpec == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (pendingIntent == null)
|
||||
{
|
||||
// InlinePresentation requires nonNull pending intent (even though we only utilize one for the
|
||||
// "my vault" presentation) so we're including an empty one here
|
||||
pendingIntent = PendingIntent.GetService(context, 0, new Intent(),
|
||||
PendingIntentFlags.OneShot | PendingIntentFlags.UpdateCurrent);
|
||||
}
|
||||
var slice = CreateInlinePresentationSlice(
|
||||
inlinePresentationSpec,
|
||||
text,
|
||||
subtext,
|
||||
iconId,
|
||||
"Autofill option",
|
||||
pendingIntent,
|
||||
context);
|
||||
if (slice != null)
|
||||
{
|
||||
return new InlinePresentation(slice, inlinePresentationSpec, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Slice CreateInlinePresentationSlice(
|
||||
InlinePresentationSpec inlinePresentationSpec,
|
||||
string text,
|
||||
string subtext,
|
||||
int iconId,
|
||||
string contentDescription,
|
||||
PendingIntent pendingIntent,
|
||||
Context context)
|
||||
{
|
||||
var imeStyle = inlinePresentationSpec.Style;
|
||||
if (!UiVersions.GetVersions(imeStyle).Contains(UiVersions.InlineUiVersion1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var contentBuilder = InlineSuggestionUi.NewContentBuilder(pendingIntent)
|
||||
.SetContentDescription(contentDescription);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
contentBuilder.SetTitle(text);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(subtext))
|
||||
{
|
||||
contentBuilder.SetSubtitle(subtext);
|
||||
}
|
||||
if (iconId > 0)
|
||||
{
|
||||
var icon = Icon.CreateWithResource(context, iconId);
|
||||
if (icon != null)
|
||||
{
|
||||
if (iconId == Resource.Drawable.icon)
|
||||
{
|
||||
// Don't tint our logo
|
||||
icon.SetTintBlendMode(BlendMode.Dst);
|
||||
}
|
||||
contentBuilder.SetStartIcon(icon);
|
||||
}
|
||||
}
|
||||
return contentBuilder.Build().JavaCast<InlineSuggestionUi.Content>()?.Slice;
|
||||
}
|
||||
|
||||
public static void AddSaveInfo(Parser parser, FillRequest fillRequest, FillResponse.Builder responseBuilder,
|
||||
FieldCollection fields)
|
||||
{
|
||||
// Docs state that password fields cannot be reliably saved in Compat mode since they will show as
|
||||
// masked values.
|
||||
bool? compatRequest = null;
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q && fillRequest != null)
|
||||
{
|
||||
// Attempt to automatically establish compat request mode on Android 10+
|
||||
compatRequest = (fillRequest.Flags | FillRequest.FlagCompatibilityModeRequest) == fillRequest.Flags;
|
||||
}
|
||||
var compatBrowser = compatRequest ?? CompatBrowsers.Contains(parser.PackageName);
|
||||
if (compatBrowser && fields.SaveType == SaveDataType.Password)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requiredIds = fields.GetRequiredSaveFields();
|
||||
if (fields.SaveType == SaveDataType.Generic || requiredIds.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var saveBuilder = new SaveInfo.Builder(fields.SaveType, requiredIds);
|
||||
var optionalIds = fields.GetOptionalSaveIds();
|
||||
if (optionalIds.Length > 0)
|
||||
{
|
||||
saveBuilder.SetOptionalIds(optionalIds);
|
||||
}
|
||||
if (compatBrowser)
|
||||
{
|
||||
saveBuilder.SetFlags(SaveFlags.SaveOnAllViewsInvisible);
|
||||
}
|
||||
responseBuilder.SetSaveInfo(saveBuilder.Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
155
src/Android/Autofill/AutofillService.cs
Normal file
155
src/Android/Autofill/AutofillService.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using Android;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Widget;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
[Service(Permission = Manifest.Permission.BindAutofillService, Label = "Bitwarden")]
|
||||
[IntentFilter(new string[] { "android.service.autofill.AutofillService" })]
|
||||
[MetaData("android.autofill", Resource = "@xml/autofillservice")]
|
||||
[Register("com.x8bit.bitwarden.Autofill.AutofillService")]
|
||||
public class AutofillService : Android.Service.Autofill.AutofillService
|
||||
{
|
||||
private ICipherService _cipherService;
|
||||
private IVaultTimeoutService _vaultTimeoutService;
|
||||
private IStorageService _storageService;
|
||||
private IPolicyService _policyService;
|
||||
private IUserService _userService;
|
||||
|
||||
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
|
||||
FillCallback callback)
|
||||
{
|
||||
var structure = request.FillContexts?.LastOrDefault()?.Structure;
|
||||
if (structure == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parser = new Parser(structure, ApplicationContext);
|
||||
parser.Parse();
|
||||
|
||||
if (_storageService == null)
|
||||
{
|
||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
}
|
||||
|
||||
var shouldAutofill = await parser.ShouldAutofillAsync(_storageService);
|
||||
if (!shouldAutofill)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var inlineAutofillEnabled = await _storageService.GetAsync<bool?>(Constants.InlineAutofillEnabledKey) ?? true;
|
||||
|
||||
if (_vaultTimeoutService == null)
|
||||
{
|
||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||
}
|
||||
|
||||
List<FilledItem> items = null;
|
||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
||||
var locked = await _vaultTimeoutService.IsLockedAsync();
|
||||
if (!locked)
|
||||
{
|
||||
if (_cipherService == null)
|
||||
{
|
||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||
}
|
||||
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService);
|
||||
}
|
||||
|
||||
// build response
|
||||
var response = AutofillHelpers.BuildFillResponse(parser, items, locked, inlineAutofillEnabled, request);
|
||||
callback.OnSuccess(response);
|
||||
}
|
||||
|
||||
public async override void OnSaveRequest(SaveRequest request, SaveCallback callback)
|
||||
{
|
||||
var structure = request.FillContexts?.LastOrDefault()?.Structure;
|
||||
if (structure == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_storageService == null)
|
||||
{
|
||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
}
|
||||
|
||||
var disableSavePrompt = await _storageService.GetAsync<bool?>(Constants.AutofillDisableSavePromptKey);
|
||||
if (disableSavePrompt.GetValueOrDefault())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_policyService ??= ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||
|
||||
var personalOwnershipPolicies = await _policyService.GetAll(PolicyType.PersonalOwnership);
|
||||
if (personalOwnershipPolicies != null)
|
||||
{
|
||||
_userService ??= ServiceContainer.Resolve<IUserService>("userService");
|
||||
foreach (var policy in personalOwnershipPolicies)
|
||||
{
|
||||
if (policy.Enabled)
|
||||
{
|
||||
var org = await _userService.GetOrganizationAsync(policy.OrganizationId);
|
||||
if (org != null && org.Enabled && org.UsePolicies && !org.canManagePolicies
|
||||
&& org.Status == OrganizationUserStatusType.Confirmed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parser = new Parser(structure, ApplicationContext);
|
||||
parser.Parse();
|
||||
|
||||
var savedItem = parser.FieldCollection.GetSavedItem();
|
||||
if (savedItem == null)
|
||||
{
|
||||
Toast.MakeText(this, "Unable to save this form.", ToastLength.Short).Show();
|
||||
return;
|
||||
}
|
||||
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop);
|
||||
intent.PutExtra("autofillFramework", true);
|
||||
intent.PutExtra("autofillFrameworkSave", true);
|
||||
intent.PutExtra("autofillFrameworkType", (int)savedItem.Type);
|
||||
switch (savedItem.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
intent.PutExtra("autofillFrameworkName", parser.Uri
|
||||
.Replace(Constants.AndroidAppProtocol, string.Empty)
|
||||
.Replace("https://", string.Empty)
|
||||
.Replace("http://", string.Empty));
|
||||
intent.PutExtra("autofillFrameworkUri", parser.Uri);
|
||||
intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username);
|
||||
intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password);
|
||||
break;
|
||||
case CipherType.Card:
|
||||
intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name);
|
||||
intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number);
|
||||
intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth);
|
||||
intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear);
|
||||
intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code);
|
||||
break;
|
||||
default:
|
||||
Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show();
|
||||
return;
|
||||
}
|
||||
StartActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
195
src/Android/Autofill/Field.cs
Normal file
195
src/Android/Autofill/Field.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Views;
|
||||
using Android.Views.Autofill;
|
||||
using static Android.App.Assist.AssistStructure;
|
||||
using Android.Text;
|
||||
using static Android.Views.ViewStructure;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
private List<string> _hints;
|
||||
|
||||
public Field(ViewNode node)
|
||||
{
|
||||
Id = node.Id;
|
||||
TrackingId = $"{node.Id}_{node.GetHashCode()}";
|
||||
IdEntry = node.IdEntry;
|
||||
AutofillId = node.AutofillId;
|
||||
AutofillType = node.AutofillType;
|
||||
InputType = node.InputType;
|
||||
Focused = node.IsFocused;
|
||||
Selected = node.IsSelected;
|
||||
Clickable = node.IsClickable;
|
||||
Visible = node.Visibility == ViewStates.Visible;
|
||||
Hints = FilterForSupportedHints(node.GetAutofillHints());
|
||||
Hint = node.Hint;
|
||||
AutofillOptions = node.GetAutofillOptions()?.ToList();
|
||||
HtmlInfo = node.HtmlInfo;
|
||||
Node = node;
|
||||
|
||||
if (node.AutofillValue != null)
|
||||
{
|
||||
if (node.AutofillValue.IsList)
|
||||
{
|
||||
var autofillOptions = node.GetAutofillOptions();
|
||||
if (autofillOptions != null && autofillOptions.Length > 0)
|
||||
{
|
||||
ListValue = node.AutofillValue.ListValue;
|
||||
TextValue = autofillOptions[node.AutofillValue.ListValue];
|
||||
}
|
||||
}
|
||||
else if (node.AutofillValue.IsDate)
|
||||
{
|
||||
DateValue = node.AutofillValue.DateValue;
|
||||
}
|
||||
else if (node.AutofillValue.IsText)
|
||||
{
|
||||
TextValue = node.AutofillValue.TextValue;
|
||||
}
|
||||
else if (node.AutofillValue.IsToggle)
|
||||
{
|
||||
ToggleValue = node.AutofillValue.ToggleValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SaveDataType SaveType { get; set; } = SaveDataType.Generic;
|
||||
public List<string> Hints
|
||||
{
|
||||
get => _hints;
|
||||
set
|
||||
{
|
||||
_hints = value;
|
||||
UpdateSaveTypeFromHints();
|
||||
}
|
||||
}
|
||||
public string Hint { get; set; }
|
||||
public int Id { get; private set; }
|
||||
public string TrackingId { get; private set; }
|
||||
public string IdEntry { get; set; }
|
||||
public AutofillId AutofillId { get; private set; }
|
||||
public AutofillType AutofillType { get; private set; }
|
||||
public InputTypes InputType { get; private set; }
|
||||
public bool Focused { get; private set; }
|
||||
public bool Selected { get; private set; }
|
||||
public bool Clickable { get; private set; }
|
||||
public bool Visible { get; private set; }
|
||||
public List<string> AutofillOptions { get; set; }
|
||||
public string TextValue { get; set; }
|
||||
public long? DateValue { get; set; }
|
||||
public int? ListValue { get; set; }
|
||||
public bool? ToggleValue { get; set; }
|
||||
public HtmlInfo HtmlInfo { get; private set; }
|
||||
public ViewNode Node { get; private set; }
|
||||
|
||||
public bool ValueIsNull()
|
||||
{
|
||||
return TextValue == null && DateValue == null && ToggleValue == null;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var field = obj as Field;
|
||||
if (TextValue != null ? !TextValue.Equals(field.TextValue) : field.TextValue != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (DateValue != null ? !DateValue.Equals(field.DateValue) : field.DateValue != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ToggleValue != null ? ToggleValue.Equals(field.ToggleValue) : field.ToggleValue == null;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var result = TextValue != null ? TextValue.GetHashCode() : 0;
|
||||
result = 31 * result + (DateValue != null ? DateValue.GetHashCode() : 0);
|
||||
result = 31 * result + (ToggleValue != null ? ToggleValue.GetHashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<string> FilterForSupportedHints(string[] hints)
|
||||
{
|
||||
return hints?.Where(h => IsValidHint(h)).ToList() ?? new List<string>();
|
||||
}
|
||||
|
||||
private static bool IsValidHint(string hint)
|
||||
{
|
||||
switch (hint)
|
||||
{
|
||||
case View.AutofillHintCreditCardExpirationDate:
|
||||
case View.AutofillHintCreditCardExpirationDay:
|
||||
case View.AutofillHintCreditCardExpirationMonth:
|
||||
case View.AutofillHintCreditCardExpirationYear:
|
||||
case View.AutofillHintCreditCardNumber:
|
||||
case View.AutofillHintCreditCardSecurityCode:
|
||||
case View.AutofillHintEmailAddress:
|
||||
case View.AutofillHintPhone:
|
||||
case View.AutofillHintName:
|
||||
case View.AutofillHintPassword:
|
||||
case View.AutofillHintPostalAddress:
|
||||
case View.AutofillHintPostalCode:
|
||||
case View.AutofillHintUsername:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSaveTypeFromHints()
|
||||
{
|
||||
SaveType = SaveDataType.Generic;
|
||||
if (_hints == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var hint in _hints)
|
||||
{
|
||||
switch (hint)
|
||||
{
|
||||
case View.AutofillHintCreditCardExpirationDate:
|
||||
case View.AutofillHintCreditCardExpirationDay:
|
||||
case View.AutofillHintCreditCardExpirationMonth:
|
||||
case View.AutofillHintCreditCardExpirationYear:
|
||||
case View.AutofillHintCreditCardNumber:
|
||||
case View.AutofillHintCreditCardSecurityCode:
|
||||
SaveType |= SaveDataType.CreditCard;
|
||||
break;
|
||||
case View.AutofillHintEmailAddress:
|
||||
SaveType |= SaveDataType.EmailAddress;
|
||||
break;
|
||||
case View.AutofillHintPhone:
|
||||
case View.AutofillHintName:
|
||||
SaveType |= SaveDataType.Generic;
|
||||
break;
|
||||
case View.AutofillHintPassword:
|
||||
SaveType |= SaveDataType.Password;
|
||||
SaveType &= ~SaveDataType.EmailAddress;
|
||||
SaveType &= ~SaveDataType.Username;
|
||||
break;
|
||||
case View.AutofillHintPostalAddress:
|
||||
case View.AutofillHintPostalCode:
|
||||
SaveType |= SaveDataType.Address;
|
||||
break;
|
||||
case View.AutofillHintUsername:
|
||||
SaveType |= SaveDataType.Username;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
342
src/Android/Autofill/FieldCollection.cs
Normal file
342
src/Android/Autofill/FieldCollection.cs
Normal file
@@ -0,0 +1,342 @@
|
||||
using System.Collections.Generic;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Views.Autofill;
|
||||
using System.Linq;
|
||||
using Android.Text;
|
||||
using Android.Views;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class FieldCollection
|
||||
{
|
||||
private List<Field> _passwordFields = null;
|
||||
private List<Field> _usernameFields = null;
|
||||
private HashSet<string> _ignoreSearchTerms = new HashSet<string> { "search", "find", "recipient", "edit" };
|
||||
private HashSet<string> _passwordTerms = new HashSet<string> { "password", "pswd" };
|
||||
|
||||
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
|
||||
public SaveDataType SaveType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FillableForLogin)
|
||||
{
|
||||
return SaveDataType.Password;
|
||||
}
|
||||
else if (FillableForCard)
|
||||
{
|
||||
return SaveDataType.CreditCard;
|
||||
}
|
||||
|
||||
return SaveDataType.Generic;
|
||||
}
|
||||
}
|
||||
public HashSet<string> Hints { get; private set; } = new HashSet<string>();
|
||||
public HashSet<string> FocusedHints { get; private set; } = new HashSet<string>();
|
||||
public HashSet<string> FieldTrackingIds { get; private set; } = new HashSet<string>();
|
||||
public List<Field> Fields { get; private set; } = new List<Field>();
|
||||
public IDictionary<string, List<Field>> HintToFieldsMap { get; private set; } =
|
||||
new Dictionary<string, List<Field>>();
|
||||
public List<AutofillId> IgnoreAutofillIds { get; private set; } = new List<AutofillId>();
|
||||
|
||||
public List<Field> PasswordFields
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_passwordFields != null)
|
||||
{
|
||||
return _passwordFields;
|
||||
}
|
||||
if (Hints.Any())
|
||||
{
|
||||
_passwordFields = new List<Field>();
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintPassword))
|
||||
{
|
||||
_passwordFields.AddRange(HintToFieldsMap[View.AutofillHintPassword]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
|
||||
if (!_passwordFields.Any())
|
||||
{
|
||||
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
||||
}
|
||||
}
|
||||
return _passwordFields;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Field> UsernameFields
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_usernameFields != null)
|
||||
{
|
||||
return _usernameFields;
|
||||
}
|
||||
_usernameFields = new List<Field>();
|
||||
if (Hints.Any())
|
||||
{
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintEmailAddress))
|
||||
{
|
||||
_usernameFields.AddRange(HintToFieldsMap[View.AutofillHintEmailAddress]);
|
||||
}
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintUsername))
|
||||
{
|
||||
_usernameFields.AddRange(HintToFieldsMap[View.AutofillHintUsername]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var passwordField in PasswordFields)
|
||||
{
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
|
||||
.LastOrDefault();
|
||||
if (usernameField != null)
|
||||
{
|
||||
_usernameFields.Add(usernameField);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _usernameFields;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FillableForLogin => FocusedHintsContain(new string[] {
|
||||
View.AutofillHintUsername,
|
||||
View.AutofillHintEmailAddress,
|
||||
View.AutofillHintPassword
|
||||
}) || UsernameFields.Any(f => f.Focused) || PasswordFields.Any(f => f.Focused);
|
||||
|
||||
public bool FillableForCard => FocusedHintsContain(new string[] {
|
||||
View.AutofillHintCreditCardNumber,
|
||||
View.AutofillHintCreditCardExpirationMonth,
|
||||
View.AutofillHintCreditCardExpirationYear,
|
||||
View.AutofillHintCreditCardSecurityCode
|
||||
});
|
||||
|
||||
public bool FillableForIdentity => FocusedHintsContain(new string[] {
|
||||
View.AutofillHintName,
|
||||
View.AutofillHintPhone,
|
||||
View.AutofillHintPostalAddress,
|
||||
View.AutofillHintPostalCode
|
||||
});
|
||||
|
||||
public bool Fillable => FillableForLogin || FillableForCard || FillableForIdentity;
|
||||
|
||||
public void Add(Field field)
|
||||
{
|
||||
if (field == null || FieldTrackingIds.Contains(field.TrackingId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_passwordFields = _usernameFields = null;
|
||||
FieldTrackingIds.Add(field.TrackingId);
|
||||
Fields.Add(field);
|
||||
AutofillIds.Add(field.AutofillId);
|
||||
|
||||
if (field.Hints != null)
|
||||
{
|
||||
foreach (var hint in field.Hints)
|
||||
{
|
||||
Hints.Add(hint);
|
||||
if (field.Focused)
|
||||
{
|
||||
FocusedHints.Add(hint);
|
||||
}
|
||||
if (!HintToFieldsMap.ContainsKey(hint))
|
||||
{
|
||||
HintToFieldsMap.Add(hint, new List<Field>());
|
||||
}
|
||||
HintToFieldsMap[hint].Add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SavedItem GetSavedItem()
|
||||
{
|
||||
if (SaveType == SaveDataType.Password)
|
||||
{
|
||||
var passwordField = PasswordFields.FirstOrDefault(f => !string.IsNullOrWhiteSpace(f.TextValue));
|
||||
if (passwordField == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var savedItem = new SavedItem
|
||||
{
|
||||
Type = Core.Enums.CipherType.Login,
|
||||
Login = new SavedItem.LoginItem
|
||||
{
|
||||
Password = GetFieldValue(passwordField)
|
||||
}
|
||||
};
|
||||
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
|
||||
savedItem.Login.Username = GetFieldValue(usernameField);
|
||||
return savedItem;
|
||||
}
|
||||
else if (SaveType == SaveDataType.CreditCard)
|
||||
{
|
||||
var savedItem = new SavedItem
|
||||
{
|
||||
Type = Core.Enums.CipherType.Card,
|
||||
Card = new SavedItem.CardItem
|
||||
{
|
||||
Number = GetFieldValue(View.AutofillHintCreditCardNumber),
|
||||
Name = GetFieldValue(View.AutofillHintName),
|
||||
ExpMonth = GetFieldValue(View.AutofillHintCreditCardExpirationMonth, true),
|
||||
ExpYear = GetFieldValue(View.AutofillHintCreditCardExpirationYear),
|
||||
Code = GetFieldValue(View.AutofillHintCreditCardSecurityCode)
|
||||
}
|
||||
};
|
||||
return savedItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public AutofillId[] GetOptionalSaveIds()
|
||||
{
|
||||
if (SaveType == SaveDataType.Password)
|
||||
{
|
||||
return UsernameFields.Select(f => f.AutofillId).ToArray();
|
||||
}
|
||||
else if (SaveType == SaveDataType.CreditCard)
|
||||
{
|
||||
var fieldList = new List<Field>();
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardSecurityCode))
|
||||
{
|
||||
fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardSecurityCode]);
|
||||
}
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationYear))
|
||||
{
|
||||
fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardExpirationYear]);
|
||||
}
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationMonth))
|
||||
{
|
||||
fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardExpirationMonth]);
|
||||
}
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintName))
|
||||
{
|
||||
fieldList.AddRange(HintToFieldsMap[View.AutofillHintName]);
|
||||
}
|
||||
return fieldList.Select(f => f.AutofillId).ToArray();
|
||||
}
|
||||
return new AutofillId[0];
|
||||
}
|
||||
|
||||
public AutofillId[] GetRequiredSaveFields()
|
||||
{
|
||||
if (SaveType == SaveDataType.Password)
|
||||
{
|
||||
return PasswordFields.Select(f => f.AutofillId).ToArray();
|
||||
}
|
||||
else if (SaveType == SaveDataType.CreditCard && HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardNumber))
|
||||
{
|
||||
return HintToFieldsMap[View.AutofillHintCreditCardNumber].Select(f => f.AutofillId).ToArray();
|
||||
}
|
||||
return new AutofillId[0];
|
||||
}
|
||||
|
||||
private bool FocusedHintsContain(IEnumerable<string> hints)
|
||||
{
|
||||
return hints.Any(h => FocusedHints.Contains(h));
|
||||
}
|
||||
|
||||
private string GetFieldValue(string hint, bool monthValue = false)
|
||||
{
|
||||
if (HintToFieldsMap.ContainsKey(hint))
|
||||
{
|
||||
foreach (var field in HintToFieldsMap[hint])
|
||||
{
|
||||
var val = GetFieldValue(field, monthValue);
|
||||
if (!string.IsNullOrWhiteSpace(val))
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetFieldValue(Field field, bool monthValue = false)
|
||||
{
|
||||
if (field == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(field.TextValue))
|
||||
{
|
||||
if (field.AutofillType == AutofillType.List && field.ListValue.HasValue && monthValue)
|
||||
{
|
||||
if (field.AutofillOptions.Count == 13)
|
||||
{
|
||||
return field.ListValue.ToString();
|
||||
}
|
||||
else if (field.AutofillOptions.Count == 12)
|
||||
{
|
||||
return (field.ListValue + 1).ToString();
|
||||
}
|
||||
}
|
||||
return field.TextValue;
|
||||
}
|
||||
else if (field.DateValue.HasValue)
|
||||
{
|
||||
return field.DateValue.Value.ToString();
|
||||
}
|
||||
else if (field.ToggleValue.HasValue)
|
||||
{
|
||||
return field.ToggleValue.Value.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool FieldIsPassword(Field f)
|
||||
{
|
||||
var inputTypePassword = f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationWebPassword);
|
||||
|
||||
// For whatever reason, multi-line input types are coming through with TextVariationPassword flags
|
||||
if (inputTypePassword && f.InputType.HasFlag(InputTypes.TextVariationPassword) &&
|
||||
f.InputType.HasFlag(InputTypes.TextFlagMultiLine))
|
||||
{
|
||||
inputTypePassword = false;
|
||||
}
|
||||
|
||||
if (!inputTypePassword && f.HtmlInfo != null && f.HtmlInfo.Tag == "input" &&
|
||||
(f.HtmlInfo.Attributes?.Any() ?? false))
|
||||
{
|
||||
foreach (var a in f.HtmlInfo.Attributes)
|
||||
{
|
||||
var key = a.First as Java.Lang.String;
|
||||
var val = a.Second as Java.Lang.String;
|
||||
if (key != null && val != null && key.ToString() == "type" && val.ToString() == "password")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputTypePassword && !ValueContainsAnyTerms(f.IdEntry, _ignoreSearchTerms) &&
|
||||
!ValueContainsAnyTerms(f.Hint, _ignoreSearchTerms);
|
||||
}
|
||||
|
||||
private bool FieldHasPasswordTerms(Field f)
|
||||
{
|
||||
return ValueContainsAnyTerms(f.IdEntry, _passwordTerms) || ValueContainsAnyTerms(f.Hint, _passwordTerms);
|
||||
}
|
||||
|
||||
private bool ValueContainsAnyTerms(string value, HashSet<string> terms)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var lowerValue = value.ToLowerInvariant();
|
||||
return terms.Any(t => lowerValue.Contains(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
224
src/Android/Autofill/FilledItem.cs
Normal file
224
src/Android/Autofill/FilledItem.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using Android.Service.Autofill;
|
||||
using Android.Views.Autofill;
|
||||
using System.Linq;
|
||||
using Bit.Core.Enums;
|
||||
using Android.Views;
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class FilledItem
|
||||
{
|
||||
private string _password;
|
||||
private string _cardName;
|
||||
private string _cardNumber;
|
||||
private string _cardExpMonth;
|
||||
private string _cardExpYear;
|
||||
private string _cardCode;
|
||||
private string _idPhone;
|
||||
private string _idEmail;
|
||||
private string _idUsername;
|
||||
private string _idAddress;
|
||||
private string _idPostalCode;
|
||||
|
||||
public FilledItem(CipherView cipher)
|
||||
{
|
||||
Name = cipher.Name;
|
||||
Type = cipher.Type;
|
||||
Subtitle = cipher.SubTitle;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
Icon = Resource.Drawable.login;
|
||||
_password = cipher.Login.Password;
|
||||
break;
|
||||
case CipherType.Card:
|
||||
_cardNumber = cipher.Card.Number;
|
||||
Icon = Resource.Drawable.card;
|
||||
_cardName = cipher.Card.CardholderName;
|
||||
_cardCode = cipher.Card.Code;
|
||||
_cardExpMonth = cipher.Card.ExpMonth;
|
||||
_cardExpYear = cipher.Card.ExpYear;
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
Icon = Resource.Drawable.id;
|
||||
_idPhone = cipher.Identity.Phone;
|
||||
_idEmail = cipher.Identity.Email;
|
||||
_idUsername = cipher.Identity.Username;
|
||||
_idAddress = cipher.Identity.FullAddress;
|
||||
_idPostalCode = cipher.Identity.PostalCode;
|
||||
break;
|
||||
default:
|
||||
Icon = Resource.Drawable.login;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Subtitle { get; set; } = string.Empty;
|
||||
public int Icon { get; set; } = Resource.Drawable.login;
|
||||
public CipherType Type { get; set; }
|
||||
|
||||
public bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder)
|
||||
{
|
||||
if (!fieldCollection?.Fields.Any() ?? true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var setValues = false;
|
||||
if (Type == CipherType.Login)
|
||||
{
|
||||
if (fieldCollection.PasswordFields.Any() && !string.IsNullOrWhiteSpace(_password))
|
||||
{
|
||||
foreach (var f in fieldCollection.PasswordFields)
|
||||
{
|
||||
var val = ApplyValue(f, _password);
|
||||
if (val != null)
|
||||
{
|
||||
setValues = true;
|
||||
datasetBuilder.SetValue(f.AutofillId, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fieldCollection.UsernameFields.Any() && !string.IsNullOrWhiteSpace(Subtitle))
|
||||
{
|
||||
foreach (var f in fieldCollection.UsernameFields)
|
||||
{
|
||||
var val = ApplyValue(f, Subtitle);
|
||||
if (val != null)
|
||||
{
|
||||
setValues = true;
|
||||
datasetBuilder.SetValue(f.AutofillId, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Type == CipherType.Card)
|
||||
{
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardNumber,
|
||||
_cardNumber))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardSecurityCode,
|
||||
_cardCode))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection,
|
||||
Android.Views.View.AutofillHintCreditCardExpirationMonth, _cardExpMonth, true))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardExpirationYear,
|
||||
_cardExpYear))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintName, _cardName))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
}
|
||||
else if (Type == CipherType.Identity)
|
||||
{
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPhone, _idPhone))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintEmailAddress, _idEmail))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintUsername,
|
||||
_idUsername))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPostalAddress,
|
||||
_idAddress))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPostalCode,
|
||||
_idPostalCode))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
if (ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintName, Subtitle))
|
||||
{
|
||||
setValues = true;
|
||||
}
|
||||
}
|
||||
return setValues;
|
||||
}
|
||||
|
||||
private static bool ApplyValue(Dataset.Builder builder, FieldCollection fieldCollection,
|
||||
string hint, string value, bool monthValue = false)
|
||||
{
|
||||
bool setValues = false;
|
||||
if (fieldCollection.HintToFieldsMap.ContainsKey(hint) && !string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
foreach (var f in fieldCollection.HintToFieldsMap[hint])
|
||||
{
|
||||
var val = ApplyValue(f, value, monthValue);
|
||||
if (val != null)
|
||||
{
|
||||
setValues = true;
|
||||
builder.SetValue(f.AutofillId, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return setValues;
|
||||
}
|
||||
|
||||
private static AutofillValue ApplyValue(Field field, string value, bool monthValue = false)
|
||||
{
|
||||
switch (field.AutofillType)
|
||||
{
|
||||
case AutofillType.Date:
|
||||
if (long.TryParse(value, out long dateValue))
|
||||
{
|
||||
return AutofillValue.ForDate(dateValue);
|
||||
}
|
||||
break;
|
||||
case AutofillType.List:
|
||||
if (field.AutofillOptions != null)
|
||||
{
|
||||
if (monthValue && int.TryParse(value, out int monthIndex))
|
||||
{
|
||||
if (field.AutofillOptions.Count == 13)
|
||||
{
|
||||
return AutofillValue.ForList(monthIndex);
|
||||
}
|
||||
else if (field.AutofillOptions.Count >= monthIndex)
|
||||
{
|
||||
return AutofillValue.ForList(monthIndex - 1);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < field.AutofillOptions.Count; i++)
|
||||
{
|
||||
if (field.AutofillOptions[i].Equals(value))
|
||||
{
|
||||
return AutofillValue.ForList(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AutofillType.Text:
|
||||
return AutofillValue.ForText(value);
|
||||
case AutofillType.Toggle:
|
||||
if (bool.TryParse(value, out bool toggleValue))
|
||||
{
|
||||
return AutofillValue.ForToggle(toggleValue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
176
src/Android/Autofill/Parser.cs
Normal file
176
src/Android/Autofill/Parser.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using static Android.App.Assist.AssistStructure;
|
||||
using Android.App.Assist;
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core;
|
||||
using Android.Content;
|
||||
using Bit.Core.Abstractions;
|
||||
using System.Threading.Tasks;
|
||||
using Android.OS;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class Parser
|
||||
{
|
||||
public static HashSet<string> _excludedPackageIds = new HashSet<string>
|
||||
{
|
||||
"android"
|
||||
};
|
||||
private readonly AssistStructure _structure;
|
||||
private string _uri;
|
||||
private string _packageName;
|
||||
private string _website;
|
||||
|
||||
public Parser(AssistStructure structure, Context applicationContext)
|
||||
{
|
||||
_structure = structure;
|
||||
ApplicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public Context ApplicationContext { get; set; }
|
||||
public FieldCollection FieldCollection { get; private set; } = new FieldCollection();
|
||||
|
||||
public string Uri
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_uri))
|
||||
{
|
||||
return _uri;
|
||||
}
|
||||
var websiteNull = string.IsNullOrWhiteSpace(Website);
|
||||
if (websiteNull && string.IsNullOrWhiteSpace(PackageName))
|
||||
{
|
||||
_uri = null;
|
||||
}
|
||||
else if (!websiteNull)
|
||||
{
|
||||
_uri = Website;
|
||||
}
|
||||
else
|
||||
{
|
||||
_uri = string.Concat(Constants.AndroidAppProtocol, PackageName);
|
||||
}
|
||||
return _uri;
|
||||
}
|
||||
}
|
||||
|
||||
public string PackageName
|
||||
{
|
||||
get => _packageName;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
_packageName = _uri = null;
|
||||
}
|
||||
_packageName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Website
|
||||
{
|
||||
get => _website;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
_website = _uri = null;
|
||||
}
|
||||
_website = value;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ShouldAutofillAsync(IStorageService storageService)
|
||||
{
|
||||
var fillable = !string.IsNullOrWhiteSpace(Uri) && !AutofillHelpers.BlacklistedUris.Contains(Uri) &&
|
||||
FieldCollection != null && FieldCollection.Fillable;
|
||||
if (fillable)
|
||||
{
|
||||
var blacklistedUris = await storageService.GetAsync<List<string>>(Constants.AutofillBlacklistedUrisKey);
|
||||
if (blacklistedUris != null && blacklistedUris.Count > 0)
|
||||
{
|
||||
fillable = !new HashSet<string>(blacklistedUris).Contains(Uri);
|
||||
}
|
||||
}
|
||||
return fillable;
|
||||
}
|
||||
|
||||
public void Parse()
|
||||
{
|
||||
string titlePackageId = null;
|
||||
for (var i = 0; i < _structure.WindowNodeCount; i++)
|
||||
{
|
||||
var node = _structure.GetWindowNodeAt(i);
|
||||
if (i == 0)
|
||||
{
|
||||
titlePackageId = GetTitlePackageId(node);
|
||||
}
|
||||
ParseNode(node.RootViewNode);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(PackageName) && string.IsNullOrWhiteSpace(Website))
|
||||
{
|
||||
PackageName = titlePackageId;
|
||||
}
|
||||
if (!AutofillHelpers.TrustedBrowsers.Contains(PackageName) &&
|
||||
!AutofillHelpers.CompatBrowsers.Contains(PackageName))
|
||||
{
|
||||
Website = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseNode(ViewNode node)
|
||||
{
|
||||
SetPackageAndDomain(node);
|
||||
var hints = node.GetAutofillHints();
|
||||
var isEditText = node.ClassName == "android.widget.EditText" || node?.HtmlInfo?.Tag == "input";
|
||||
if (isEditText || (hints?.Length ?? 0) > 0)
|
||||
{
|
||||
FieldCollection.Add(new Field(node));
|
||||
}
|
||||
else
|
||||
{
|
||||
FieldCollection.IgnoreAutofillIds.Add(node.AutofillId);
|
||||
}
|
||||
|
||||
for (var i = 0; i < node.ChildCount; i++)
|
||||
{
|
||||
ParseNode(node.GetChildAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPackageAndDomain(ViewNode node)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(PackageName) && !string.IsNullOrWhiteSpace(node.IdPackage) &&
|
||||
!_excludedPackageIds.Contains(node.IdPackage))
|
||||
{
|
||||
PackageName = node.IdPackage;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Website) && !string.IsNullOrWhiteSpace(node.WebDomain))
|
||||
{
|
||||
var scheme = "http";
|
||||
if ((int)Build.VERSION.SdkInt >= 28)
|
||||
{
|
||||
scheme = node.WebScheme;
|
||||
}
|
||||
Website = string.Format("{0}://{1}", scheme, node.WebDomain);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTitlePackageId(WindowNode node)
|
||||
{
|
||||
if (node != null && !string.IsNullOrWhiteSpace(node.Title))
|
||||
{
|
||||
var slashPosition = node.Title.IndexOf('/');
|
||||
if (slashPosition > -1)
|
||||
{
|
||||
var packageId = node.Title.Substring(0, slashPosition);
|
||||
if (packageId.Contains("."))
|
||||
{
|
||||
return packageId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/Android/Autofill/SavedItem.cs
Normal file
26
src/Android/Autofill/SavedItem.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Droid.Autofill
|
||||
{
|
||||
public class SavedItem
|
||||
{
|
||||
public CipherType Type { get; set; }
|
||||
public LoginItem Login { get; set; }
|
||||
public CardItem Card { get; set; }
|
||||
|
||||
public class LoginItem
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
public class CardItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Android.AccessibilityServices;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Views.Accessibility;
|
||||
using Android.Widget;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
//[Service(Permission = "android.permission.BIND_ACCESSIBILITY_SERVICE", Label = "bitwarden")]
|
||||
//[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
|
||||
//[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
|
||||
public class AutofillService : AccessibilityService
|
||||
{
|
||||
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||
{
|
||||
var eventType = e.EventType;
|
||||
switch(eventType)
|
||||
{
|
||||
case EventTypes.ViewTextSelectionChanged:
|
||||
if(e.Source.Password && string.IsNullOrWhiteSpace(e.Source.Text))
|
||||
{
|
||||
var bundle = new Bundle();
|
||||
bundle.PutCharSequence(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, "mypassword");
|
||||
e.Source.PerformAction(global::Android.Views.Accessibility.Action.SetText, bundle);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInterrupt()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class CustomButtonRenderer : ButtonRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if(Control.TextSize == (float)Device.GetNamedSize(NamedSize.Default, typeof(Button)))
|
||||
{
|
||||
Control.TextSize = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Button));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
Control.SetPadding((int)global::Android.App.Application.Context.ToPixels(-8), 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedButton), typeof(ExtendedButtonRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedButtonRenderer : CustomButtonRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
SetPadding();
|
||||
SetUppercase();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if(e.PropertyName == ExtendedButton.PaddingProperty.PropertyName)
|
||||
{
|
||||
SetPadding();
|
||||
}
|
||||
else if(e.PropertyName == ExtendedButton.UppercaseProperty.PropertyName)
|
||||
{
|
||||
SetUppercase();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPadding()
|
||||
{
|
||||
var element = Element as ExtendedButton;
|
||||
if(element != null)
|
||||
{
|
||||
Control.SetPadding(
|
||||
(int)element.Padding.Left,
|
||||
(int)element.Padding.Top,
|
||||
(int)element.Padding.Right,
|
||||
(int)element.Padding.Bottom);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetUppercase()
|
||||
{
|
||||
var element = Element as ExtendedButton;
|
||||
if(element != null && !string.IsNullOrWhiteSpace(element.Text))
|
||||
{
|
||||
if(element.Uppercase)
|
||||
{
|
||||
element.Text = element.Text.ToUpperInvariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
Control.TransformationMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedEditor), typeof(ExtendedEditorRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedEditorRenderer : EditorRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var view = (ExtendedEditor)Element;
|
||||
|
||||
SetBorder(view);
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var view = (ExtendedEditor)Element;
|
||||
|
||||
if(e.PropertyName == ExtendedEditor.HasBorderProperty.PropertyName)
|
||||
{
|
||||
SetBorder(view);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
Control.SetBackgroundColor(view.BackgroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBorder(ExtendedEditor view)
|
||||
{
|
||||
if(!view.HasBorder)
|
||||
{
|
||||
Control.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Android.Graphics;
|
||||
using Android.Text;
|
||||
using Android.Text.Method;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.Widget;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Enums;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedEntryRenderer : EntryRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var view = (ExtendedEntry)Element;
|
||||
if(Control != null)
|
||||
{
|
||||
Control.SetIncludeFontPadding(false);
|
||||
if(e.NewElement != null && e.NewElement.IsPassword)
|
||||
{
|
||||
Control.SetTypeface(Typeface.Default, TypefaceStyle.Normal);
|
||||
Control.TransformationMethod = new PasswordTransformationMethod();
|
||||
}
|
||||
}
|
||||
|
||||
SetBorder(view);
|
||||
SetMaxLength(view);
|
||||
SetReturnType(view);
|
||||
|
||||
// Editor Action is called when the return button is pressed
|
||||
Control.EditorAction += (object sender, TextView.EditorActionEventArgs args) =>
|
||||
{
|
||||
if(view.ReturnType != ReturnType.Next)
|
||||
{
|
||||
view.Unfocus();
|
||||
}
|
||||
|
||||
// Call all the methods attached to base_entry event handler Completed
|
||||
view.InvokeCompleted();
|
||||
};
|
||||
|
||||
if(view.DisableAutocapitalize)
|
||||
{
|
||||
Control.SetRawInputType(Control.InputType |= InputTypes.TextVariationEmailAddress);
|
||||
}
|
||||
|
||||
if(view.Autocorrect.HasValue)
|
||||
{
|
||||
Control.SetRawInputType(Control.InputType |= InputTypes.TextFlagNoSuggestions);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var view = (ExtendedEntry)Element;
|
||||
|
||||
if(e.PropertyName == ExtendedEntry.HasBorderProperty.PropertyName
|
||||
|| e.PropertyName == ExtendedEntry.HasOnlyBottomBorderProperty.PropertyName
|
||||
|| e.PropertyName == ExtendedEntry.BottomBorderColorProperty.PropertyName)
|
||||
{
|
||||
SetBorder(view);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
Control.SetBackgroundColor(view.BackgroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetReturnType(ExtendedEntry view)
|
||||
{
|
||||
if(view.ReturnType.HasValue)
|
||||
{
|
||||
switch(view.ReturnType.Value)
|
||||
{
|
||||
case ReturnType.Go:
|
||||
Control.ImeOptions = ImeAction.Go;
|
||||
Control.SetImeActionLabel("Go", ImeAction.Go);
|
||||
break;
|
||||
case ReturnType.Next:
|
||||
Control.ImeOptions = ImeAction.Next;
|
||||
Control.SetImeActionLabel("Next", ImeAction.Next);
|
||||
break;
|
||||
case ReturnType.Search:
|
||||
Control.ImeOptions = ImeAction.Search;
|
||||
Control.SetImeActionLabel("Search", ImeAction.Search);
|
||||
break;
|
||||
case ReturnType.Send:
|
||||
Control.ImeOptions = ImeAction.Send;
|
||||
Control.SetImeActionLabel("Send", ImeAction.Send);
|
||||
break;
|
||||
default:
|
||||
Control.SetImeActionLabel("Done", ImeAction.Done);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBorder(ExtendedEntry view)
|
||||
{
|
||||
if(!view.HasBorder)
|
||||
{
|
||||
Control.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Control.SetBackgroundColor(view.BottomBorderColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMaxLength(ExtendedEntry view)
|
||||
{
|
||||
Control.SetFilters(new IInputFilter[] { new InputFilterLengthFilter(view.MaxLength) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedPicker), typeof(ExtendedPickerRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedPickerRenderer : PickerRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var view = (ExtendedPicker)Element;
|
||||
|
||||
Control.TextSize = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Picker));
|
||||
SetBorder(view);
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var view = (ExtendedPicker)Element;
|
||||
|
||||
if(e.PropertyName == ExtendedPicker.HasBorderProperty.PropertyName)
|
||||
{
|
||||
SetBorder(view);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
Control.SetBackgroundColor(view.BackgroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBorder(ExtendedPicker view)
|
||||
{
|
||||
if(!view.HasBorder)
|
||||
{
|
||||
Control.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using Android.Content;
|
||||
using System.ComponentModel;
|
||||
using Android.Views;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AView = Android.Views.View;
|
||||
using Android.Widget;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedSwitchCell), typeof(ExtendedSwitchCellRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedSwitchCellRenderer : SwitchCellRenderer
|
||||
{
|
||||
protected BaseCellView View { get; private set; }
|
||||
|
||||
protected override AView GetCellCore(Cell item, AView convertView, ViewGroup parent, Context context)
|
||||
{
|
||||
var View = base.GetCellCore(item, convertView, parent, context) as SwitchCellView;
|
||||
var extendedCell = (ExtendedSwitchCell)item;
|
||||
|
||||
if(View != null)
|
||||
{
|
||||
if(extendedCell.BackgroundColor != Color.White)
|
||||
{
|
||||
View.SetBackgroundColor(extendedCell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
View.SetBackgroundResource(Resource.Drawable.list_selector);
|
||||
}
|
||||
|
||||
if(item.IsEnabled)
|
||||
{
|
||||
View.SetMainTextColor(Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
View.SetMainTextColor(Color.FromHex("777777"));
|
||||
}
|
||||
|
||||
if(View.ChildCount > 1)
|
||||
{
|
||||
var layout = View.GetChildAt(1) as LinearLayout;
|
||||
if(layout != null && layout.ChildCount > 0)
|
||||
{
|
||||
var textView = layout.GetChildAt(0) as TextView;
|
||||
if(textView != null)
|
||||
{
|
||||
textView.TextSize = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return View;
|
||||
}
|
||||
|
||||
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
base.OnCellPropertyChanged(sender, args);
|
||||
|
||||
var cell = (ExtendedSwitchCell)Cell;
|
||||
|
||||
if(args.PropertyName == ExtendedSwitchCell.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
View.SetBackgroundColor(cell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Android.Support.Design.Widget;
|
||||
using Xamarin.Forms.Platform.Android.AppCompat;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedTabbedPage), typeof(ExtendedTabbedPageRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedTabbedPageRenderer : TabbedPageRenderer, TabLayout.IOnTabSelectedListener
|
||||
{
|
||||
private TabLayout _tabLayout;
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
var view = (ExtendedTabbedPage)Element;
|
||||
|
||||
var field = typeof(ExtendedTabbedPageRenderer).BaseType.GetField("_tabLayout",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
_tabLayout = field?.GetValue(this) as TabLayout;
|
||||
if(_tabLayout != null)
|
||||
{
|
||||
var tab = _tabLayout.GetTabAt(0);
|
||||
SetSelectedTabIcon(tab, Element.Children[0].Icon, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TabLayout.IOnTabSelectedListener.OnTabSelected(TabLayout.Tab tab)
|
||||
{
|
||||
if(Element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedIndex = tab.Position;
|
||||
var child = Element.Children[selectedIndex];
|
||||
if(Element.Children.Count > selectedIndex && selectedIndex >= 0)
|
||||
{
|
||||
Element.CurrentPage = Element.Children[selectedIndex];
|
||||
}
|
||||
|
||||
SetSelectedTabIcon(tab, child.Icon, true);
|
||||
}
|
||||
|
||||
void TabLayout.IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
|
||||
{
|
||||
var child = Element.Children[tab.Position];
|
||||
SetSelectedTabIcon(tab, child.Icon, false);
|
||||
}
|
||||
|
||||
private void SetSelectedTabIcon(TabLayout.Tab tab, string icon, bool selected)
|
||||
{
|
||||
if(string.IsNullOrEmpty(icon))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(selected)
|
||||
{
|
||||
var selectedResource = IdFromTitle(string.Format("{0}_selected", icon), ResourceManager.DrawableClass);
|
||||
if(selectedResource != 0)
|
||||
{
|
||||
tab.SetIcon(selectedResource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var resource = IdFromTitle(icon, ResourceManager.DrawableClass);
|
||||
tab.SetIcon(resource);
|
||||
}
|
||||
|
||||
private int IdFromTitle(string title, Type type)
|
||||
{
|
||||
var name = System.IO.Path.GetFileNameWithoutExtension(title);
|
||||
return GetId(type, name);
|
||||
}
|
||||
|
||||
private int GetId(Type type, string propertyName)
|
||||
{
|
||||
var props = type.GetFields();
|
||||
var prop = props.FirstOrDefault(p => p.Name == propertyName);
|
||||
if(prop != null)
|
||||
{
|
||||
return (int)prop.GetValue(type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
using System;
|
||||
using Android.Widget;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Android.Content;
|
||||
using AView = Android.Views.View;
|
||||
using AListView = Android.Widget.ListView;
|
||||
using Android.Views;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedTableView), typeof(ExtendedTableViewRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedTableViewRenderer : TableViewRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
Control.Divider = null;
|
||||
Control.DividerHeight = 0;
|
||||
}
|
||||
|
||||
protected override TableViewModelRenderer GetModelRenderer(AListView listView, TableView view)
|
||||
{
|
||||
return new CustomTableViewModelRenderer(Context, listView, view);
|
||||
}
|
||||
|
||||
public override SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
|
||||
{
|
||||
var baseSize = base.GetDesiredSize(widthConstraint, heightConstraint);
|
||||
var height = ComputeHeight(Control, Convert.ToInt32(baseSize.Request.Width));
|
||||
return new SizeRequest(new Size(baseSize.Request.Width, height));
|
||||
}
|
||||
|
||||
private int ComputeHeight(AListView listView, int width)
|
||||
{
|
||||
var element = Element as ExtendedTableView;
|
||||
|
||||
var adapter = listView.Adapter;
|
||||
var totalHeight = listView.PaddingTop + listView.PaddingBottom;
|
||||
var desiredWidth = MeasureSpec.MakeMeasureSpec(width, MeasureSpecMode.AtMost);
|
||||
for(var i = 0; i < adapter.Count; i++)
|
||||
{
|
||||
if(i == 0 && (element?.NoHeader ?? false))
|
||||
{
|
||||
totalHeight += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
var view = adapter.GetView(i, null, listView);
|
||||
view.LayoutParameters = new LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
|
||||
view.Measure(desiredWidth, MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified));
|
||||
totalHeight += view.MeasuredHeight;
|
||||
}
|
||||
|
||||
return totalHeight + (listView.DividerHeight * (adapter.Count - 1));
|
||||
}
|
||||
|
||||
private class CustomTableViewModelRenderer : TableViewModelRenderer
|
||||
{
|
||||
private readonly ExtendedTableView _view;
|
||||
private readonly AListView _listView;
|
||||
|
||||
public CustomTableViewModelRenderer(Context context, AListView listView, TableView view)
|
||||
: base(context, listView, view)
|
||||
{
|
||||
_view = view as ExtendedTableView;
|
||||
_listView = listView;
|
||||
}
|
||||
|
||||
private ITableViewController Controller => _view;
|
||||
|
||||
// ref http://bit.ly/2b9cjnQ
|
||||
public override AView GetView(int position, AView convertView, ViewGroup parent)
|
||||
{
|
||||
var baseView = base.GetView(position, convertView, parent);
|
||||
var layout = baseView as LinearLayout;
|
||||
if(layout == null)
|
||||
{
|
||||
return baseView;
|
||||
}
|
||||
|
||||
bool isHeader, nextIsHeader;
|
||||
var cell = GetCellForPosition(position, out isHeader, out nextIsHeader);
|
||||
if(layout.ChildCount > 0)
|
||||
{
|
||||
layout.RemoveViewAt(0);
|
||||
var cellView = CellFactory.GetCell(cell, convertView, parent, Context, _view);
|
||||
layout.AddView(cellView, 0);
|
||||
}
|
||||
|
||||
if(isHeader)
|
||||
{
|
||||
var textCell = layout.GetChildAt(0) as BaseCellView;
|
||||
if(textCell != null)
|
||||
{
|
||||
if(position == 0 && _view.NoHeader)
|
||||
{
|
||||
textCell.Visibility = ViewStates.Gone;
|
||||
}
|
||||
else
|
||||
{
|
||||
textCell.MainText = textCell.MainText?.ToUpperInvariant();
|
||||
textCell.SetMainTextColor(Color.FromHex("777777"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bline = layout.GetChildAt(1);
|
||||
if(bline != null)
|
||||
{
|
||||
bline.SetBackgroundColor(_view.SeparatorColor.ToAndroid());
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
// Copy/pasted from Xamarin source. Invoke via reflection instead maybe?
|
||||
private Cell GetCellForPosition(int position, out bool isHeader, out bool nextIsHeader)
|
||||
{
|
||||
isHeader = false;
|
||||
nextIsHeader = false;
|
||||
|
||||
var model = Controller.Model;
|
||||
var sectionCount = model.GetSectionCount();
|
||||
|
||||
for(var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++)
|
||||
{
|
||||
var size = model.GetRowCount(sectionIndex) + 1;
|
||||
if(position == 0)
|
||||
{
|
||||
isHeader = true;
|
||||
nextIsHeader = size == 0 && sectionIndex < sectionCount - 1;
|
||||
|
||||
var header = model.GetHeaderCell(sectionIndex);
|
||||
Cell resultCell = null;
|
||||
if(header != null)
|
||||
{
|
||||
resultCell = header;
|
||||
}
|
||||
|
||||
if(resultCell == null)
|
||||
{
|
||||
resultCell = new TextCell { Text = model.GetSectionTitle(sectionIndex) };
|
||||
}
|
||||
|
||||
resultCell.Parent = _view;
|
||||
return resultCell;
|
||||
}
|
||||
|
||||
if(position < size)
|
||||
{
|
||||
nextIsHeader = position == size - 1;
|
||||
return (Cell)model.GetItem(sectionIndex, position - 1);
|
||||
}
|
||||
|
||||
position -= size;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
using Android.Content;
|
||||
using System.ComponentModel;
|
||||
using Android.Views;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AView = Android.Views.View;
|
||||
using Android.Widget;
|
||||
using Android.Text;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedTextCell), typeof(ExtendedTextCellRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedTextCellRenderer : TextCellRenderer
|
||||
{
|
||||
protected AView View { get; private set; }
|
||||
|
||||
protected override AView GetCellCore(Cell item, AView convertView, ViewGroup parent, Context context)
|
||||
{
|
||||
var View = (BaseCellView)base.GetCellCore(item, convertView, parent, context);
|
||||
var extendedCell = (ExtendedTextCell)item;
|
||||
|
||||
if(View != null)
|
||||
{
|
||||
if(extendedCell.BackgroundColor != Color.White)
|
||||
{
|
||||
View.SetBackgroundColor(extendedCell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
View.SetBackgroundResource(Resource.Drawable.list_selector);
|
||||
}
|
||||
|
||||
if(extendedCell.ShowDisclousure)
|
||||
{
|
||||
var resourceId = Resource.Drawable.ion_chevron_right;
|
||||
if(!string.IsNullOrWhiteSpace(extendedCell.DisclousureImage))
|
||||
{
|
||||
var fileName = System.IO.Path.GetFileNameWithoutExtension(extendedCell.DisclousureImage);
|
||||
resourceId = context.Resources.GetIdentifier(fileName, "drawable", context.PackageName);
|
||||
}
|
||||
|
||||
var image = new DisclosureImage(context, extendedCell);
|
||||
image.SetImageResource(resourceId);
|
||||
image.SetPadding(10, 10, 30, 10);
|
||||
View.SetAccessoryView(image);
|
||||
}
|
||||
|
||||
if(View.ChildCount > 1)
|
||||
{
|
||||
var layout = View.GetChildAt(1) as LinearLayout;
|
||||
if(layout != null)
|
||||
{
|
||||
if(layout.ChildCount > 0)
|
||||
{
|
||||
var textView = layout.GetChildAt(0) as TextView;
|
||||
if(textView != null)
|
||||
{
|
||||
textView.TextSize = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label));
|
||||
}
|
||||
}
|
||||
|
||||
if(layout.ChildCount > 1)
|
||||
{
|
||||
var detailView = layout.GetChildAt(1) as TextView;
|
||||
if(detailView != null)
|
||||
{
|
||||
UpdateLineBreakMode(detailView, extendedCell.DetailLineBreakMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return View;
|
||||
}
|
||||
|
||||
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
base.OnCellPropertyChanged(sender, args);
|
||||
|
||||
var cell = (ExtendedTextCell)Cell;
|
||||
|
||||
if(args.PropertyName == ExtendedTextCell.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
View.SetBackgroundColor(cell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
|
||||
// TODO: other properties
|
||||
}
|
||||
|
||||
private void UpdateLineBreakMode(TextView view, LineBreakMode lineBreakMode)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(lineBreakMode)
|
||||
{
|
||||
case LineBreakMode.NoWrap:
|
||||
view.SetSingleLine(true);
|
||||
view.Ellipsize = null;
|
||||
break;
|
||||
case LineBreakMode.WordWrap:
|
||||
view.SetSingleLine(false);
|
||||
view.Ellipsize = null;
|
||||
view.SetMaxLines(100);
|
||||
break;
|
||||
case LineBreakMode.CharacterWrap:
|
||||
view.SetSingleLine(false);
|
||||
view.Ellipsize = null;
|
||||
view.SetMaxLines(100);
|
||||
break;
|
||||
case LineBreakMode.HeadTruncation:
|
||||
view.SetSingleLine(true);
|
||||
view.Ellipsize = TextUtils.TruncateAt.Start;
|
||||
break;
|
||||
case LineBreakMode.TailTruncation:
|
||||
view.SetSingleLine(true);
|
||||
view.Ellipsize = TextUtils.TruncateAt.End;
|
||||
break;
|
||||
case LineBreakMode.MiddleTruncation:
|
||||
view.SetSingleLine(true);
|
||||
view.Ellipsize = TextUtils.TruncateAt.Middle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private class DisclosureImage : ImageView
|
||||
{
|
||||
private ExtendedTextCell _cell;
|
||||
|
||||
public DisclosureImage(Context context, ExtendedTextCell cell) : base(context)
|
||||
{
|
||||
_cell = cell;
|
||||
}
|
||||
|
||||
public override bool OnTouchEvent(MotionEvent e)
|
||||
{
|
||||
switch(e.Action)
|
||||
{
|
||||
case MotionEventActions.Up:
|
||||
_cell.OnDisclousureTapped();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using Android.Content;
|
||||
using System.ComponentModel;
|
||||
using Android.Views;
|
||||
using Bit.Android.Controls;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AView = Android.Views.View;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
|
||||
namespace Bit.Android.Controls
|
||||
{
|
||||
public class ExtendedViewCellRenderer : ViewCellRenderer
|
||||
{
|
||||
protected AView View { get; private set; }
|
||||
|
||||
protected override AView GetCellCore(Cell item, AView convertView, ViewGroup parent, Context context)
|
||||
{
|
||||
var View = base.GetCellCore(item, convertView, parent, context);
|
||||
var extendedCell = (ExtendedViewCell)item;
|
||||
|
||||
if(View != null)
|
||||
{
|
||||
if(extendedCell.BackgroundColor != Color.White)
|
||||
{
|
||||
View.SetBackgroundColor(extendedCell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
View.SetBackgroundResource(Resource.Drawable.list_selector);
|
||||
}
|
||||
}
|
||||
|
||||
return View;
|
||||
}
|
||||
|
||||
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
base.OnCellPropertyChanged(sender, args);
|
||||
|
||||
var cell = (ExtendedViewCell)Cell;
|
||||
|
||||
if(args.PropertyName == ExtendedViewCell.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
View.SetBackgroundColor(cell.BackgroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/Android/Effects/FabShadowEffect.cs
Normal file
30
src/Android/Effects/FabShadowEffect.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Android.Graphics.Drawables;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Effects;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")]
|
||||
namespace Bit.Droid.Effects
|
||||
{
|
||||
public class FabShadowEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached ()
|
||||
{
|
||||
if (Control is Android.Widget.Button button)
|
||||
{
|
||||
var gd = new GradientDrawable();
|
||||
gd.SetColor(ThemeManager.GetResourceColor("FabColor").ToAndroid());
|
||||
gd.SetCornerRadius(100);
|
||||
|
||||
button.SetBackground(gd);
|
||||
button.Elevation = 6;
|
||||
button.TranslationZ = 20;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetached ()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Android/Effects/FixedSizeEffect.cs
Normal file
23
src/Android/Effects/FixedSizeEffect.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Android.Widget;
|
||||
using Bit.Droid.Effects;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportEffect(typeof(FixedSizeEffect), "FixedSizeEffect")]
|
||||
namespace Bit.Droid.Effects
|
||||
{
|
||||
public class FixedSizeEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
if (Element is Label label && Control is TextView textView)
|
||||
{
|
||||
textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Android/Effects/SelectableLabelEffect.cs
Normal file
23
src/Android/Effects/SelectableLabelEffect.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Android.Widget;
|
||||
using Bit.Droid.Effects;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportEffect(typeof(SelectableLabelEffect), "SelectableLabelEffect")]
|
||||
namespace Bit.Droid.Effects
|
||||
{
|
||||
public class SelectableLabelEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
if (Control is TextView textView)
|
||||
{
|
||||
textView.SetTextIsSelectable(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/Android/Effects/TabBarEffect.cs
Normal file
30
src/Android/Effects/TabBarEffect.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Android.Views;
|
||||
using Bit.Droid.Effects;
|
||||
using Google.Android.Material.BottomNavigation;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ResolutionGroupName("Bitwarden")]
|
||||
[assembly: ExportEffect(typeof(TabBarEffect), "TabBarEffect")]
|
||||
namespace Bit.Droid.Effects
|
||||
{
|
||||
public class TabBarEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
if (!(Container.GetChildAt(0) is ViewGroup layout))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView))
|
||||
{
|
||||
return;
|
||||
}
|
||||
bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled;
|
||||
}
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using HockeyApp.Android;
|
||||
using Bit.App.Abstractions;
|
||||
using Newtonsoft.Json;
|
||||
using Android.Runtime;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
public class HockeyAppCrashManagerListener : CrashManagerListener
|
||||
{
|
||||
private readonly IAppIdService _appIdService;
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
public HockeyAppCrashManagerListener()
|
||||
{ }
|
||||
|
||||
public HockeyAppCrashManagerListener(System.IntPtr javaRef, JniHandleOwnership transfer)
|
||||
: base(javaRef, transfer)
|
||||
{ }
|
||||
|
||||
public HockeyAppCrashManagerListener(
|
||||
IAppIdService appIdService,
|
||||
IAuthService authService)
|
||||
{
|
||||
_appIdService = appIdService;
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_appIdService != null && _authService != null)
|
||||
{
|
||||
var log = new
|
||||
{
|
||||
AppId = _appIdService.AppId,
|
||||
UserId = _authService.UserId
|
||||
};
|
||||
|
||||
return JsonConvert.SerializeObject(log, Formatting.Indented);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShouldAutoUploadCrashes()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +1,467 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.Views;
|
||||
using Android.Runtime;
|
||||
using Android.OS;
|
||||
using Bit.Core;
|
||||
using System.Linq;
|
||||
using Bit.App.Abstractions;
|
||||
using XLabs.Ioc;
|
||||
using Plugin.Fingerprint.Abstractions;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using Acr.UserDialogs;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Android.Content;
|
||||
using System.Reflection;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Xamarin.Forms;
|
||||
using Bit.Droid.Utilities;
|
||||
using Bit.Droid.Receivers;
|
||||
using Bit.App.Models;
|
||||
using Bit.Core.Enums;
|
||||
using Android.Nfc;
|
||||
using Bit.App.Utilities;
|
||||
using System.Threading.Tasks;
|
||||
using AndroidX.Core.Content;
|
||||
using ZXing.Net.Mobile.Android;
|
||||
|
||||
namespace Bit.Android
|
||||
namespace Bit.Droid
|
||||
{
|
||||
[Activity(Label = "bitwarden",
|
||||
Icon = "@drawable/icon",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
WindowSoftInputMode = SoftInput.StateHidden)]
|
||||
public class MainActivity : FormsAppCompatActivity
|
||||
{
|
||||
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
[Activity(
|
||||
Label = "Bitwarden",
|
||||
Icon = "@mipmap/ic_launcher",
|
||||
Theme = "@style/LaunchTheme",
|
||||
MainLauncher = true,
|
||||
LaunchMode = LaunchMode.SingleTask,
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
|
||||
ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden |
|
||||
ConfigChanges.Navigation)]
|
||||
[IntentFilter(
|
||||
new[] { Intent.ActionSend },
|
||||
Categories = new[] { Intent.CategoryDefault },
|
||||
DataMimeTypes = new[]
|
||||
{
|
||||
ToolbarResource = Resource.Layout.toolbar;
|
||||
TabLayoutResource = Resource.Layout.tabs;
|
||||
@"application/*",
|
||||
@"image/*",
|
||||
@"video/*",
|
||||
@"text/*"
|
||||
})]
|
||||
[Register("com.x8bit.bitwarden.MainActivity")]
|
||||
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
{
|
||||
private IDeviceActionService _deviceActionService;
|
||||
private IMessagingService _messagingService;
|
||||
private IBroadcasterService _broadcasterService;
|
||||
private IUserService _userService;
|
||||
private IAppIdService _appIdService;
|
||||
private IStorageService _storageService;
|
||||
private IEventService _eventService;
|
||||
private PendingIntent _clearClipboardPendingIntent;
|
||||
private PendingIntent _eventUploadPendingIntent;
|
||||
private AppOptions _appOptions;
|
||||
private string _activityKey = $"{nameof(MainActivity)}_{Java.Lang.JavaSystem.CurrentTimeMillis().ToString()}";
|
||||
private Java.Util.Regex.Pattern _otpPattern =
|
||||
Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
|
||||
|
||||
base.OnCreate(bundle);
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
var eventUploadIntent = new Intent(this, typeof(EventUploadReceiver));
|
||||
_eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent,
|
||||
PendingIntentFlags.UpdateCurrent);
|
||||
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
|
||||
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
|
||||
PendingIntentFlags.UpdateCurrent);
|
||||
|
||||
// workaround for app compat bug
|
||||
// ref https://forums.xamarin.com/discussion/62414/app-resuming-results-in-crash-with-formsappcompatactivity
|
||||
Task.Delay(10).Wait();
|
||||
var policy = new StrictMode.ThreadPolicy.Builder().PermitAll().Build();
|
||||
StrictMode.SetThreadPolicy(policy);
|
||||
|
||||
Console.WriteLine("A OnCreate");
|
||||
Window.SetSoftInputMode(SoftInput.StateHidden);
|
||||
Window.AddFlags(WindowManagerFlags.Secure);
|
||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||
_appIdService = ServiceContainer.Resolve<IAppIdService>("appIdService");
|
||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||
|
||||
var appIdService = Resolver.Resolve<IAppIdService>();
|
||||
var authService = Resolver.Resolve<IAuthService>();
|
||||
TabLayoutResource = Resource.Layout.Tabbar;
|
||||
ToolbarResource = Resource.Layout.Toolbar;
|
||||
|
||||
HockeyApp.Android.CrashManager.Register(this, HockeyAppId,
|
||||
new HockeyAppCrashManagerListener(appIdService, authService));
|
||||
|
||||
Forms.Init(this, bundle);
|
||||
|
||||
typeof(Color).GetProperty("Accent", BindingFlags.Public | BindingFlags.Static)
|
||||
.SetValue(null, Color.FromHex("d2d6de"));
|
||||
|
||||
|
||||
LoadApplication(new App.App(
|
||||
Resolver.Resolve<IAuthService>(),
|
||||
Resolver.Resolve<IConnectivity>(),
|
||||
Resolver.Resolve<IUserDialogs>(),
|
||||
Resolver.Resolve<IDatabaseService>(),
|
||||
Resolver.Resolve<ISyncService>(),
|
||||
Resolver.Resolve<IFingerprint>(),
|
||||
Resolver.Resolve<ISettings>(),
|
||||
Resolver.Resolve<ILockService>(),
|
||||
Resolver.Resolve<IGoogleAnalyticsService>()));
|
||||
|
||||
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, "RateApp", (sender) =>
|
||||
UpdateTheme(ThemeManager.GetTheme(true));
|
||||
base.OnCreate(savedInstanceState);
|
||||
if (!CoreHelpers.InDebugMode())
|
||||
{
|
||||
RateApp();
|
||||
Window.AddFlags(Android.Views.WindowManagerFlags.Secure);
|
||||
}
|
||||
|
||||
#if !FDROID
|
||||
var appCenterHelper = new AppCenterHelper(_appIdService, _userService);
|
||||
var appCenterTask = appCenterHelper.InitAsync();
|
||||
#endif
|
||||
|
||||
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
||||
Xamarin.Forms.Forms.Init(this, savedInstanceState);
|
||||
_appOptions = GetOptions();
|
||||
LoadApplication(new App.App(_appOptions));
|
||||
|
||||
_broadcasterService.Subscribe(_activityKey, (message) =>
|
||||
{
|
||||
if (message.Command == "startEventTimer")
|
||||
{
|
||||
StartEventAlarm();
|
||||
}
|
||||
else if (message.Command == "stopEventTimer")
|
||||
{
|
||||
var task = StopEventAlarmAsync();
|
||||
}
|
||||
else if (message.Command == "finishMainActivity")
|
||||
{
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(() => Finish());
|
||||
}
|
||||
else if (message.Command == "listenYubiKeyOTP")
|
||||
{
|
||||
ListenYubiKey((bool)message.Data);
|
||||
}
|
||||
else if (message.Command == "updatedTheme")
|
||||
{
|
||||
RestartApp();
|
||||
}
|
||||
else if (message.Command == "exit")
|
||||
{
|
||||
ExitApp();
|
||||
}
|
||||
else if (message.Command == "copiedToClipboard")
|
||||
{
|
||||
var task = ClearClipboardAlarmAsync(message.Data as Tuple<string, int?, bool>);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
Console.WriteLine("A OnPause");
|
||||
base.OnPause();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
Console.WriteLine("A OnDestroy");
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
protected override void OnRestart()
|
||||
{
|
||||
Console.WriteLine("A OnRestart");
|
||||
base.OnRestart();
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
Console.WriteLine("A OnStart");
|
||||
base.OnStart();
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
Console.WriteLine("A OnStop");
|
||||
base.OnStop();
|
||||
ListenYubiKey(false);
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
Console.WriteLine("A OnResume");
|
||||
base.OnResume();
|
||||
Xamarin.Essentials.Platform.OnResume();
|
||||
if (_deviceActionService.SupportsNfc())
|
||||
{
|
||||
try
|
||||
{
|
||||
_messagingService.Send("resumeYubiKey");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
var setRestrictions = AndroidHelpers.SetPreconfiguredRestrictionSettingsAsync(this);
|
||||
}
|
||||
|
||||
public void RateApp()
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
{
|
||||
base.OnNewIntent(intent);
|
||||
try
|
||||
{
|
||||
var rateIntent = RateIntentForUrl("market://details");
|
||||
StartActivity(rateIntent);
|
||||
if (intent.GetBooleanExtra("generatorTile", false))
|
||||
{
|
||||
_messagingService.Send("popAllAndGoToTabGenerator");
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.GeneratorTile = true;
|
||||
}
|
||||
}
|
||||
else if (intent.GetBooleanExtra("myVaultTile", false))
|
||||
{
|
||||
_messagingService.Send("popAllAndGoToTabMyVault");
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.MyVaultTile = true;
|
||||
}
|
||||
}
|
||||
else if (intent.Action == Intent.ActionSend && intent.Type != null)
|
||||
{
|
||||
if (_appOptions != null)
|
||||
{
|
||||
_appOptions.CreateSend = GetCreateSendRequest(intent);
|
||||
}
|
||||
_messagingService.Send("popAllAndGoToTabSend");
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseYubiKey(intent.DataString);
|
||||
}
|
||||
}
|
||||
catch(ActivityNotFoundException)
|
||||
catch (Exception e)
|
||||
{
|
||||
var rateIntent = RateIntentForUrl("https://play.google.com/store/apps/details");
|
||||
StartActivity(rateIntent);
|
||||
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", e.GetType(), e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private Intent RateIntentForUrl(string url)
|
||||
public async override void OnRequestPermissionsResult(int requestCode, string[] permissions,
|
||||
[GeneratedEnum] Permission[] grantResults)
|
||||
{
|
||||
var intent = new Intent(Intent.ActionView, global::Android.Net.Uri.Parse($"{url}?id={PackageName}"));
|
||||
var flags = ActivityFlags.NoHistory | ActivityFlags.MultipleTask;
|
||||
if((int)Build.VERSION.SdkInt >= 21)
|
||||
if (requestCode == Constants.SelectFilePermissionRequestCode)
|
||||
{
|
||||
flags |= ActivityFlags.NewDocument;
|
||||
if (grantResults.Any(r => r != Permission.Granted))
|
||||
{
|
||||
_messagingService.Send("selectFileCameraPermissionDenied");
|
||||
}
|
||||
await _deviceActionService.SelectFileAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
// noinspection deprecation
|
||||
flags |= ActivityFlags.ClearWhenTaskReset;
|
||||
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
intent.AddFlags(flags);
|
||||
return intent;
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
if (resultCode == Result.Ok &&
|
||||
(requestCode == Constants.SelectFileRequestCode || requestCode == Constants.SaveFileRequestCode))
|
||||
{
|
||||
Android.Net.Uri uri = null;
|
||||
string fileName = null;
|
||||
if (data != null && data.Data != null)
|
||||
{
|
||||
uri = data.Data;
|
||||
fileName = AndroidHelpers.GetFileName(ApplicationContext, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// camera
|
||||
var file = new Java.IO.File(FilesDir, "temp_camera_photo.jpg");
|
||||
uri = FileProvider.GetUriForFile(this, "com.x8bit.bitwarden.fileprovider", file);
|
||||
fileName = $"photo_{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.jpg";
|
||||
}
|
||||
|
||||
if (uri == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == Constants.SaveFileRequestCode)
|
||||
{
|
||||
_messagingService.Send("selectSaveFileResult",
|
||||
new Tuple<string, string>(uri.ToString(), fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var stream = ContentResolver.OpenInputStream(uri))
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
stream.CopyTo(memoryStream);
|
||||
_messagingService.Send("selectFileResult",
|
||||
new Tuple<byte[], string>(memoryStream.ToArray(), fileName ?? "unknown_file_name"));
|
||||
}
|
||||
}
|
||||
catch (Java.IO.FileNotFoundException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
_broadcasterService.Unsubscribe(_activityKey);
|
||||
}
|
||||
|
||||
private void ListenYubiKey(bool listen)
|
||||
{
|
||||
if (!_deviceActionService.SupportsNfc())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var adapter = NfcAdapter.GetDefaultAdapter(this);
|
||||
if (listen)
|
||||
{
|
||||
var intent = new Intent(this, Class);
|
||||
intent.AddFlags(ActivityFlags.SingleTop);
|
||||
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
|
||||
// register for all NDEF tags starting with http och https
|
||||
var ndef = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
|
||||
ndef.AddDataScheme("http");
|
||||
ndef.AddDataScheme("https");
|
||||
var filters = new IntentFilter[] { ndef };
|
||||
try
|
||||
{
|
||||
// register for foreground dispatch so we'll receive tags according to our intent filters
|
||||
adapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
adapter.DisableForegroundDispatch(this);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private AppOptions GetOptions()
|
||||
{
|
||||
var options = new AppOptions
|
||||
{
|
||||
Uri = Intent.GetStringExtra("uri") ?? Intent.GetStringExtra("autofillFrameworkUri"),
|
||||
MyVaultTile = Intent.GetBooleanExtra("myVaultTile", false),
|
||||
GeneratorTile = Intent.GetBooleanExtra("generatorTile", false),
|
||||
FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false),
|
||||
CreateSend = GetCreateSendRequest(Intent)
|
||||
};
|
||||
var fillType = Intent.GetIntExtra("autofillFrameworkFillType", 0);
|
||||
if (fillType > 0)
|
||||
{
|
||||
options.FillType = (CipherType)fillType;
|
||||
}
|
||||
if (Intent.GetBooleanExtra("autofillFrameworkSave", false))
|
||||
{
|
||||
options.SaveType = (CipherType)Intent.GetIntExtra("autofillFrameworkType", 0);
|
||||
options.SaveName = Intent.GetStringExtra("autofillFrameworkName");
|
||||
options.SaveUsername = Intent.GetStringExtra("autofillFrameworkUsername");
|
||||
options.SavePassword = Intent.GetStringExtra("autofillFrameworkPassword");
|
||||
options.SaveCardName = Intent.GetStringExtra("autofillFrameworkCardName");
|
||||
options.SaveCardNumber = Intent.GetStringExtra("autofillFrameworkCardNumber");
|
||||
options.SaveCardExpMonth = Intent.GetStringExtra("autofillFrameworkCardExpMonth");
|
||||
options.SaveCardExpYear = Intent.GetStringExtra("autofillFrameworkCardExpYear");
|
||||
options.SaveCardCode = Intent.GetStringExtra("autofillFrameworkCardCode");
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
private Tuple<SendType, string, byte[], string> GetCreateSendRequest(Intent intent)
|
||||
{
|
||||
if (intent.Action == Intent.ActionSend && intent.Type != null)
|
||||
{
|
||||
if ((intent.Flags & ActivityFlags.LaunchedFromHistory) == ActivityFlags.LaunchedFromHistory)
|
||||
{
|
||||
// don't re-deliver intent if resuming from app switcher
|
||||
return null;
|
||||
}
|
||||
var type = intent.Type;
|
||||
if (type.Contains("text/"))
|
||||
{
|
||||
var subject = intent.GetStringExtra(Intent.ExtraSubject);
|
||||
var text = intent.GetStringExtra(Intent.ExtraText);
|
||||
return new Tuple<SendType, string, byte[], string>(SendType.Text, subject, null, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = intent.ClipData?.GetItemAt(0);
|
||||
var uri = data?.Uri;
|
||||
var filename = AndroidHelpers.GetFileName(ApplicationContext, uri);
|
||||
try
|
||||
{
|
||||
using (var stream = ContentResolver.OpenInputStream(uri))
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
stream.CopyTo(memoryStream);
|
||||
return new Tuple<SendType, string, byte[], string>(SendType.File, filename, memoryStream.ToArray(), null);
|
||||
}
|
||||
}
|
||||
catch (Java.IO.FileNotFoundException) { }
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ParseYubiKey(string data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var otpMatch = _otpPattern.Matcher(data);
|
||||
if (otpMatch.Matches())
|
||||
{
|
||||
var otp = otpMatch.Group(1);
|
||||
_messagingService.Send("gotYubiKeyOTP", otp);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTheme(string theme)
|
||||
{
|
||||
if (theme == "light")
|
||||
{
|
||||
SetTheme(Resource.Style.LightTheme);
|
||||
}
|
||||
else if (theme == "dark")
|
||||
{
|
||||
SetTheme(Resource.Style.DarkTheme);
|
||||
}
|
||||
else if (theme == "black")
|
||||
{
|
||||
SetTheme(Resource.Style.BlackTheme);
|
||||
}
|
||||
else if (theme == "nord")
|
||||
{
|
||||
SetTheme(Resource.Style.NordTheme);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_deviceActionService.UsingDarkTheme())
|
||||
{
|
||||
SetTheme(Resource.Style.DarkTheme);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTheme(Resource.Style.LightTheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RestartApp()
|
||||
{
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
var pendingIntent = PendingIntent.GetActivity(this, 5923650, intent, PendingIntentFlags.CancelCurrent);
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + 500;
|
||||
alarmManager.Set(AlarmType.Rtc, triggerMs, pendingIntent);
|
||||
Java.Lang.JavaSystem.Exit(0);
|
||||
}
|
||||
|
||||
private void ExitApp()
|
||||
{
|
||||
FinishAffinity();
|
||||
Java.Lang.JavaSystem.Exit(0);
|
||||
}
|
||||
|
||||
private async Task ClearClipboardAlarmAsync(Tuple<string, int?, bool> data)
|
||||
{
|
||||
if (data.Item3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var clearMs = data.Item2;
|
||||
if (clearMs == null)
|
||||
{
|
||||
var clearSeconds = await _storageService.GetAsync<int?>(Constants.ClearClipboardKey);
|
||||
if (clearSeconds != null)
|
||||
{
|
||||
clearMs = clearSeconds.Value * 1000;
|
||||
}
|
||||
}
|
||||
if (clearMs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);
|
||||
}
|
||||
|
||||
private void StartEventAlarm()
|
||||
{
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
alarmManager.SetInexactRepeating(AlarmType.ElapsedRealtime, 120000, 300000, _eventUploadPendingIntent);
|
||||
}
|
||||
|
||||
private async Task StopEventAlarmAsync()
|
||||
{
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
alarmManager.Cancel(_eventUploadPendingIntent);
|
||||
await _eventService.UploadEventsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,228 +1,154 @@
|
||||
using System;
|
||||
using Acr.UserDialogs;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Bit.Android.Services;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Repositories;
|
||||
using Bit.App.Services;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Plugin.Connectivity;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Droid.Services;
|
||||
using Bit.Droid.Utilities;
|
||||
using Plugin.CurrentActivity;
|
||||
using Plugin.Fingerprint;
|
||||
using Plugin.Settings;
|
||||
using PushNotification.Plugin;
|
||||
using PushNotification.Plugin.Abstractions;
|
||||
using XLabs.Ioc;
|
||||
using XLabs.Ioc.Unity;
|
||||
using System.Threading.Tasks;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Xamarin.Android.Net;
|
||||
#if !FDROID
|
||||
using Android.Gms.Security;
|
||||
#endif
|
||||
|
||||
namespace Bit.Android
|
||||
namespace Bit.Droid
|
||||
{
|
||||
#if DEBUG
|
||||
[Application(Debuggable = true)]
|
||||
#else
|
||||
[Application(Debuggable = false)]
|
||||
#endif
|
||||
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
|
||||
[Register("com.x8bit.bitwarden.MainApplication")]
|
||||
#if FDROID
|
||||
public class MainApplication : Application
|
||||
#else
|
||||
public class MainApplication : Application, ProviderInstaller.IProviderInstallListener
|
||||
#endif
|
||||
{
|
||||
private const string FirstLaunchKey = "firstLaunch";
|
||||
private const string LastVersionCodeKey = "lastVersionCode";
|
||||
|
||||
public static Context AppContext;
|
||||
|
||||
public MainApplication(IntPtr handle, JniHandleOwnership transer)
|
||||
: base(handle, transer)
|
||||
{
|
||||
if(!Resolver.IsSet)
|
||||
if (ServiceContainer.RegisteredServices.Count == 0)
|
||||
{
|
||||
SetIoc();
|
||||
RegisterLocalServices();
|
||||
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||
ServiceContainer.Init(deviceActionService.DeviceUserAgent, Constants.ClearCiphersCacheKey,
|
||||
Constants.AndroidAllClearCipherCacheKeys);
|
||||
}
|
||||
#if !FDROID
|
||||
if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)
|
||||
{
|
||||
ProviderInstaller.InstallIfNeededAsync(ApplicationContext, this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
|
||||
// workaround for app compat bug
|
||||
// ref https://forums.xamarin.com/discussion/62414/app-resuming-results-in-crash-with-formsappcompatactivity
|
||||
Task.Delay(10).Wait();
|
||||
|
||||
RegisterActivityLifecycleCallbacks(this);
|
||||
AppContext = ApplicationContext;
|
||||
StartPushService();
|
||||
HandlePushReregistration();
|
||||
Bootstrap();
|
||||
CrossCurrentActivity.Current.Init(this);
|
||||
}
|
||||
|
||||
private void HandlePushReregistration()
|
||||
public void OnProviderInstallFailed(int errorCode, Intent recoveryIntent)
|
||||
{
|
||||
var pushNotification = Resolver.Resolve<IPushNotification>();
|
||||
var settings = Resolver.Resolve<ISettings>();
|
||||
}
|
||||
|
||||
// Reregister for push token based on certain conditions
|
||||
// ref https://github.com/rdelrosario/xamarin-plugins/issues/65
|
||||
public void OnProviderInstalled()
|
||||
{
|
||||
}
|
||||
|
||||
var reregister = false;
|
||||
private void RegisterLocalServices()
|
||||
{
|
||||
ServiceContainer.Register<ILogService>("logService", new AndroidLogService());
|
||||
|
||||
// 1. First time starting the app after a new install
|
||||
if(settings.GetValueOrDefault(FirstLaunchKey, true))
|
||||
// Note: This might cause a race condition. Investigate more.
|
||||
Task.Run(() =>
|
||||
{
|
||||
settings.AddOrUpdateValue(FirstLaunchKey, false);
|
||||
reregister = true;
|
||||
}
|
||||
|
||||
// 2. App version changed (installed update)
|
||||
var versionCode = Context.ApplicationContext.PackageManager.GetPackageInfo(Context.PackageName, 0).VersionCode;
|
||||
if(settings.GetValueOrDefault(LastVersionCodeKey, -1) != versionCode)
|
||||
{
|
||||
settings.AddOrUpdateValue(LastVersionCodeKey, versionCode);
|
||||
reregister = true;
|
||||
}
|
||||
|
||||
// 3. In debug mode
|
||||
if(InDebugMode())
|
||||
{
|
||||
reregister = true;
|
||||
}
|
||||
|
||||
// 4. Doesn't have a push token currently
|
||||
if(string.IsNullOrWhiteSpace(pushNotification.Token))
|
||||
{
|
||||
reregister = true;
|
||||
}
|
||||
|
||||
if(reregister)
|
||||
{
|
||||
pushNotification.Unregister();
|
||||
if(Resolver.Resolve<IAuthService>().IsAuthenticated)
|
||||
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
|
||||
FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
|
||||
{
|
||||
pushNotification.Register();
|
||||
}
|
||||
}
|
||||
}
|
||||
FadeAnimationEnabled = false,
|
||||
FadeAnimationForCachedImages = false
|
||||
});
|
||||
ZXing.Net.Mobile.Forms.Android.Platform.Init();
|
||||
});
|
||||
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
|
||||
|
||||
private bool InDebugMode()
|
||||
{
|
||||
#if DEBUG
|
||||
return true;
|
||||
var preferencesStorage = new PreferencesStorageService(null);
|
||||
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
|
||||
var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));
|
||||
var localizeService = new LocalizeService();
|
||||
var broadcasterService = new BroadcasterService();
|
||||
var messagingService = new MobileBroadcasterMessagingService(broadcasterService);
|
||||
var i18nService = new MobileI18nService(localizeService.GetCurrentCultureInfo());
|
||||
var secureStorageService = new SecureStorageService();
|
||||
var cryptoPrimitiveService = new CryptoPrimitiveService();
|
||||
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
|
||||
var deviceActionService = new DeviceActionService(mobileStorageService, messagingService,
|
||||
broadcasterService, () => ServiceContainer.Resolve<IEventService>("eventService"));
|
||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
|
||||
broadcasterService);
|
||||
var biometricService = new BiometricService();
|
||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||
var cryptoService = new CryptoService(mobileStorageService, secureStorageService, cryptoFunctionService);
|
||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
||||
|
||||
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);
|
||||
ServiceContainer.Register<IMessagingService>("messagingService", messagingService);
|
||||
ServiceContainer.Register<ILocalizeService>("localizeService", localizeService);
|
||||
ServiceContainer.Register<II18nService>("i18nService", i18nService);
|
||||
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", cryptoPrimitiveService);
|
||||
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
||||
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
||||
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
||||
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
||||
ServiceContainer.Register<IBiometricService>("biometricService", biometricService);
|
||||
ServiceContainer.Register<ICryptoFunctionService>("cryptoFunctionService", cryptoFunctionService);
|
||||
ServiceContainer.Register<ICryptoService>("cryptoService", cryptoService);
|
||||
ServiceContainer.Register<IPasswordRepromptService>("passwordRepromptService", passwordRepromptService);
|
||||
|
||||
// Push
|
||||
#if FDROID
|
||||
ServiceContainer.Register<IPushNotificationListenerService>(
|
||||
"pushNotificationListenerService", new NoopPushNotificationListenerService());
|
||||
ServiceContainer.Register<IPushNotificationService>(
|
||||
"pushNotificationService", new NoopPushNotificationService());
|
||||
#else
|
||||
return false;
|
||||
var notificationListenerService = new PushNotificationListenerService();
|
||||
ServiceContainer.Register<IPushNotificationListenerService>(
|
||||
"pushNotificationListenerService", notificationListenerService);
|
||||
var androidPushNotificationService = new AndroidPushNotificationService(
|
||||
mobileStorageService, notificationListenerService);
|
||||
ServiceContainer.Register<IPushNotificationService>(
|
||||
"pushNotificationService", androidPushNotificationService);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OnTerminate()
|
||||
private void Bootstrap()
|
||||
{
|
||||
base.OnTerminate();
|
||||
UnregisterActivityLifecycleCallbacks(this);
|
||||
(ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService).Init();
|
||||
ServiceContainer.Resolve<IAuthService>("authService").Init();
|
||||
// Note: This is not awaited
|
||||
var bootstrapTask = BootstrapAsync();
|
||||
}
|
||||
|
||||
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
|
||||
private async Task BootstrapAsync()
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivityDestroyed(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityPaused(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityResumed(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityStarted(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivityStopped(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public static void StartPushService()
|
||||
{
|
||||
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
|
||||
if(Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
|
||||
{
|
||||
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext,
|
||||
typeof(PushNotificationService)), 0);
|
||||
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(AlarmService);
|
||||
alarm.Cancel(pintent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void StopPushService()
|
||||
{
|
||||
AppContext.StopService(new Intent(AppContext, typeof(PushNotificationService)));
|
||||
if(Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
|
||||
{
|
||||
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext,
|
||||
typeof(PushNotificationService)), 0);
|
||||
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(AlarmService);
|
||||
alarm.Cancel(pintent);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetIoc()
|
||||
{
|
||||
UserDialogs.Init(this);
|
||||
|
||||
var container = new UnityContainer();
|
||||
|
||||
container
|
||||
// Android Stuff
|
||||
.RegisterInstance(ApplicationContext)
|
||||
.RegisterInstance<Application>(this)
|
||||
// Services
|
||||
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISecureStorageService, KeyStoreStorageService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IKeyDerivationService, BouncyCastleKeyDerivationService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IFolderService, FolderService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISiteService, SiteService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISyncService, SyncService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IClipboardService, ClipboardService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IPushNotificationListener, PushNotificationListener>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IAppIdService, AppIdService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IPasswordGenerationService, PasswordGenerationService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IReflectionService, ReflectionService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ILockService, LockService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IAppInfoService, AppInfoService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IGoogleAnalyticsService, GoogleAnalyticsService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IDeviceInfoService, DeviceInfoService>(new ContainerControlledLifetimeManager())
|
||||
// Repositories
|
||||
.RegisterType<IFolderRepository, FolderRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IFolderApiRepository, FolderApiRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISiteRepository, SiteRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISiteApiRepository, SiteApiRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IAuthApiRepository, AuthApiRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IDeviceApiRepository, DeviceApiRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<IAccountsApiRepository, AccountsApiRepository>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ICipherApiRepository, CipherApiRepository>(new ContainerControlledLifetimeManager())
|
||||
// Other
|
||||
.RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager())
|
||||
.RegisterInstance(CrossConnectivity.Current, new ContainerControlledLifetimeManager())
|
||||
.RegisterInstance(UserDialogs.Instance, new ContainerControlledLifetimeManager())
|
||||
.RegisterInstance(CrossFingerprint.Current, new ContainerControlledLifetimeManager());
|
||||
|
||||
CrossPushNotification.Initialize(container.Resolve<IPushNotificationListener>(), "962181367620");
|
||||
container.RegisterInstance(CrossPushNotification.Current, new ContainerControlledLifetimeManager());
|
||||
|
||||
Resolver.SetResolver(new UnityResolver(container));
|
||||
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
|
||||
var disableFavicon = await ServiceContainer.Resolve<IStorageService>("storageService")
|
||||
.GetAsync<bool?>(Constants.DisableFaviconKey);
|
||||
await ServiceContainer.Resolve<IStateService>("stateService").SaveAsync(
|
||||
Constants.DisableFaviconKey, disableFavicon);
|
||||
await ServiceContainer.Resolve<IEnvironmentService>("environmentService").SetUrlsFromStorageAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="0.0.4" android:installLocation="auto" android:versionCode="4">
|
||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
<uses-permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<application android:label="bitwarden" android:theme="@style/BitwardenTheme"></application>
|
||||
</manifest>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="1"
|
||||
android:versionName="2.11.1"
|
||||
android:installLocation="internalOnly"
|
||||
package="com.x8bit.bitwarden">
|
||||
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
|
||||
<application
|
||||
android:label="Bitwarden"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:allowBackup="false"
|
||||
tools:replace="android:allowBackup"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.x8bit.bitwarden.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
|
||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions" />
|
||||
|
||||
<!-- Support for Samsung "Multi Window" mode (for Android < 7.0 users) -->
|
||||
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true" />
|
||||
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true" />
|
||||
|
||||
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
|
||||
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true" />
|
||||
</application>
|
||||
|
||||
<!-- Package visibility (for Android 11+) -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="*"/>
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Android.App;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
@@ -9,9 +7,9 @@ using Android.App;
|
||||
[assembly: AssemblyTitle("BitwardenAndroid")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("8bit Solutions LLC")]
|
||||
[assembly: AssemblyProduct("bitwarden")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyCompany("Bitwarden Inc.")]
|
||||
[assembly: AssemblyProduct("Bitwarden")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
@@ -28,7 +26,3 @@ using Android.App;
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
// Add some common permissions, these can be removed if not needed
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
||||
51
src/Android/Push/FirebaseMessagingService.cs
Normal file
51
src/Android/Push/FirebaseMessagingService.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
#if !FDROID
|
||||
using Android.App;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Firebase.Messaging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.Droid.Push
|
||||
{
|
||||
[Service(Exported=false)]
|
||||
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
|
||||
public class FirebaseMessagingService : Firebase.Messaging.FirebaseMessagingService
|
||||
{
|
||||
public async override void OnNewToken(string token)
|
||||
{
|
||||
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
var pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService");
|
||||
|
||||
await storageService.SaveAsync(Core.Constants.PushRegisteredTokenKey, token);
|
||||
await pushNotificationService.RegisterAsync();
|
||||
}
|
||||
|
||||
public async override void OnMessageReceived(RemoteMessage message)
|
||||
{
|
||||
if (message?.Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var data = message.Data.ContainsKey("data") ? message.Data["data"] : null;
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var obj = JObject.Parse(data);
|
||||
var listener = ServiceContainer.Resolve<IPushNotificationListenerService>(
|
||||
"pushNotificationListenerService");
|
||||
await listener.OnMessageAsync(obj, Device.Android);
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
14
src/Android/Receivers/ClearClipboardAlarmReceiver.cs
Normal file
14
src/Android/Receivers/ClearClipboardAlarmReceiver.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Android.Content;
|
||||
|
||||
namespace Bit.Droid.Receivers
|
||||
{
|
||||
[BroadcastReceiver(Name = "com.x8bit.bitwarden.ClearClipboardAlarmReceiver", Exported = false)]
|
||||
public class ClearClipboardAlarmReceiver : BroadcastReceiver
|
||||
{
|
||||
public override void OnReceive(Context context, Intent intent)
|
||||
{
|
||||
var clipboardManager = context.GetSystemService(Context.ClipboardService) as ClipboardManager;
|
||||
clipboardManager.PrimaryClip = ClipData.NewPlainText("bitwarden", " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Android/Receivers/EventUploadReceiver.cs
Normal file
16
src/Android/Receivers/EventUploadReceiver.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Android.Content;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Droid.Receivers
|
||||
{
|
||||
[BroadcastReceiver(Name = "com.x8bit.bitwarden.EventUploadReceiver", Exported = false)]
|
||||
public class EventUploadReceiver : BroadcastReceiver
|
||||
{
|
||||
public async override void OnReceive(Context context, Intent intent)
|
||||
{
|
||||
var eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||
await eventService.UploadEventsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/Android/Receivers/PackageReplacedReceiver.cs
Normal file
22
src/Android/Receivers/PackageReplacedReceiver.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Droid.Receivers
|
||||
{
|
||||
[BroadcastReceiver(Name = "com.x8bit.bitwarden.PackageReplacedReceiver", Exported = false)]
|
||||
[IntentFilter(new[] { Intent.ActionMyPackageReplaced })]
|
||||
public class PackageReplacedReceiver : BroadcastReceiver
|
||||
{
|
||||
public override async void OnReceive(Context context, Intent intent)
|
||||
{
|
||||
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
await AppHelpers.PerformUpdateTasksAsync(ServiceContainer.Resolve<ISyncService>("syncService"),
|
||||
ServiceContainer.Resolve<IDeviceActionService>("deviceActionService"), storageService);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Android/Receivers/RestrictionsChangedReceiver.cs
Normal file
23
src/Android/Receivers/RestrictionsChangedReceiver.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Droid.Utilities;
|
||||
|
||||
namespace Bit.Droid.Receivers
|
||||
{
|
||||
[BroadcastReceiver(Name = "com.x8bit.bitwarden.RestrictionsChangedReceiver", Exported = false)]
|
||||
[IntentFilter(new[] { Intent.ActionApplicationRestrictionsChanged })]
|
||||
public class RestrictionsChangedReceiver : BroadcastReceiver
|
||||
{
|
||||
public async override void OnReceive(Context context, Intent intent)
|
||||
{
|
||||
if (intent.Action == Intent.ActionApplicationRestrictionsChanged)
|
||||
{
|
||||
await AndroidHelpers.SetPreconfiguredRestrictionSettingsAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Android/Renderers/CustomEditorRenderer.cs
Normal file
37
src/Android/Renderers/CustomEditorRenderer.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Android.Content;
|
||||
using Android.Views.InputMethods;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomEditorRenderer : EditorRenderer
|
||||
{
|
||||
public CustomEditorRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
// Workaround for issue described here:
|
||||
// https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651
|
||||
protected override void OnAttachedToWindow()
|
||||
{
|
||||
base.OnAttachedToWindow();
|
||||
EditText.Enabled = false;
|
||||
EditText.Enabled = true;
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
||||
Control.PaddingBottom + 20);
|
||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
||||
(ImeAction)ImeFlags.NoExtractUi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/Android/Renderers/CustomEntryRenderer.cs
Normal file
73
src/Android/Renderers/CustomEntryRenderer.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Text;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.Widget;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomEntryRenderer : EntryRenderer
|
||||
{
|
||||
public CustomEntryRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
||||
Control.PaddingBottom + 20);
|
||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
||||
(ImeAction)ImeFlags.NoExtractUi;
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for failure to disable text prediction on non-password fields
|
||||
// see https://github.com/xamarin/Xamarin.Forms/issues/10857
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
// Check if changed property is "IsPassword", otherwise ignore
|
||||
if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
|
||||
{
|
||||
// Check if field type is text, otherwise ignore (numeric passwords, etc.)
|
||||
EditText.InputType = Element.Keyboard.ToInputType();
|
||||
bool isText = (EditText.InputType & InputTypes.ClassText) == InputTypes.ClassText,
|
||||
isNumber = (EditText.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber;
|
||||
if (isText || isNumber)
|
||||
{
|
||||
if (Element.IsPassword)
|
||||
{
|
||||
// Element is a password field, set inputType to TextVariationPassword which disables
|
||||
// predictive text by default
|
||||
EditText.InputType = EditText.InputType |
|
||||
(isText ? InputTypes.TextVariationPassword : InputTypes.NumberVariationPassword);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Element is not a password field, set inputType to TextVariationVisiblePassword to
|
||||
// disable predictive text while still displaying the content.
|
||||
EditText.InputType = EditText.InputType |
|
||||
(isText ? InputTypes.TextVariationVisiblePassword : InputTypes.NumberVariationNormal);
|
||||
}
|
||||
|
||||
// The workaround above forces a reset of the style properties, so we need to re-apply the font.
|
||||
// see https://xamarin.github.io/bugzilla-archives/33/33666/bug.html
|
||||
var typeface = Typeface.CreateFromAsset(Context.Assets, "RobotoMono_Regular.ttf");
|
||||
if (Control is TextView label)
|
||||
{
|
||||
label.Typeface = typeface;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/Android/Renderers/CustomPickerRenderer.cs
Normal file
25
src/Android/Renderers/CustomPickerRenderer.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Android.Content;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomPickerRenderer : PickerRenderer
|
||||
{
|
||||
public CustomPickerRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
||||
Control.PaddingBottom + 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/Android/Renderers/CustomSearchBarRenderer.cs
Normal file
33
src/Android/Renderers/CustomSearchBarRenderer.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Android.Content;
|
||||
using Android.Views.InputMethods;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
||||
{
|
||||
public CustomSearchBarRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var magId = Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
||||
var magImage = (Android.Widget.ImageView)Control.FindViewById(magId);
|
||||
magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
|
||||
}
|
||||
catch { }
|
||||
Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
||||
(ImeAction)ImeFlags.NoExtractUi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/Android/Renderers/CustomTabbedRenderer.cs
Normal file
60
src/Android/Renderers/CustomTabbedRenderer.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.Droid.Renderers;
|
||||
using Google.Android.Material.BottomNavigation;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Xamarin.Forms.Platform.Android.AppCompat;
|
||||
|
||||
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomTabbedRenderer : TabbedPageRenderer, BottomNavigationView.IOnNavigationItemReselectedListener
|
||||
{
|
||||
private TabbedPage _page;
|
||||
|
||||
public CustomTabbedRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
_page = e.NewElement;
|
||||
GetBottomNavigationView()?.SetOnNavigationItemReselectedListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
_page = e.OldElement;
|
||||
}
|
||||
}
|
||||
|
||||
private BottomNavigationView GetBottomNavigationView()
|
||||
{
|
||||
for (var i = 0; i < ViewGroup.ChildCount; i++)
|
||||
{
|
||||
var childView = ViewGroup.GetChildAt(i);
|
||||
if (childView is ViewGroup viewGroup)
|
||||
{
|
||||
for (var j = 0; j < viewGroup.ChildCount; j++)
|
||||
{
|
||||
var childRelativeLayoutView = viewGroup.GetChildAt(j);
|
||||
if (childRelativeLayoutView is BottomNavigationView bottomNavigationView)
|
||||
{
|
||||
return bottomNavigationView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async void BottomNavigationView.IOnNavigationItemReselectedListener.OnNavigationItemReselected(IMenuItem item)
|
||||
{
|
||||
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
|
||||
{
|
||||
await _page.CurrentPage.Navigation.PopToRootAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Android/Renderers/ExtendedDatePickerRenderer.cs
Normal file
50
src/Android/Renderers/ExtendedDatePickerRenderer.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedDatePickerRenderer : DatePickerRenderer
|
||||
{
|
||||
public ExtendedDatePickerRenderer(Context context)
|
||||
: base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && Element is ExtendedDatePicker element)
|
||||
{
|
||||
// center text
|
||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
||||
|
||||
// use placeholder until NullableDate set
|
||||
if (!element.NullableDate.HasValue)
|
||||
{
|
||||
Control.Text = element.PlaceHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == DatePicker.DateProperty.PropertyName ||
|
||||
e.PropertyName == DatePicker.FormatProperty.PropertyName)
|
||||
{
|
||||
if (Control != null && Element is ExtendedDatePicker element)
|
||||
{
|
||||
if (Element.Format == element.PlaceHolder)
|
||||
{
|
||||
Control.Text = element.PlaceHolder;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/Android/Renderers/ExtendedGridRenderer.cs
Normal file
43
src/Android/Renderers/ExtendedGridRenderer.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Android.Content;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedGridRenderer : ViewRenderer
|
||||
{
|
||||
private static int? _bgResId;
|
||||
|
||||
public ExtendedGridRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(GetBgResId());
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBgResId()
|
||||
{
|
||||
if (_bgResId == null)
|
||||
{
|
||||
if (ThemeManager.GetTheme(true) == "nord")
|
||||
{
|
||||
_bgResId = Resource.Drawable.list_item_bg_nord;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
|
||||
Resource.Drawable.list_item_bg_dark;
|
||||
}
|
||||
}
|
||||
return _bgResId.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/Android/Renderers/ExtendedSliderRenderer.cs
Normal file
40
src/Android/Renderers/ExtendedSliderRenderer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using AndroidX.Core.Content.Resources;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedSlider), typeof(ExtendedSliderRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedSliderRenderer : SliderRenderer
|
||||
{
|
||||
public ExtendedSliderRenderer(Context context)
|
||||
: base(context)
|
||||
{}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && Element is ExtendedSlider view)
|
||||
{
|
||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
|
||||
if (t is GradientDrawable thumb)
|
||||
{
|
||||
if (view.ThumbColor == Color.Default)
|
||||
{
|
||||
thumb.SetColor(Color.White.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
thumb.SetColor(view.ThumbColor.ToAndroid());
|
||||
}
|
||||
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
|
||||
Control.SetThumb(thumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/Android/Renderers/ExtendedStackLayoutRenderer.cs
Normal file
43
src/Android/Renderers/ExtendedStackLayoutRenderer.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Android.Content;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedStackLayoutRenderer : ViewRenderer
|
||||
{
|
||||
private static int? _bgResId;
|
||||
|
||||
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(GetBgResId());
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBgResId()
|
||||
{
|
||||
if (_bgResId == null)
|
||||
{
|
||||
if (ThemeManager.GetTheme(true) == "nord")
|
||||
{
|
||||
_bgResId = Resource.Drawable.list_item_bg_nord;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
|
||||
Resource.Drawable.list_item_bg_dark;
|
||||
}
|
||||
}
|
||||
return _bgResId.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Android/Renderers/ExtendedTimePickerRenderer.cs
Normal file
50
src/Android/Renderers/ExtendedTimePickerRenderer.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedTimePickerRenderer : TimePickerRenderer
|
||||
{
|
||||
public ExtendedTimePickerRenderer(Context context)
|
||||
: base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && Element is ExtendedTimePicker element)
|
||||
{
|
||||
// center text
|
||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
||||
|
||||
// use placeholder until NullableTime set
|
||||
if (!element.NullableTime.HasValue)
|
||||
{
|
||||
Control.Text = element.PlaceHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == TimePicker.TimeProperty.PropertyName ||
|
||||
e.PropertyName == TimePicker.FormatProperty.PropertyName)
|
||||
{
|
||||
if (Control != null && Element is ExtendedTimePicker element)
|
||||
{
|
||||
if (Element.Format == element.PlaceHolder)
|
||||
{
|
||||
Control.Text = element.PlaceHolder;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
98
src/Android/Renderers/HybridWebViewRenderer.cs
Normal file
98
src/Android/Renderers/HybridWebViewRenderer.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Android.Webkit;
|
||||
using AWebkit = Android.Webkit;
|
||||
using Java.Interop;
|
||||
using Android.Content;
|
||||
using Bit.Droid.Renderers;
|
||||
using System.ComponentModel;
|
||||
|
||||
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, AWebkit.WebView>
|
||||
{
|
||||
private const string JSFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
|
||||
|
||||
private readonly Context _context;
|
||||
|
||||
public HybridWebViewRenderer(Context context)
|
||||
: base(context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control == null)
|
||||
{
|
||||
var webView = new AWebkit.WebView(_context);
|
||||
webView.Settings.JavaScriptEnabled = true;
|
||||
webView.SetWebViewClient(new JSWebViewClient(string.Format("javascript: {0}", JSFunction)));
|
||||
SetNativeControl(webView);
|
||||
}
|
||||
if (e.OldElement != null)
|
||||
{
|
||||
Control.RemoveJavascriptInterface("jsBridge");
|
||||
var hybridWebView = e.OldElement as HybridWebView;
|
||||
hybridWebView.Cleanup();
|
||||
}
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
|
||||
Control.LoadUrl(Element.Uri);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == HybridWebView.UriProperty.PropertyName)
|
||||
{
|
||||
Control.LoadUrl(Element.Uri);
|
||||
}
|
||||
}
|
||||
|
||||
public class JSBridge : Java.Lang.Object
|
||||
{
|
||||
private readonly WeakReference<HybridWebViewRenderer> _hybridWebViewRenderer;
|
||||
|
||||
public JSBridge(HybridWebViewRenderer hybridRenderer)
|
||||
{
|
||||
_hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
|
||||
}
|
||||
|
||||
[JavascriptInterface]
|
||||
[Export("invokeAction")]
|
||||
public void InvokeAction(string data)
|
||||
{
|
||||
if (_hybridWebViewRenderer != null &&
|
||||
_hybridWebViewRenderer.TryGetTarget(out HybridWebViewRenderer hybridRenderer))
|
||||
{
|
||||
hybridRenderer.Element.InvokeAction(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class JSWebViewClient : WebViewClient
|
||||
{
|
||||
private readonly string _javascript;
|
||||
|
||||
public JSWebViewClient(string javascript)
|
||||
{
|
||||
_javascript = javascript;
|
||||
|
||||
}
|
||||
|
||||
public override void OnPageFinished(AWebkit.WebView view, string url)
|
||||
{
|
||||
base.OnPageFinished(view, url);
|
||||
view.EvaluateJavascript(_javascript, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user