1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00

Compare commits

...

1048 Commits

Author SHA1 Message Date
Kyle Spearrin
28166f79a1 ACCESS_NETWORK_STATE permission 2019-06-13 12:02:36 -04:00
Kyle Spearrin
2fe67137c5 more fdroid build cleanup of google services 2019-06-13 10:06:21 -04:00
Kyle Spearrin
a6ea2de691 bump version 2019-06-13 10:06:21 -04:00
Kyle Spearrin
7ffcde002e small delay before calling LoadAsync 2019-06-13 10:06:21 -04:00
Kyle Spearrin
a3f66b8ab1 chmod keystore correct path 2019-06-13 10:06:21 -04:00
Kyle Spearrin
43cee53dc8 make sure totp copy isn't available if not premium 2019-06-13 10:06:21 -04:00
Kyle Spearrin
6c5979040f New translations AppResources.resx (Hebrew) (#535) 2019-06-13 08:28:59 -04:00
Kyle Spearrin
666291d12d update publisher api 2019-06-13 00:54:42 -04:00
Kyle Spearrin
c04a8ccdc2 New Crowdin translations (#534)
* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Portuguese, Brazilian)
2019-06-12 23:00:39 -04:00
Kyle Spearrin
b13d2f7f91 dot for fallback text. resolves #531 2019-06-12 22:21:47 -04:00
Kyle Spearrin
0b56dd2795 null checks 2019-06-12 21:49:52 -04:00
Kyle Spearrin
028ebff102 activity key and unsub when activity destroyed 2019-06-12 21:49:43 -04:00
Kyle Spearrin
cd60c3da2a fixed size icons 2019-06-12 09:13:13 -04:00
Kyle Spearrin
3d239a3c2b selectable label effect 2019-06-12 08:31:33 -04:00
Kyle Spearrin
26d0077bb8 delay search to 500 ms 2019-06-12 08:12:55 -04:00
Kyle Spearrin
5dbe9e5ca2 add lots of misc thigns to appdelegate 2019-06-11 23:04:41 -04:00
Kyle Spearrin
5aac96edb5 remove XF reference 2019-06-11 22:27:39 -04:00
Kyle Spearrin
c45b62fa6e icons and splash screen 2019-06-11 22:20:59 -04:00
Kyle Spearrin
e05708979d close buttons for ios 2019-06-11 21:31:51 -04:00
Kyle Spearrin
b6e7db6ecf custom content page renderer for left nav items 2019-06-11 20:57:12 -04:00
Kyle Spearrin
17060a2a1b dont link on debug 2019-06-11 20:47:01 -04:00
Kyle Spearrin
389fbc31e9 bootstrap ios 2019-06-11 16:01:56 -04:00
Kyle Spearrin
da3c3c30e7 MtouchLink sdkonly 2019-06-11 15:41:32 -04:00
Kyle Spearrin
42a7086088 info and entitlements plists 2019-06-11 15:31:32 -04:00
Kyle Spearrin
5d4cc007bb bootstrap ios 2019-06-11 15:20:28 -04:00
Kyle Spearrin
a8dfb8e2b9 add back ios project 2019-06-11 14:46:11 -04:00
Kyle Spearrin
873999336f added ios core project 2019-06-11 11:07:56 -04:00
Kyle Spearrin
8476f53337 try create uri 2019-06-11 11:00:34 -04:00
Kyle Spearrin
31a77a6e19 autofocus prompt input 2019-06-10 23:18:34 -04:00
Kyle Spearrin
2376489f51 minor layout adjustments 2019-06-10 22:37:25 -04:00
Kyle Spearrin
0bfd9f386e fdroid button first 2019-06-10 22:07:06 -04:00
Kyle Spearrin
00e214871d .ToLocalTime() on view dates 2019-06-10 21:59:23 -04:00
Kyle Spearrin
fd41047923 layout adjustments 2019-06-10 21:53:12 -04:00
Kyle Spearrin
393882f57b size adjustments for cipher cell 2019-06-10 21:40:36 -04:00
Kyle Spearrin
313e3a3447 remove old layouts 2019-06-10 21:16:33 -04:00
Kyle Spearrin
23b3972503 catch bad regex parse 2019-06-10 20:47:30 -04:00
Kyle Spearrin
01a64676b4 re-enable appveyor regular builds 2019-06-10 17:01:27 -04:00
Kyle Spearrin
a8ee067215 copy/paste fdroid 2019-06-10 16:58:09 -04:00
Kyle Spearrin
504731885a add repo url info to fdroid page 2019-06-10 16:47:00 -04:00
Kyle Spearrin
76078348d6 style updates 2019-06-10 16:26:36 -04:00
Kyle Spearrin
464fb2144b limitations 2019-06-10 16:13:08 -04:00
Kyle Spearrin
c4e64ae80a bitwarden fdroid webpage 2019-06-10 16:09:34 -04:00
Kyle Spearrin
a614d6634a disable vs build 2019-06-10 15:42:40 -04:00
Kyle Spearrin
856d7905db dist is up one dir 2019-06-10 15:42:16 -04:00
Kyle Spearrin
5b4be62fb4 copy fdroid index html file to dist 2019-06-10 15:34:48 -04:00
Kyle Spearrin
44a58e3e9b test fdroid deploy 2019-06-10 15:32:50 -04:00
Kyle Spearrin
28b6d2ee2e bitwarden on fdroid index html file 2019-06-10 15:31:33 -04:00
Kyle Spearrin
d749095d08 New Crowdin translations (#526)
* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Catalan)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Hebrew)

* New translations AppResources.resx (Hebrew)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Estonian)
2019-06-10 15:18:59 -04:00
Kyle Spearrin
2cdf2cbe19 remove "of apps" 2019-06-10 15:15:33 -04:00
Kyle Spearrin
06669bc77b rename npm package to bitwarden-mobile 2019-06-10 15:11:49 -04:00
Kyle Spearrin
6cd6b00ea6 clean l10n script 2019-06-10 15:11:01 -04:00
Kyle Spearrin
61bf43cd96 only deploy fdroid on release tag 2019-06-10 15:05:49 -04:00
Kyle Spearrin
3be53235a5 build whole solution 2019-06-10 14:50:26 -04:00
Kyle Spearrin
0f0d9f9a10 try cd 2019-06-10 14:40:38 -04:00
Kyle Spearrin
e6cfa84b73 cname dist 2019-06-10 14:38:33 -04:00
Kyle Spearrin
e5888e4b90 move cmd to ps 2019-06-10 14:28:05 -04:00
Kyle Spearrin
8e9e818c43 fixes for appveyor 2019-06-10 14:10:14 -04:00
Kyle Spearrin
5f41487fd2 fdroid-dist 2019-06-10 13:58:34 -04:00
Kyle Spearrin
3b7d3e2652 update appveyor for fdroid builds 2019-06-10 13:57:12 -04:00
Kyle Spearrin
5963cd35d5 fdroid assets 2019-06-10 13:36:03 -04:00
Kyle Spearrin
c4ebd8b6b7 fixes to locking 2019-06-10 13:19:05 -04:00
Kyle Spearrin
678640966e NormalizePassword 2019-06-10 13:09:42 -04:00
Kyle Spearrin
89f9394977 formatting 2019-06-10 12:58:54 -04:00
Kyle Spearrin
e7df752581 fix yubikey listening 2019-06-10 10:53:11 -04:00
Kyle Spearrin
dca567b00d _inited check on 2fa page load 2019-06-10 10:45:22 -04:00
Kyle Spearrin
5248df85ec transparent bg more button 2019-06-10 10:42:15 -04:00
Kyle Spearrin
31d39e0626 padding on cipher list item 2019-06-10 10:37:47 -04:00
Kyle Spearrin
5485bb574e font sizes for cipher cell on android 2019-06-10 10:02:09 -04:00
Kyle Spearrin
337965a7f7 set colors for cipher view cell 2019-06-08 22:29:22 -04:00
Kyle Spearrin
81cd2e26f4 more button click command 2019-06-08 13:04:06 -04:00
Kyle Spearrin
95c07334d7 website icons enabled property 2019-06-08 12:18:49 -04:00
Kyle Spearrin
2f66ee264b image and icon 2019-06-08 11:48:45 -04:00
Kyle Spearrin
5f16066641 autosize 2019-06-08 01:04:31 -04:00
Kyle Spearrin
6cdf84dcb7 wiring up cipher view cell elements 2019-06-07 15:52:47 -04:00
Kyle Spearrin
d7bfc64840 stub native cipher view cell for android 2019-06-07 14:35:44 -04:00
Kyle Spearrin
d199c83a61 null check 2019-06-07 10:31:41 -04:00
Kyle Spearrin
060e1a822f only prompt fingerprint if set 2019-06-07 10:12:11 -04:00
Kyle Spearrin
54141f77d6 no fade animations 2019-06-06 20:38:53 -04:00
Kyle Spearrin
d5c610b819 set generator page from tile if locked 2019-06-06 20:34:59 -04:00
Kyle Spearrin
a2bedaab8a try 1s delay on search to stop crashing 2019-06-06 16:18:44 -04:00
Kyle Spearrin
fa5c8c2c75 always focus search bar on appear, resolves #521 2019-06-06 09:39:48 -04:00
Kyle Spearrin
a2d00c4057 ResetWithRange once on search 2019-06-06 09:32:25 -04:00
Kyle Spearrin
cf9595a0bc only show autofill settings button when disabled
resolves #522
2019-06-06 09:14:32 -04:00
Kyle Spearrin
68d8b1fa3e catch disable display for nfc 2019-06-06 08:59:54 -04:00
Kyle Spearrin
6f905319c3 prompt fignerprint on resume of lock page 2019-06-06 08:04:54 -04:00
Kyle Spearrin
d6fd3edb3c nav bar background theming 2019-06-05 20:18:11 -04:00
Kyle Spearrin
5441c49d8d navigationBarColor black 2019-06-05 17:39:32 -04:00
Kyle Spearrin
c7938a8630 adjust toolbar after loading completes 2019-06-05 17:25:12 -04:00
Kyle Spearrin
bc0bb7c7bb fic editor renderer and add incognito to prompt 2019-06-05 16:48:54 -04:00
Kyle Spearrin
1c58d99006 add back app name and theme 2019-06-05 16:40:05 -04:00
Kyle Spearrin
e0c52dea3a generator tile and icon size adjustments 2019-06-05 16:37:54 -04:00
Kyle Spearrin
a1a5d3b363 dont need splash activity 2019-06-05 15:09:13 -04:00
Kyle Spearrin
9ae08932c2 support "no folder" short list on vault page 2019-06-05 14:27:34 -04:00
Kyle Spearrin
7d8dfb997e ShowNoData for main page 2019-06-05 13:59:08 -04:00
Kyle Spearrin
c8d8d94c7f placeholder colors 2019-06-05 12:32:40 -04:00
Kyle Spearrin
58f01493e0 darkbasedTheme 2019-06-05 12:19:53 -04:00
Kyle Spearrin
4a01116e93 catch any errors on OpenAccessibilitySettings 2019-06-05 12:09:05 -04:00
Kyle Spearrin
1cdc97f037 nord placeholder color 2019-06-05 12:00:15 -04:00
Kyle Spearrin
927c1a6799 set DisabledIconColor 2019-06-05 11:54:31 -04:00
Kyle Spearrin
8eec0c22d7 nord theme 2019-06-05 11:36:58 -04:00
Kyle Spearrin
9d86fac103 IsBusy on syncing 2019-06-05 09:39:30 -04:00
Kyle Spearrin
65f2ea1df2 stop blocking OnBackButtonPressed 2019-06-05 09:12:29 -04:00
Kyle Spearrin
4d54c8f1d1 resolve some todos 2019-06-05 08:58:11 -04:00
Kyle Spearrin
046f25c223 catch No public key when generating fingerprint 2019-06-05 08:37:07 -04:00
Kyle Spearrin
661cd79654 null check on parts 2019-06-05 08:29:27 -04:00
Kyle Spearrin
3b7078e565 try/catch on autofill service detection 2019-06-05 08:24:47 -04:00
Kyle Spearrin
e59ac5d65d generator buttons on different lines 2019-06-05 08:19:36 -04:00
Kyle Spearrin
67da9387ff take whole otpauth URI 2019-06-05 00:41:12 -04:00
Kyle Spearrin
c3f91761f6 HasCiphers and HasFolders props 2019-06-05 00:29:49 -04:00
Kyle Spearrin
a239ee80bc null checks 2019-06-05 00:21:45 -04:00
Kyle Spearrin
96275d8eec attempted workaround for arg outof range exception 2019-06-05 00:15:54 -04:00
Kyle Spearrin
1ef086a02c triedV1ReSync check 2019-06-04 23:39:58 -04:00
Kyle Spearrin
db10fee207 check internet connection on sync 2019-06-04 23:26:56 -04:00
Kyle Spearrin
279b53704b do full sync if no data is present 2019-06-04 23:25:09 -04:00
Kyle Spearrin
dbc750b44e request focus on email field for hint page 2019-06-04 23:16:57 -04:00
Kyle Spearrin
b29ccf67b1 load login page after registration 2019-06-04 23:07:35 -04:00
Kyle Spearrin
b67adf8789 properly parse error model 2019-06-04 22:48:03 -04:00
Kyle Spearrin
113eaef0d1 cleanup themes 2019-06-04 22:11:31 -04:00
Kyle Spearrin
6c88d25941 add locking to BroadcasterService 2019-06-04 21:28:50 -04:00
Kyle Spearrin
f6f6253eab catch exception on accessibility service running 2019-06-04 17:06:27 -04:00
Kyle Spearrin
8e1753ea37 sync date on settings list is local 2019-06-04 16:36:34 -04:00
Kyle Spearrin
83f8989d1f update screenshots 2019-06-04 16:36:25 -04:00
Kyle Spearrin
e1f5c97550 New Crowdin translations (#516)
* New translations AppResources.resx (Danish)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Spanish)
2019-06-04 12:40:15 -04:00
Kyle Spearrin
f8fa867154 Cipher.Login null check 2019-06-04 12:37:57 -04:00
Kyle Spearrin
f0893ca214 UriMatchType cast from int 2019-06-04 12:34:29 -04:00
Kyle Spearrin
82a58d9487 do you typo 2019-06-04 12:18:23 -04:00
Kyle Spearrin
d0ea6aedd0 appveyor updates 2019-06-04 12:01:51 -04:00
Kyle Spearrin
775d929711 migration settings are for prefs storage 2019-06-04 10:57:02 -04:00
Kyle Spearrin
5bae62cdcb New Crowdin translations (#513)
* New translations AppResources.resx (Afrikaans)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Catalan)

* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (Hebrew)

* New translations AppResources.resx (German)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Estonian)
2019-06-04 10:56:55 -04:00
Kyle Spearrin
0a664c47b7 autofill not enabled prompt if migrated 2019-06-04 10:51:10 -04:00
Kyle Spearrin
f856e559a2 update readme 2019-06-04 10:08:56 -04:00
Kyle Spearrin
0283120934 New Crowdin translations (#512)
* New translations AppResources.resx (Afrikaans)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Catalan)

* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (Hebrew)

* New translations AppResources.resx (German)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Estonian)
2019-06-04 10:08:37 -04:00
Kyle Spearrin
5237cbeab0 remove some old resource strings 2019-06-04 09:58:12 -04:00
Kyle Spearrin
15961c419e New Crowdin translations (#510)
* New translations AppResources.resx (Afrikaans)

* New translations copy.resx (Italian)

* New translations copy.resx (Norwegian Bokmal)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations copy.resx (Korean)

* New translations copy.resx (Korean)

* New translations AppResources.resx (Korean)

* New translations copy.resx (Japanese)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Afrikaans)

* New translations AppResources.resx (Indonesian)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Hungarian)

* New translations copy.resx (Hindi)

* New translations copy.resx (Norwegian Bokmal)

* New translations copy.resx (Persian)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Spanish)

* New translations copy.resx (Slovak)

* New translations copy.resx (Slovak)

* New translations AppResources.resx (Slovak)

* New translations copy.resx (Russian)

* New translations copy.resx (Russian)

* New translations AppResources.resx (Russian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Persian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Portuguese)

* New translations AppResources.resx (Portuguese)

* New translations copy.resx (Polish)

* New translations copy.resx (Polish)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Hindi)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Hebrew)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Czech)

* New translations AppResources.resx (Czech)

* New translations copy.resx (Croatian)

* New translations copy.resx (Croatian)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Hebrew)

* New translations copy.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Traditional)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Chinese Simplified)

* New translations copy.resx (Catalan)

* New translations copy.resx (Catalan)

* New translations AppResources.resx (Catalan)

* New translations copy.resx (Bulgarian)

* New translations copy.resx (Bulgarian)

* New translations AppResources.resx (Bulgarian)

* New translations copy.resx (Afrikaans)

* New translations copy.resx (Czech)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Danish)

* New translations copy.resx (Finnish)

* New translations AppResources.resx (Hebrew)

* New translations copy.resx (Danish)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (Finnish)

* New translations copy.resx (German)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (English, United Kingdom)

* New translations copy.resx (Estonian)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Dutch)

* New translations copy.resx (Dutch)

* New translations copy.resx (English, United Kingdom)

* New translations copy.resx (English, United Kingdom)

* New translations AppResources.resx (Estonian)

* New translations copy.resx (Estonian)

* New translations copy.resx (Turkish)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Ukrainian)

* New translations AppResources.resx (Ukrainian)

* New translations copy.resx (Turkish)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Turkish)

* New translations copy.resx (Thai)

* New translations copy.resx (Thai)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Vietnamese)
2019-06-04 09:49:42 -04:00
Kyle Spearrin
8b591a7f0c replace password copied 2019-06-04 09:48:08 -04:00
Kyle Spearrin
f7977c3435 cloc XAML 2019-06-04 09:42:11 -04:00
Kyle Spearrin
0c699e6c12 remove old boxedview 2019-06-04 09:38:31 -04:00
Kyle Spearrin
11e5b2ea5d rename main theme to light theme 2019-06-04 09:36:45 -04:00
Kyle Spearrin
fdfd2d20e6 fdroid builds 2019-06-03 23:54:40 -04:00
Kyle Spearrin
32adb7b91a store assets 2019-06-03 23:51:59 -04:00
Kyle Spearrin
237d31be28 add resx for other languages 2019-06-03 23:46:09 -04:00
Kyle Spearrin
ee07182157 ListItemBorderColor for dark theme 2019-06-03 23:33:48 -04:00
Kyle Spearrin
506ab12b95 sync on migrate if online 2019-06-03 23:26:57 -04:00
Kyle Spearrin
42d6a7c9b8 ShowAndroidAutofillSettings
ShowAndroidAccessibilitySettings
2019-06-03 23:20:59 -04:00
Kyle Spearrin
44530b63ca check internet connection 2019-06-03 23:12:54 -04:00
Kyle Spearrin
eadba95d5f settings screen 2019-06-03 23:01:31 -04:00
Kyle Spearrin
2574e0cba5 Add Site Prompt 2019-06-03 23:00:48 -04:00
Kyle Spearrin
e03cf94441 check internet connection before calling server 2019-06-03 22:43:52 -04:00
Kyle Spearrin
b38b801963 android tweaks 2019-06-03 22:19:51 -04:00
Kyle Spearrin
4f990ffe96 more imeFlags 2019-06-03 17:23:50 -04:00
Kyle Spearrin
8c54062c44 remove lock logging 2019-06-03 17:04:45 -04:00
Kyle Spearrin
9766ebc8e3 always set FingerprintLocked explicitly 2019-06-03 16:56:37 -04:00
Kyle Spearrin
07bc425046 more logging 2019-06-03 16:43:57 -04:00
Kyle Spearrin
d0b8c2c4bf more lock logging 2019-06-03 16:35:04 -04:00
Kyle Spearrin
83bc7c6d51 remove lock service logging 2019-06-03 16:25:43 -04:00
Kyle Spearrin
d64625aba2 more lock service logging 2019-06-03 16:07:45 -04:00
Kyle Spearrin
d1eec27fae lock service logging 2019-06-03 16:04:04 -04:00
Kyle Spearrin
43517fc4f6 set last active to 1 year ago 2019-06-03 15:50:26 -04:00
Kyle Spearrin
0e3eeab828 post migration 2019-06-03 15:44:05 -04:00
Kyle Spearrin
6b68e85077 check lock after migration 2019-06-03 15:32:40 -04:00
Kyle Spearrin
c9faa40475 don't migrate push:lastRegistrationDate 2019-06-03 15:15:00 -04:00
Kyle Spearrin
f8969675e7 only set default lock if unset 2019-06-03 15:07:19 -04:00
Kyle Spearrin
d620b70dac migration cleanup 2019-06-03 15:06:05 -04:00
Kyle Spearrin
4055f92831 migration cleanup 2019-06-03 14:52:16 -04:00
Kyle Spearrin
3e50461ea7 set passphrase defaults 2019-06-03 14:38:54 -04:00
Kyle Spearrin
5eee358059 sync when finished migrating 2019-06-03 14:32:43 -04:00
Kyle Spearrin
17b90c744c adjust defaults for pwGenerator migration 2019-06-03 14:25:29 -04:00
Kyle Spearrin
a78997771f only set pin when needed. sync after migration 2019-06-03 14:21:56 -04:00
Kyle Spearrin
3a691977aa remove reg date from migration 2019-06-03 14:08:27 -04:00
Kyle Spearrin
4bea105693 autofill save prompt is for preferences 2019-06-03 14:06:17 -04:00
Kyle Spearrin
0918e1d963 migrate push reg date 2019-06-03 14:03:24 -04:00
Kyle Spearrin
11ec9b320e proper type for push reg date on migration 2019-06-03 13:53:36 -04:00
Kyle Spearrin
97e98e1d9d more logging 2019-06-03 13:27:32 -04:00
Kyle Spearrin
e6dcdc51a4 more logging 2019-06-03 13:20:46 -04:00
Kyle Spearrin
702d27fea0 migration logging 2019-06-03 13:13:50 -04:00
Kyle Spearrin
59b086168a debug write line migration 2019-06-03 13:05:04 -04:00
Kyle Spearrin
57c89f5b2a log if needs migration 2019-06-03 12:54:31 -04:00
Kyle Spearrin
b69304992f log service 2019-06-03 12:52:46 -04:00
Kyle Spearrin
a5256a6491 remove device lock 2019-06-03 12:33:20 -04:00
Kyle Spearrin
8211f85725 lock on app restart 2019-06-03 12:30:26 -04:00
Kyle Spearrin
c27e44a7d2 autofill service page 2019-06-03 12:19:42 -04:00
Kyle Spearrin
22f16ea514 accessibility settings page 2019-06-03 12:05:18 -04:00
Kyle Spearrin
7ed45c3535 missing scroll view 2019-06-03 11:32:48 -04:00
Kyle Spearrin
a3716bc841 settings enabled/disabled text 2019-06-03 11:26:16 -04:00
Kyle Spearrin
e8c776fe49 implement blacklisted uris options for autofill 2019-06-03 11:08:33 -04:00
Kyle Spearrin
999c9667c8 dont process OnSaveRequest if prompt disabled 2019-06-03 11:01:08 -04:00
Kyle Spearrin
59620e6435 cleanup options page a bit more 2019-06-03 10:57:08 -04:00
Kyle Spearrin
cf4a6bb1a2 autosize notes 2019-06-03 10:46:05 -04:00
Kyle Spearrin
8658ebd6bb new autofill options 2019-06-03 10:45:27 -04:00
Kyle Spearrin
59f1dcca12 logged in as on 2019-06-03 09:58:35 -04:00
Kyle Spearrin
4382490823 black theme styling 2019-06-02 00:14:09 -04:00
Kyle Spearrin
479ad31325 black theme option 2019-06-02 00:08:20 -04:00
Kyle Spearrin
dd976b5b86 more black theme stub 2019-06-01 23:59:17 -04:00
Kyle Spearrin
18c2c1433b stub black theme 2019-06-01 23:42:42 -04:00
Kyle Spearrin
0fc013eb8a migrated messaging 2019-06-01 23:33:36 -04:00
Kyle Spearrin
1d95c73173 set type selected index later 2019-06-01 23:09:38 -04:00
Kyle Spearrin
312b6c2d44 pass _appOptions to load method 2019-06-01 22:44:15 -04:00
Kyle Spearrin
cab2b261b5 do not request focus on yubikey 2019-06-01 22:27:08 -04:00
Kyle Spearrin
2ddb384c80 blacklist com.android.settings 2019-06-01 21:27:30 -04:00
Kyle Spearrin
ca27b34122 focus yubikey token entry 2019-06-01 01:08:18 -04:00
Kyle Spearrin
5ce2eaf77e dont auto show fingerprint if lock is initiated 2019-06-01 01:07:02 -04:00
Kyle Spearrin
4ae02c27a4 old userid is string 2019-06-01 00:51:50 -04:00
Kyle Spearrin
50f71e7280 migration flag fix 2019-06-01 00:42:26 -04:00
Kyle Spearrin
638de90cc4 validating 2019-06-01 00:13:36 -04:00
Kyle Spearrin
d1646e5aca support old key on password unlock 2019-05-31 23:46:22 -04:00
Kyle Spearrin
ddd521cd4b migrate if necessary 2019-05-31 23:32:01 -04:00
Kyle Spearrin
f5b05ecd92 remove needs migration flag 2019-05-31 23:26:09 -04:00
Kyle Spearrin
4f2b76c442 finish migrate data helper 2019-05-31 23:23:58 -04:00
Kyle Spearrin
6aef106482 start some migration work for auth data 2019-05-31 17:49:51 -04:00
Kyle Spearrin
b191542ab7 ime NoPersonalizedLearning on entry and editor 2019-05-31 16:47:54 -04:00
Kyle Spearrin
e0e69920e9 masterPassOnRestart option for pin locking 2019-05-31 15:30:22 -04:00
Kyle Spearrin
f3edae9bb1 NoOrgsToList 2019-05-31 14:57:11 -04:00
Kyle Spearrin
0d5f5ec9ba init settings on tabs page changed 2019-05-31 14:18:32 -04:00
Kyle Spearrin
582799464f back button to groupings page on android 2019-05-31 14:15:37 -04:00
Kyle Spearrin
fc0d91d3e7 return type field focus on cipher add/edit 2019-05-31 14:10:49 -04:00
Kyle Spearrin
81b8c1716f color adjustments 2019-05-31 13:41:18 -04:00
Kyle Spearrin
b5d2a9a2fb return command for folders add/edit 2019-05-31 12:14:25 -04:00
Kyle Spearrin
a98283f3ff return commands for accounts pages 2019-05-31 12:13:14 -04:00
Kyle Spearrin
61be796c76 return commands on login page 2019-05-31 12:02:40 -04:00
Kyle Spearrin
dd090b0ed9 do once 2019-05-31 11:55:11 -04:00
Kyle Spearrin
6588b5bebb list section separator on settings page 2019-05-31 11:52:56 -04:00
Kyle Spearrin
aa3fd29508 list row separator 2019-05-31 11:40:53 -04:00
Kyle Spearrin
dcf412d94d border for sections 2019-05-31 11:36:44 -04:00
Kyle Spearrin
defac4e2d5 center numbers 2019-05-31 11:19:14 -04:00
Kyle Spearrin
6163a6dd77 fix slider history saves 2019-05-31 11:13:46 -04:00
Kyle Spearrin
32e757a873 update slider stroke 2019-05-31 11:03:32 -04:00
Kyle Spearrin
8df940447d save length and history when value done changing 2019-05-31 09:09:32 -04:00
Kyle Spearrin
ac6f3a6bb6 fix ip address matching on getdomain 2019-05-31 08:30:18 -04:00
Kyle Spearrin
46e631388d no need to catch apiexception 2019-05-31 08:18:18 -04:00
Kyle Spearrin
ff7c9f210c hide password and clear field on unlock 2019-05-30 23:48:39 -04:00
Kyle Spearrin
eecf81f0a5 verify fingerprint when enabling 2019-05-30 22:50:58 -04:00
Kyle Spearrin
b356627afd autofill rows on settings page 2019-05-30 22:45:48 -04:00
Kyle Spearrin
e3dcf4aed1 dont return null 2019-05-30 22:11:19 -04:00
Kyle Spearrin
4dd05cf10e remove boxedview 2019-05-30 22:09:28 -04:00
Kyle Spearrin
68a85a2561 myvault tile service 2019-05-30 22:05:50 -04:00
Kyle Spearrin
49cde1c67d icons updates 2019-05-30 21:59:02 -04:00
Kyle Spearrin
249dffe778 build number on about page 2019-05-30 21:25:54 -04:00
Kyle Spearrin
6d9b860c8b update tabbar 2019-05-30 21:24:03 -04:00
Kyle Spearrin
b1eabdfe86 main thread 2019-05-30 20:40:50 -04:00
Kyle Spearrin
ab9bbf7b0f save activity 2019-05-30 20:24:30 -04:00
Kyle Spearrin
cf2308a12d CipherListOptions on search page 2019-05-30 18:33:18 -04:00
Kyle Spearrin
0aa1359ad4 use current.mainpage 2019-05-30 18:27:57 -04:00
Kyle Spearrin
48c51173a1 CipherListOptions on autofill page 2019-05-30 17:24:41 -04:00
Kyle Spearrin
6838b32304 copy to remove no folder from list 2019-05-30 15:20:04 -04:00
Kyle Spearrin
60f81c5cba no need to check sync success 2019-05-30 15:15:58 -04:00
Kyle Spearrin
419cfceef1 needs migration flag 2019-05-30 15:11:22 -04:00
Kyle Spearrin
c7b62c8551 move some items needed for migration 2019-05-30 14:43:35 -04:00
Kyle Spearrin
a66489cd8c make AutofillServiceEnabled public 2019-05-30 14:21:15 -04:00
Kyle Spearrin
6d51864873 update tasks and sync on app start 2019-05-30 14:13:02 -04:00
Kyle Spearrin
dc7b37c8f2 accessibility service autofill 2019-05-30 12:37:35 -04:00
Kyle Spearrin
21bbb2af42 search icon 2019-05-30 12:04:31 -04:00
Kyle Spearrin
c3b9f4e5a8 run subscribed messages on main thread 2019-05-30 11:40:33 -04:00
Kyle Spearrin
70fa41ca3e clear clipboard alarm 2019-05-30 11:22:35 -04:00
Kyle Spearrin
49705b1074 use ValueHasBeenCopied string 2019-05-30 09:15:59 -04:00
Kyle Spearrin
32395dcb20 fixes 2019-05-30 08:45:39 -04:00
Kyle Spearrin
e34ca49b9b pop pages if cipher doesnt exist 2019-05-30 08:40:10 -04:00
Kyle Spearrin
46a8ffa5ae pop page on delete success 2019-05-30 08:35:50 -04:00
Kyle Spearrin
3f8f29dfe7 secondary menu on groupings page 2019-05-30 00:29:00 -04:00
Kyle Spearrin
67970afc1e log out on stamp mismatch when syncing 2019-05-29 23:41:43 -04:00
Kyle Spearrin
1c08901698 remove some todos 2019-05-29 23:37:25 -04:00
Kyle Spearrin
86d8d64bf6 CipherListOptions 2019-05-29 23:35:34 -04:00
Kyle Spearrin
cc8b8f9ceb restart app after theme change 2019-05-29 23:02:30 -04:00
Kyle Spearrin
6e91d66b2c white logo and popupTheme 2019-05-29 17:14:15 -04:00
Kyle Spearrin
886f356525 blue track color on dark theme 2019-05-29 16:55:13 -04:00
Kyle Spearrin
3fe7324cdf more theming 2019-05-29 16:44:18 -04:00
Kyle Spearrin
a1741fdd67 themeing 2019-05-29 15:50:20 -04:00
Kyle Spearrin
40484a7bf0 set theme on options change 2019-05-29 14:23:55 -04:00
Kyle Spearrin
48376d0a93 more options 2019-05-29 14:11:15 -04:00
Kyle Spearrin
6be54fa7ee disable favicons and totp copy fix for org 2019-05-29 09:55:48 -04:00
Kyle Spearrin
6c6da368dd options page 2019-05-29 09:36:57 -04:00
Kyle Spearrin
d70de04816 stub out options page 2019-05-29 09:08:47 -04:00
Kyle Spearrin
bf022f8a41 move settings page into folder 2019-05-29 09:05:24 -04:00
Kyle Spearrin
7046a010f9 remove XF 2019-05-29 08:40:16 -04:00
Kyle Spearrin
5cdccc7527 fix warnings 2019-05-29 08:27:58 -04:00
Kyle Spearrin
02552d0b24 add xf back to android project 2019-05-29 00:34:15 -04:00
Kyle Spearrin
026dd4761e hockeyapp 2019-05-28 23:14:02 -04:00
Kyle Spearrin
635dd5d4d5 non-debug is secure 2019-05-28 23:04:01 -04:00
Kyle Spearrin
81d972a462 thread policy 2019-05-28 23:03:03 -04:00
Kyle Spearrin
bfeddd6d99 forms only needs to be on main app project 2019-05-28 23:01:10 -04:00
Kyle Spearrin
437a60a967 crash fixes 2019-05-28 22:57:59 -04:00
Kyle Spearrin
6218c65ec6 prime expensive tasks 2019-05-28 17:18:27 -04:00
Kyle Spearrin
25d02cec25 load EEFLongWordList from file 2019-05-28 17:06:57 -04:00
Kyle Spearrin
0bbb549533 prime the word list 2019-05-28 16:39:10 -04:00
Kyle Spearrin
4ca5593d2e load on sync completed 2019-05-28 16:28:21 -04:00
Kyle Spearrin
630fc3f73c fix route for device token PUT 2019-05-28 16:20:24 -04:00
Kyle Spearrin
d66646d168 disable fdroid for now to speed of builds 2019-05-28 15:50:53 -04:00
Kyle Spearrin
ffe7771801 async await 2019-05-28 15:40:56 -04:00
Kyle Spearrin
5942bcc16d remove old autofill service 2019-05-28 15:34:49 -04:00
Kyle Spearrin
eb3d0d726f turn off rdp builds 2019-05-28 15:21:14 -04:00
Kyle Spearrin
a4846c7b11 remove ios projects for now 2019-05-28 15:05:28 -04:00
Kyle Spearrin
8e7ed05f25 firebase receivers 2019-05-28 14:53:23 -04:00
Kyle Spearrin
84d21efb5d enable rdp 2019-05-28 14:28:06 -04:00
Kyle Spearrin
68ee013114 multidex? 2019-05-28 13:54:13 -04:00
Kyle Spearrin
cd8a09ddef fdroid config profile 2019-05-28 13:50:01 -04:00
Kyle Spearrin
e1f6302280 remove json.net from ios core project 2019-05-28 13:41:39 -04:00
Kyle Spearrin
144197daaf play store publisher 2019-05-28 13:29:09 -04:00
Kyle Spearrin
57af4e0a03 merge fixes 2019-05-28 12:15:38 -04:00
Kyle Spearrin
309caa2f83 fix ios handler 2019-05-28 12:03:41 -04:00
Kyle Spearrin
3f11fdaa82 push notification services 2019-05-28 12:01:55 -04:00
Kyle Spearrin
faccb61a6b clear master password on login 2019-05-28 10:16:57 -04:00
Kyle Spearrin
786f3b4644 2fa for email 2019-05-28 10:12:51 -04:00
Kyle Spearrin
58d101659a listen to yubikey 2019-05-28 09:54:08 -04:00
Kyle Spearrin
822fc7f308 add/remove continue button 2019-05-28 09:12:05 -04:00
Kyle Spearrin
29ab7f7a30 touch ups on two-factor page 2019-05-28 09:04:20 -04:00
Kyle Spearrin
bf4f0bdba0 two-factor page UI 2019-05-27 11:57:10 -04:00
Kyle Spearrin
e8705d49f2 stub our 2fa page backend 2019-05-27 10:28:38 -04:00
Kyle Spearrin
6d49253ee5 stub out two factor page 2019-05-23 21:19:45 -04:00
Kyle Spearrin
23f27282d6 hybrid webview 2019-05-23 21:05:52 -04:00
Kyle Spearrin
bfa336b72d scan totp key 2019-05-22 21:10:04 -04:00
Kyle Spearrin
b5522c1b5e no async 2019-05-22 20:54:44 -04:00
Kyle Spearrin
543e3418a5 scan page 2019-05-22 20:54:17 -04:00
Kyle Spearrin
ea3dcd6250 add zxing lib 2019-05-22 20:28:31 -04:00
Kyle Spearrin
b8cbd5e0aa search for autofilling 2019-05-20 22:18:34 -04:00
Kyle Spearrin
29951207ec lock page work with autofill 2019-05-17 16:36:29 -04:00
Kyle Spearrin
3c58775ae2 fixes for autofill service 2019-05-17 15:43:14 -04:00
Kyle Spearrin
9ab41c5de6 populate add page from autofill 2019-05-17 15:24:15 -04:00
Kyle Spearrin
65f3a146fa autofill page fixes 2019-05-17 14:58:42 -04:00
Kyle Spearrin
22366ec0a2 autofill cipher 2019-05-17 14:46:31 -04:00
Kyle Spearrin
d038fb900e fuzzy autofill prop 2019-05-17 14:34:29 -04:00
Kyle Spearrin
13c5ebe065 disable favicons constant 2019-05-17 14:34:14 -04:00
Kyle Spearrin
4112e0a4c9 autofill actions 2019-05-17 14:34:00 -04:00
Kyle Spearrin
f73a5d6307 display alert action 2019-05-17 14:04:16 -04:00
Kyle Spearrin
a3e165fa06 some device functions 2019-05-17 13:46:32 -04:00
Kyle Spearrin
3e633dc38e stub out autofill ciphers listing page 2019-05-17 13:14:26 -04:00
Kyle Spearrin
d53bfae529 fix settings 2019-05-17 13:10:07 -04:00
Kyle Spearrin
9d491a3636 app options for add/edit page 2019-05-17 12:03:35 -04:00
Kyle Spearrin
c77d4b795a is locked inside if 2019-05-17 11:02:50 -04:00
Kyle Spearrin
c96daf2d68 logged in as and verify messages 2019-05-17 10:01:45 -04:00
Kyle Spearrin
961e23f0b8 face id strings 2019-05-17 09:46:36 -04:00
Kyle Spearrin
defb67c523 faceid detection 2019-05-17 09:45:07 -04:00
Kyle Spearrin
4aa1209bc7 fingerprint unlock 2019-05-17 09:42:20 -04:00
Kyle Spearrin
a7ad89471a update libs 2019-05-17 09:22:16 -04:00
Kyle Spearrin
1f74e102fa dont focus fields if using fingerprint locking 2019-05-16 17:31:08 -04:00
Kyle Spearrin
5761b47073 fingerprint locking 2019-05-16 17:30:07 -04:00
Kyle Spearrin
22a0b262e1 fingerprint setup 2019-05-16 16:31:58 -04:00
Kyle Spearrin
6e42f5ce7b use proper set lock option method 2019-05-16 16:00:16 -04:00
Kyle Spearrin
c5bd59e52c set pin from settings 2019-05-16 15:54:21 -04:00
Kyle Spearrin
c65b065dd7 lock option picker 2019-05-16 14:55:18 -04:00
Kyle Spearrin
3f8ab1bfe7 no need to schedule locking if already locked 2019-05-16 12:33:48 -04:00
Kyle Spearrin
cf41c5e090 lock now 2019-05-16 12:31:00 -04:00
Kyle Spearrin
290e90ba8e lock alarm 2019-05-16 12:30:20 -04:00
Kyle Spearrin
84c9516659 log user activity 2019-05-16 12:30:13 -04:00
Kyle Spearrin
3eb1ab0452 lock service fixes 2019-05-16 12:29:55 -04:00
Kyle Spearrin
f317f45d14 type change fix 2019-05-16 12:03:36 -04:00
Kyle Spearrin
5f6a3f4cb5 lock page fixes 2019-05-16 08:41:57 -04:00
Kyle Spearrin
27b6631cc1 lock page 2019-05-15 17:37:59 -04:00
Kyle Spearrin
f7bb091366 lock now button 2019-05-15 15:47:50 -04:00
Kyle Spearrin
5cf2092576 register lock service 2019-05-15 14:26:23 -04:00
Kyle Spearrin
954de743f5 lock service 2019-05-15 14:22:28 -04:00
Kyle Spearrin
8ab632e207 lock now string 2019-05-15 13:35:17 -04:00
Kyle Spearrin
547cd4e828 various settings 2019-05-15 13:26:55 -04:00
Kyle Spearrin
264028b623 rate app 2019-05-15 13:09:49 -04:00
Kyle Spearrin
2c302985f8 colon 2019-05-15 12:55:52 -04:00
Kyle Spearrin
d6f46cf5c5 fingerprint phrase and help settings 2019-05-15 12:54:48 -04:00
Kyle Spearrin
d4ed276684 hash phrase fixes 2019-05-15 12:53:01 -04:00
Kyle Spearrin
67e458833f settings about dialog 2019-05-15 09:14:49 -04:00
Kyle Spearrin
291c201b00 folder add/edit page 2019-05-14 17:25:58 -04:00
Kyle Spearrin
f9473ea61d folders page 2019-05-14 17:02:24 -04:00
Kyle Spearrin
b68031bd11 sync page details 2019-05-14 16:36:54 -04:00
Kyle Spearrin
879b5ef3aa stub sync page 2019-05-14 12:05:30 -04:00
Kyle Spearrin
ff1f895476 stub out settings page with a listview 2019-05-14 11:53:41 -04:00
Kyle Spearrin
3229835f50 load something for other tab pages 2019-05-14 09:51:13 -04:00
Kyle Spearrin
f0a96759a4 page name for groupings 2019-05-14 09:48:40 -04:00
Kyle Spearrin
4f4c6064db new tab page from code 2019-05-14 09:43:46 -04:00
Kyle Spearrin
df802152d7 tab page IsSwipePagingEnabled false 2019-05-14 09:20:03 -04:00
Kyle Spearrin
4f3a3a5b19 stub out settings page 2019-05-14 09:09:35 -04:00
Kyle Spearrin
cc7ccf921b generated password history page 2019-05-14 09:01:07 -04:00
Kyle Spearrin
4dfd8b6985 width on length label 2019-05-14 08:37:27 -04:00
Kyle Spearrin
919eedc0fa colored password property 2019-05-14 08:32:07 -04:00
Kyle Spearrin
9400c22e4f pass gen fixes 2019-05-13 16:06:56 -04:00
Kyle Spearrin
99f00b8e63 fix renderer namespaces 2019-05-13 15:25:20 -04:00
Kyle Spearrin
29d876eaed extended slider 2019-05-13 15:24:38 -04:00
Kyle Spearrin
018a7c9f96 generator UI elements 2019-05-13 14:43:23 -04:00
Kyle Spearrin
28473dd85f stub out password generator page functionality 2019-05-13 12:13:23 -04:00
Kyle Spearrin
29b37219c2 attachments page 2019-05-10 23:43:35 -04:00
Kyle Spearrin
34fd9b5842 stub attachments page 2019-05-10 14:33:33 -04:00
Kyle Spearrin
2b2787b187 collections page 2019-05-10 14:28:17 -04:00
Kyle Spearrin
253217cf20 changes based on add/edit mode 2019-05-10 14:09:13 -04:00
Kyle Spearrin
74c0e52458 secondary toolbar buttons 2019-05-10 13:47:59 -04:00
Kyle Spearrin
75cb67890d light overflow menu 2019-05-10 13:26:37 -04:00
Kyle Spearrin
9668bd85c1 share page 2019-05-10 13:22:35 -04:00
Kyle Spearrin
9aef584494 fix dialog resolve message 2019-05-10 13:22:25 -04:00
Kyle Spearrin
a535e8a82b null checks 2019-05-09 17:27:43 -04:00
Kyle Spearrin
3bd01067e3 collection management when adding new cipher 2019-05-09 16:55:11 -04:00
Kyle Spearrin
056b9fd2de fab on view page 2019-05-09 14:12:30 -04:00
Kyle Spearrin
da2ec4a38e favorite 2019-05-09 12:29:57 -04:00
Kyle Spearrin
fb5c36071d misc section with folders 2019-05-09 12:18:23 -04:00
Kyle Spearrin
b07afa7f11 fixes for custom field name prompt 2019-05-09 11:56:39 -04:00
Kyle Spearrin
a0e65fa75e custom field name prompt 2019-05-09 11:44:27 -04:00
Kyle Spearrin
866a20ed5a custom fields add/edit 2019-05-08 23:13:10 -04:00
Kyle Spearrin
49c355e52f manage URIS on add/edit 2019-05-08 16:49:32 -04:00
Kyle Spearrin
8d0dc2d230 update repeaterview to handle observables 2019-05-08 16:37:58 -04:00
Kyle Spearrin
cbda58f770 identity fields and notes 2019-05-08 15:00:45 -04:00
Kyle Spearrin
bb0ee239b4 pickers 2019-05-08 14:37:12 -04:00
Kyle Spearrin
0495c17fc8 fab padding and clicked action 2019-05-08 10:42:55 -04:00
Kyle Spearrin
2a5739dfdc fab 2019-05-08 08:33:17 -04:00
Kyle Spearrin
0b73317dd0 add some fields for various types 2019-05-07 23:22:55 -04:00
Kyle Spearrin
5dc4357078 padding/margins for entry/picker 2019-05-07 23:22:25 -04:00
Kyle Spearrin
cf2ae9d7e8 check tasks for completion 2019-05-07 23:21:56 -04:00
Kyle Spearrin
68c6537bcb fixes to cipher service 2019-05-07 13:58:50 -04:00
Kyle Spearrin
a236d7fbb1 stub out more add/edit page stuff 2019-05-07 12:29:02 -04:00
Kyle Spearrin
13267ff83d stub new add/edit page 2019-05-07 11:25:21 -04:00
Kyle Spearrin
8c31c7290c more do once and other cleanup 2019-05-06 23:30:54 -04:00
Kyle Spearrin
7d3ef39f67 more do once 2019-05-06 23:22:48 -04:00
Kyle Spearrin
51ee93eca0 better sizing on btn title 2019-05-06 23:18:13 -04:00
Kyle Spearrin
2816e72aa9 more do once checks 2019-05-06 23:07:47 -04:00
Kyle Spearrin
5ef4c96ee7 DoOnce helper 2019-05-06 22:49:57 -04:00
Kyle Spearrin
4ed12a859b cipher searching 2019-05-06 22:35:42 -04:00
Kyle Spearrin
128935eb9f searchbar on ciphers page 2019-05-04 00:14:49 -04:00
Kyle Spearrin
2553938380 material icons. stub out ciphers search page 2019-05-02 21:25:26 -04:00
Kyle Spearrin
59e412ea09 cipher password history page 2019-05-02 14:53:45 -04:00
Kyle Spearrin
9195bdcf95 style stweaks 2019-05-02 12:46:08 -04:00
Kyle Spearrin
2ca066327a re-org pages into folders 2019-05-02 12:27:23 -04:00
Kyle Spearrin
daa9bdfb8c improve home page spacing 2019-05-02 12:26:09 -04:00
Kyle Spearrin
faf690d899 environment page 2019-05-02 12:20:56 -04:00
Kyle Spearrin
9965121011 register page 2019-05-02 10:10:05 -04:00
Kyle Spearrin
15cda95c64 hint page 2019-05-01 15:53:56 -04:00
Kyle Spearrin
9678eab43f init login page 2019-05-01 15:29:57 -04:00
Kyle Spearrin
3b97fa0379 login page layout 2019-05-01 15:11:54 -04:00
Kyle Spearrin
c8368a2190 grouping counts 2019-05-01 12:28:49 -04:00
Kyle Spearrin
ba9605383d grouping types filter 2019-05-01 11:31:00 -04:00
Kyle Spearrin
caaec3ea57 fix password leaked check 2019-05-01 10:33:48 -04:00
Kyle Spearrin
a018369ae8 BaseContentPage on groupings page 2019-05-01 10:20:05 -04:00
Kyle Spearrin
b4f4f24c24 show activity indicator while still loading 2019-05-01 10:11:49 -04:00
Kyle Spearrin
9eeafcd027 accessibility service 2019-04-30 14:33:00 -04:00
Kyle Spearrin
464f4ba300 autofill service 2019-04-30 12:35:58 -04:00
Kyle Spearrin
cad56d438f more resources 2019-04-30 11:54:44 -04:00
Kyle Spearrin
5812dc7e7e more button on cipher listing 2019-04-30 11:27:53 -04:00
Kyle Spearrin
4a1bccd516 android resources 2019-04-30 10:40:51 -04:00
Kyle Spearrin
e46277c2ac preserve none folder filter 2019-04-30 09:55:28 -04:00
Kyle Spearrin
33684bd140 view page update info 2019-04-30 09:50:35 -04:00
Kyle Spearrin
865deaf401 null converters 2019-04-30 09:50:24 -04:00
Kyle Spearrin
1f4bdb04ee attachments on view page abd device actions 2019-04-29 16:09:27 -04:00
Kyle Spearrin
a5bf16a415 attachment listing 2019-04-29 14:35:44 -04:00
Kyle Spearrin
2a6fe3f351 move field view model 2019-04-29 13:56:36 -04:00
Kyle Spearrin
9468bb322d add I to ambiguous characters 2019-04-29 13:53:33 -04:00
Kyle Spearrin
9650e44078 field logic 2019-04-29 13:51:05 -04:00
Kyle Spearrin
134a4ec5d2 view page card and identity info 2019-04-29 10:20:29 -04:00
Kyle Spearrin
b7d87486a8 dont need to check target type of bool? 2019-04-29 10:00:59 -04:00
Kyle Spearrin
a75295662c null check 2019-04-29 09:59:33 -04:00
Kyle Spearrin
69eeb8bd23 fix logic on identity view address 2019-04-29 09:31:44 -04:00
Kyle Spearrin
65fe0e8f62 string has value converter 2019-04-29 09:31:34 -04:00
Kyle Spearrin
8fa2ef863f exposed password check 2019-04-27 00:19:44 -04:00
Kyle Spearrin
5e114e8074 colored password 2019-04-26 23:58:15 -04:00
Kyle Spearrin
223e8a5293 toggle password 2019-04-26 23:37:21 -04:00
Kyle Spearrin
aee9ce802a line break for box value 2019-04-26 22:59:53 -04:00
Kyle Spearrin
04bd6b49ad correct launch icon 2019-04-26 22:44:15 -04:00
Kyle Spearrin
e9d54d9cf5 remove css styling 2019-04-26 22:42:05 -04:00
Kyle Spearrin
9b2ce98b46 view page updates 2019-04-26 21:53:39 -04:00
Kyle Spearrin
d7312e2977 uris, fields, etc to view page 2019-04-26 16:58:20 -04:00
Kyle Spearrin
c2a168c6b7 styling boxes 2019-04-26 12:57:52 -04:00
Kyle Spearrin
a01f9c7351 totp text color changes with DynamicResource 2019-04-26 12:03:29 -04:00
Kyle Spearrin
dc0f9847c6 task.run ffimage init 2019-04-26 10:58:41 -04:00
Kyle Spearrin
7613f4191b init storage 2019-04-26 10:55:29 -04:00
Kyle Spearrin
1b613db534 task.run init 2019-04-26 10:54:02 -04:00
Kyle Spearrin
fb50123af0 init task 2019-04-26 10:40:28 -04:00
Kyle Spearrin
08c3aff60b litedb init 2019-04-26 10:30:41 -04:00
Kyle Spearrin
9cb141ef62 splash 2019-04-26 10:07:42 -04:00
Kyle Spearrin
baf77eb3a3 view page login info with copy buttons 2019-04-26 00:26:09 -04:00
Kyle Spearrin
0625f313dc repeater view 2019-04-25 11:43:45 -04:00
Kyle Spearrin
b644ed5a25 icon fixes 2019-04-24 23:53:36 -04:00
Kyle Spearrin
18ff6c7976 refreshing 2019-04-24 23:37:47 -04:00
Kyle Spearrin
be5fd8381f no data messages 2019-04-24 23:28:41 -04:00
Kyle Spearrin
003092a55b re-use groupings page for ciphers listing 2019-04-24 16:50:34 -04:00
Kyle Spearrin
3d50133fa8 search service 2019-04-24 14:52:26 -04:00
Kyle Spearrin
594a491251 move groupings page under vault 2019-04-24 11:25:18 -04:00
Kyle Spearrin
1cde9b8356 go to view page from groupings 2019-04-24 11:23:03 -04:00
Kyle Spearrin
b107df60e2 dark theme test 2019-04-22 17:23:11 -04:00
Kyle Spearrin
997ed42178 folder none translation 2019-04-22 17:10:28 -04:00
Kyle Spearrin
913cd23c45 cipher view cell and groupings styles 2019-04-22 17:08:37 -04:00
Kyle Spearrin
6cd1171fd5 theme variables 2019-04-22 14:17:33 -04:00
Kyle Spearrin
c3fe3292ad i18n extension 2019-04-22 13:47:45 -04:00
Kyle Spearrin
b48c231500 theming with resource dictionary 2019-04-22 11:32:17 -04:00
Kyle Spearrin
a6cd16cdb5 selected list cell transparent 2019-04-22 09:16:47 -04:00
Kyle Spearrin
2959577163 children default is empty list 2019-04-22 09:08:24 -04:00
Kyle Spearrin
efddb385d8 folder service bug 2019-04-22 08:54:43 -04:00
Kyle Spearrin
ea5a411f30 bug fixes 2019-04-19 16:57:34 -04:00
Kyle Spearrin
7548122e2d grouping listing 2019-04-19 16:45:16 -04:00
Kyle Spearrin
a4cbf3bee3 set main page 2019-04-19 16:40:20 -04:00
Kyle Spearrin
7f2c265965 sequentialize some methods 2019-04-19 16:38:20 -04:00
Kyle Spearrin
c6ce3e9480 convert to local functions to avoid continuewith 2019-04-19 16:15:29 -04:00
Kyle Spearrin
6d8af4d97a null check 2019-04-19 15:33:55 -04:00
Kyle Spearrin
60efcbaf02 empty ctors 2019-04-19 15:25:07 -04:00
Kyle Spearrin
3b63fbb61b no userid on cipher domain 2019-04-19 15:18:43 -04:00
Kyle Spearrin
2637587cf7 null checks 2019-04-19 15:18:26 -04:00
Kyle Spearrin
480f954433 changes for new messaging 2019-04-19 12:33:57 -04:00
Kyle Spearrin
7c1549bb95 re-worked message sending 2019-04-19 12:29:37 -04:00
Kyle Spearrin
4b7366e9b3 full sync on login 2019-04-19 09:57:19 -04:00
Kyle Spearrin
6288a06b49 login page 2019-04-19 09:42:55 -04:00
Kyle Spearrin
b3c67bab92 json property mapping 2019-04-19 09:25:15 -04:00
Kyle Spearrin
8c8fa8ae4c api error detection updates 2019-04-19 09:11:17 -04:00
Kyle Spearrin
0c93fc2662 home page buttons 2019-04-19 07:42:36 -04:00
Kyle Spearrin
aec2855db9 update message send type 2019-04-18 14:30:38 -04:00
Kyle Spearrin
2becf769c1 use new messaging and broadcaster services 2019-04-18 13:15:46 -04:00
Kyle Spearrin
da73a2f5d2 mobile broadcaster service 2019-04-18 12:53:05 -04:00
Kyle Spearrin
1dd5f9fc27 fix multiple i18n inits 2019-04-18 12:34:53 -04:00
Kyle Spearrin
e141991166 bootstrap 2019-04-18 12:31:35 -04:00
Kyle Spearrin
fff32e8086 register environment service 2019-04-18 12:21:35 -04:00
Kyle Spearrin
859788ca46 environment service 2019-04-18 12:19:17 -04:00
Kyle Spearrin
b94485be75 register services on android 2019-04-18 10:40:57 -04:00
Kyle Spearrin
43948c65f1 auth service 2019-04-18 09:45:31 -04:00
Kyle Spearrin
b61355a8fa update xamarin forms 2019-04-17 17:14:04 -04:00
Kyle Spearrin
8834492ec2 update xamarin forms 2019-04-17 17:13:53 -04:00
Kyle Spearrin
676e896d8c audit service 2019-04-17 17:10:21 -04:00
Kyle Spearrin
6d159740d9 remove preproject 2019-04-17 16:02:19 -04:00
Kyle Spearrin
f48aa24129 totp service 2019-04-17 16:01:07 -04:00
Kyle Spearrin
f46151bb71 password generation service 2019-04-17 15:23:26 -04:00
Kyle Spearrin
818414eb37 sync service 2019-04-17 12:12:43 -04:00
Kyle Spearrin
808fcea655 setup sync service 2019-04-17 09:38:20 -04:00
Kyle Spearrin
d050e01d08 interfaces 2019-04-17 09:09:54 -04:00
Kyle Spearrin
6cab060509 collection service 2019-04-17 09:07:51 -04:00
Kyle Spearrin
18f04af051 tree node traversal for folder 2019-04-17 08:46:51 -04:00
Kyle Spearrin
4b3bae5797 optional params 2019-04-16 23:31:05 -04:00
Kyle Spearrin
98291caf76 cipher service interface 2019-04-16 23:30:52 -04:00
Kyle Spearrin
a1a8c95ece cipher service methods 2019-04-16 20:43:54 -04:00
Kyle Spearrin
40b6460ac9 more cipher service functions 2019-04-16 17:34:59 -04:00
Kyle Spearrin
25c82ffd58 new apis 2019-04-16 17:21:04 -04:00
Kyle Spearrin
f76051d362 data model updates 2019-04-16 11:09:05 -04:00
Kyle Spearrin
351c99fb42 locale string comparer for i18n service 2019-04-16 11:08:28 -04:00
Kyle Spearrin
803527f585 locale string comparer for i18n service 2019-04-16 11:08:05 -04:00
Kyle Spearrin
d1c696bad5 new api endpoints 2019-04-16 11:07:44 -04:00
Kyle Spearrin
5d2f4e6ca4 api models 2019-04-16 11:07:32 -04:00
Kyle Spearrin
567ebcd06e more cipher service functions 2019-04-16 07:59:53 -04:00
Kyle Spearrin
1103354de3 new constants for mobile app prefixes 2019-04-16 07:44:18 -04:00
Kyle Spearrin
2fa3d214e5 make regex helpers public 2019-04-16 07:44:05 -04:00
Kyle Spearrin
7d6ec46ebe view updates 2019-04-16 07:43:56 -04:00
Kyle Spearrin
40598721f1 Url helpers 2019-04-15 18:17:19 -04:00
Kyle Spearrin
576f44a924 DomainName helper class for getting base domain 2019-04-15 16:16:53 -04:00
Kyle Spearrin
694e4960ad cipher service encrypt 2019-04-15 11:46:20 -04:00
Kyle Spearrin
4b67ba027e collection and folder models 2019-04-15 08:42:50 -04:00
Kyle Spearrin
eeb28f6ddf card view 2019-04-15 08:30:59 -04:00
Kyle Spearrin
4aa5ba2754 use crypto service 2019-04-15 07:56:46 -04:00
Kyle Spearrin
f228758fb7 domains and cipherview 2019-04-13 22:53:20 -04:00
Kyle Spearrin
d136eee224 field and password history domains/views 2019-04-12 17:21:21 -04:00
Kyle Spearrin
52a978a59a cipher data 2019-04-12 16:55:14 -04:00
Kyle Spearrin
8ade49c958 domains and view stubs 2019-04-12 16:39:20 -04:00
Kyle Spearrin
7c6c36b744 attachment models 2019-04-12 15:50:30 -04:00
Dustin C. Hatch
6c59bf8717 Android: Support autofill in Fennec F-Droid (#483)
The F-Droid build of Firefox (Fennec) has a different package name.
This name needs to be explicitly listed in order for autofill support to
work correctly.
2019-04-12 15:32:58 -04:00
Kyle Spearrin
87798612a6 more models 2019-04-12 11:42:45 -04:00
Kyle Spearrin
c89805d123 setup more models 2019-04-12 10:06:47 -04:00
Kyle Spearrin
a1ba2bf60b setup domain and view 2019-04-11 23:57:41 -04:00
Kyle Spearrin
87543f5beb api service interface 2019-04-11 23:57:05 -04:00
Kyle Spearrin
2e31a7b280 settings service 2019-04-11 16:27:45 -04:00
Kyle Spearrin
9fb2ce9297 mobile messaging service 2019-04-11 15:50:51 -04:00
Kyle Spearrin
567d527a71 fixes to i18n service 2019-04-11 15:43:13 -04:00
Kyle Spearrin
6ee109dc80 i18n service 2019-04-11 15:33:10 -04:00
Kyle Spearrin
6a65b6d735 platform utils init 2019-04-11 14:28:38 -04:00
Kyle Spearrin
b9838ecc4e service container 2019-04-11 14:14:34 -04:00
Kyle Spearrin
e1080f9be4 add app resources resx 2019-04-10 17:01:25 -04:00
Kyle Spearrin
115fa349d2 account apis 2019-04-10 15:35:23 -04:00
Kyle Spearrin
567161d8f3 auth apis and api helpers 2019-04-10 15:03:09 -04:00
Kyle Spearrin
579a7e0398 stub out beginnings of apiservice 2019-04-10 10:49:24 -04:00
Kyle Spearrin
0d417b3eee more device actions 2019-04-09 23:33:12 -04:00
Kyle Spearrin
9e51c46522 mobile platform utils 2019-04-09 23:24:03 -04:00
Kyle Spearrin
36780c5ef8 lots of enums 2019-04-09 17:14:16 -04:00
Kyle Spearrin
9e3ee50020 move some xamarin specific services to app proj 2019-04-09 17:10:56 -04:00
Kyle Spearrin
963b27fd71 state service 2019-04-09 17:01:55 -04:00
Kyle Spearrin
13a2206735 user service 2019-04-09 16:13:32 -04:00
Kyle Spearrin
929727ba41 token service 2019-04-09 10:35:21 -04:00
Kyle Spearrin
a0f6af8097 requires nuget refs 2019-04-09 10:00:32 -04:00
Kyle Spearrin
f79f93ba43 editor config with guideline at 120 2019-04-09 09:47:22 -04:00
Kyle Spearrin
0898e3cc09 no nuget packages directly 2019-04-09 09:33:08 -04:00
Kyle Spearrin
c68927c17a crypto service interface 2019-04-09 09:08:15 -04:00
Kyle Spearrin
9f740cf371 remove app reference 2019-04-08 21:42:19 -04:00
Kyle Spearrin
474ce458bf ios core lib 2019-04-08 21:38:17 -04:00
Kyle Spearrin
8c6823c463 key chain storage service 2019-04-08 21:23:16 -04:00
Kyle Spearrin
8055de4f25 shared name 2019-04-08 20:59:19 -04:00
Kyle Spearrin
d1c1aff7d9 mobile storage service 2019-04-08 20:54:59 -04:00
Kyle Spearrin
41321e3c9e json settings 2019-04-08 20:49:48 -04:00
Kyle Spearrin
992cf033f2 support more object types by using JSON strings 2019-04-08 20:48:18 -04:00
Kyle Spearrin
24b4073616 support bool type 2019-04-08 20:33:52 -04:00
Kyle Spearrin
4ef8ccaa8e support nullable preference types 2019-04-08 20:32:12 -04:00
Kyle Spearrin
f0eca137ef crypto service implementation 2019-04-08 16:04:41 -04:00
Kyle Spearrin
3f5115728b layout tweaks 2019-04-05 22:30:11 -04:00
Kyle Spearrin
3539d7389e cell buttons 2019-04-05 16:13:17 -04:00
Kyle Spearrin
8c79c42b28 entry cell renderer 2019-04-05 13:35:19 -04:00
Kyle Spearrin
1085808867 rename cell resources 2019-04-04 23:29:29 -04:00
Kyle Spearrin
0a5f9f1b23 remove description from base cell 2019-04-04 23:15:24 -04:00
Kyle Spearrin
8006bcf10c cleanup 2019-04-04 23:00:02 -04:00
Kyle Spearrin
61e95e03c8 BoxedView with LabelCell 2019-04-04 22:28:03 -04:00
Kyle Spearrin
2b2342bcad start writing crypto service 2019-04-03 14:21:54 -04:00
Kyle Spearrin
56b8bc1730 run sass on build 2019-04-03 10:05:37 -04:00
Kyle Spearrin
53aaf7caa8 back to sass 2019-04-02 23:41:17 -04:00
Kyle Spearrin
18f659de7b fix less 2019-04-02 23:22:37 -04:00
Kyle Spearrin
b2c0b02be4 move gulp tasks to sln root 2019-04-02 22:43:22 -04:00
Kyle Spearrin
61c1c6ebf8 build css from less 2019-04-02 22:15:11 -04:00
Kyle Spearrin
b837c600a8 remove css files from source 2019-04-02 21:47:36 -04:00
Kyle Spearrin
54a109345b support new moz browser in accessibility service 2019-04-01 12:57:51 -04:00
Kyle Spearrin
3a90b3beb6 theme manager 2019-03-29 21:23:34 -04:00
Kyle Spearrin
fe52324eea stylesheets 2019-03-29 17:54:03 -04:00
Kyle Spearrin
a1c853d7fc cipher view cell control 2019-03-29 16:52:57 -04:00
Kyle Spearrin
53974c4464 reorg groupings page 2019-03-29 13:24:44 -04:00
Kyle Spearrin
69ac98b2f6 vault groupings page list view stubbed 2019-03-29 12:52:57 -04:00
Kyle Spearrin
d84eece715 compile bindings 2019-03-29 09:16:22 -04:00
Kyle Spearrin
af7a456e96 more moz browsers for autofill 2019-03-29 08:48:48 -04:00
Kyle Spearrin
6088cfe266 resolves #477 2019-03-29 08:43:03 -04:00
Kyle Spearrin
02e03c7654 stub out various pages 2019-03-28 23:52:33 -04:00
Kyle Spearrin
30dd2e993f home page 2019-03-28 17:10:10 -04:00
Kyle Spearrin
574c826036 app id service 2019-03-28 16:45:00 -04:00
Kyle Spearrin
6d22888bf6 crypto function service interface 2019-03-28 16:06:55 -04:00
Kyle Spearrin
556741683d compare crypto alg 2019-03-28 16:04:38 -04:00
Kyle Spearrin
cb9dddc7a7 crypto function service 2019-03-28 15:43:50 -04:00
Kyle Spearrin
fca1dbd6ec secure storage service 2019-03-28 14:09:39 -04:00
Kyle Spearrin
364f25e22a fixes to PreferencesStorageService 2019-03-28 14:09:33 -04:00
Kyle Spearrin
9042702c09 use formatted key 2019-03-28 14:01:36 -04:00
Kyle Spearrin
86f1874379 playground app and json settings for litedb 2019-03-28 13:57:45 -04:00
Kyle Spearrin
781f838ce7 remove installLocation 2019-03-28 13:39:50 -04:00
Kyle Spearrin
addb7a0ecb fix connection string for litedb 2019-03-27 23:47:24 -04:00
Kyle Spearrin
21777602f6 storage services 2019-03-27 23:44:54 -04:00
Kyle Spearrin
a88f799372 rename lib to core 2019-03-27 21:36:28 -04:00
Kyle Spearrin
daee1a8e9d lib project 2019-03-27 21:34:39 -04:00
Kyle Spearrin
afd5d55b5f fontawesome icons 2019-03-27 21:26:57 -04:00
Kyle Spearrin
0f2d2ac7a9 themeing 2019-03-27 21:09:59 -04:00
Kyle Spearrin
a77bf9ddff stub out xamarin project 2019-03-27 20:12:44 -04:00
Kyle Spearrin
297beac169 reset for v2 2019-03-27 16:23:00 -04:00
Kyle Spearrin
5a7f106e3e restore secure flag 2019-03-15 23:00:22 -04:00
Kyle Spearrin
25636ac6ce remove secure flag 2019-03-15 23:00:06 -04:00
Kyle Spearrin
6d11921f45 exclude TextFlagMultiLine from autofill detection 2019-02-26 11:50:02 -05:00
Kyle Spearrin
05f6d6d156 opera touch support 2019-02-19 22:25:15 -05:00
Kyle Spearrin
b0cabbbfc2 parsed ShouldAutofill with app URL blacklist 2019-02-10 22:16:16 -05:00
Kyle Spearrin
4b9fa5041c bump version for ios 2019-02-04 08:56:19 -05:00
Kyle Spearrin
ed2ea75938 invoke Dispatch handler 2019-02-04 08:53:54 -05:00
Kyle Spearrin
a1fdc4a970 detect hidden field even when toggled 2019-01-25 09:08:13 -05:00
kspearrin
d20b3cadbf fix opening file on ipad 2019-01-25 08:55:26 -05:00
kspearrin
1374ee31ba remove additional ga refs 2019-01-25 08:55:26 -05:00
Kyle Spearrin
062f6b6665 remove whitespace 2019-01-24 14:46:27 -05:00
ShirokaiLon
8053e6cb81 Set Android InputType directly for the pin lock screen to force numeric-only keyboard layout. (#451)
* Set Android InputType directly for the pin lock screen to force numeric-only keyboard layout.

* Renamed variable
2019-01-24 14:45:42 -05:00
ShirokaiLon
60c5bbc73d Handle exception when adding attachment that does not exist on file system. (#449) 2019-01-22 15:53:48 -05:00
Kyle Spearrin
f0fb401d07 analytics not part of fdroid build any longer 2019-01-16 17:29:05 -05:00
Kyle Spearrin
6f3c302f28 missing null check 2019-01-16 16:38:12 -05:00
Kyle Spearrin
ba5495877c disable test nodes 2019-01-16 16:15:13 -05:00
Kyle Spearrin
2b8fe5fa98 New Crowdin translations (#445)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Korean)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Czech)

* New translations copy.resx (Czech)

* New translations copy.resx (English, United Kingdom)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations copy.resx (English, United Kingdom)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (Finnish)

* New translations copy.resx (Finnish)

* New translations AppResources.resx (Finnish)

* New translations copy.resx (Vietnamese)
2019-01-15 20:26:21 -05:00
Kyle Spearrin
c4253e63d2 Revert "New Crowdin translations (#440)"
This reverts commit 0694721e68.
2019-01-15 20:19:27 -05:00
Kyle Spearrin
8c1dc9c4ae Revert "New Crowdin translations (#443)"
This reverts commit bfddb2b4d6.
2019-01-15 20:19:17 -05:00
Kyle Spearrin
bfddb2b4d6 New Crowdin translations (#443)
* New translations copy.resx (Danish)

* New translations copy.resx (Czech)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Spanish)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (English, United Kingdom)

* New translations copy.resx (Finnish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (French)

* New translations AppResources.resx (English, United Kingdom)

* New translations copy.resx (Danish)

* New translations copy.resx (German)

* New translations copy.resx (French)

* New translations copy.resx (Finnish)

* New translations copy.resx (English, United Kingdom)

* New translations copy.resx (Czech)

* New translations copy.resx (Vietnamese)
2019-01-15 19:08:29 -05:00
Kyle Spearrin
b53ba52d05 en-gb support 2019-01-15 17:54:52 -05:00
Kyle Spearrin
0694721e68 New Crowdin translations (#440)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations copy.resx (English, United Kingdom)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations copy.resx (English, United Kingdom)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Finnish)
2019-01-15 17:35:48 -05:00
Kyle Spearrin
bc0084cc8b bump version 2019-01-15 11:33:57 -05:00
Kyle Spearrin
d3d4cca0e8 remove analytics settings 2019-01-15 11:30:13 -05:00
Kyle Spearrin
5b6becc63f remove analytics 2019-01-15 11:19:31 -05:00
Kyle Spearrin
7ed015aeb1 dont sub 1 when getting next random value 2019-01-13 22:11:01 -05:00
Kyle Spearrin
a8b84da17f New Crowdin translations (#429)
* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (French)
2018-12-27 09:22:21 -05:00
Kyle Spearrin
2d687c98df dont return if no identity 2018-12-24 11:29:12 -05:00
Kyle Spearrin
9c2a6da692 add qwant browser to autofill 2018-12-19 16:16:45 -05:00
Kyle Spearrin
ee9ecfbee9 revert colorized password on password generator 2018-12-15 16:56:06 -05:00
Kyle Spearrin
9d8a9387bc copy model password, not label text 2018-12-12 08:21:15 -05:00
Kyle Spearrin
8934cebc2a update fingerprint lib 2018-12-11 17:06:26 -05:00
Kyle Spearrin
c03a42e108 disable all install scripts 2018-12-11 10:16:17 -05:00
Kyle Spearrin
a39dfcf4d5 disable cloc 2018-12-11 10:15:56 -05:00
Kyle Spearrin
f25ab537f2 clear focus on cell 2018-12-11 10:13:17 -05:00
kspearrin
ff776e485a new instance of deviceservice 2018-12-10 11:56:07 -05:00
Kyle Spearrin
3b9f4433ad ClearExtensionCiphersCache 2018-12-10 11:48:35 -05:00
Kyle Spearrin
a8c18cf83a FormattedPassword formatting 2018-12-10 09:42:58 -05:00
Kyle Spearrin
dff91dc67d no folder fixes for groupings display 2018-12-10 09:41:21 -05:00
Kyle Spearrin
fdea212415 formatting fixes 2018-12-10 09:41:10 -05:00
Andreas Schneider
421f7e8799 Colorized passwords (#424)
* Added utility to format passwords using spans

* Use the password formatter to render the cipher password

* Colorize the password in the password generator
2018-12-10 09:30:11 -05:00
Kyle Spearrin
8fc5ad099b name short 2018-12-06 14:49:26 -05:00
Kyle Spearrin
0b1c0be0f0 support for showing groupings on ciphers list page 2018-12-06 14:17:28 -05:00
Kyle Spearrin
5cc1e2bb29 only show top level groupings on main vault page 2018-12-05 17:26:16 -05:00
Kyle Spearrin
c0eb84b7b1 bump version 2018-12-03 22:24:07 -05:00
Kyle Spearrin
66e8d955d9 allow cleartextTrafficPermitted for base config 2018-12-02 13:06:35 -05:00
Farzad E
e280f585cf Honor user CA store when targeting Android Nougat SDK and later (#420)
* Included network-security-config.xml file to honor user added CAs (see:
https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html)

* Added domain-config entry to only use system CAs connecting to bitwarden.com

* Deny all plaintext traffic from network_security_config


Ref: https://developer.android.com/training/articles/security-config#CleartextTrafficPermitted
2018-12-02 08:56:16 -05:00
Kyle Spearrin
366578600b accessible typo 2018-11-30 11:28:35 -05:00
Kyle Spearrin
8611501423 nested tree node traversal helpers 2018-11-29 19:42:24 -05:00
Kyle Spearrin
8175af4e84 add steam support for otp generation 2018-11-29 17:10:51 -05:00
Kyle Spearrin
7ff628ea51 deprecate mac checks on RSA decrypt 2018-11-26 16:05:30 -05:00
Kyle Spearrin
5792372a47 bump version 2018-11-26 09:14:07 -05:00
Kyle Spearrin
9a169251d7 New Crowdin translations (#417)
* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Portuguese)

* New translations copy.resx (Russian)

* New translations copy.resx (Russian)
2018-11-26 08:41:46 -05:00
Kyle Spearrin
2f0935dbbe update libs 2018-11-23 09:20:39 -05:00
Kyle Spearrin
5af7c7d58a Revert "comment out keyboard dismissal"
This reverts commit ed087b81b4.
2018-11-22 21:16:11 -05:00
Kyle Spearrin
9e1abb13a3 Revert "dont focus on cell tapped"
This reverts commit bbea5fe53c.
2018-11-22 21:16:02 -05:00
Kyle Spearrin
bbea5fe53c dont focus on cell tapped 2018-11-21 21:46:26 -05:00
Kyle Spearrin
ed087b81b4 comment out keyboard dismissal 2018-11-21 07:58:21 -05:00
Kyle Spearrin
0b06c87cb7 New Crowdin translations (#411)
* New translations AppResources.resx (German)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Spanish)
2018-11-20 22:48:03 -05:00
Kyle Spearrin
a9d204d3fa support attachment key, 100k iterations on regist. 2018-11-19 22:24:10 -05:00
Kyle Spearrin
36e263b9ff zh-HK gets traditional chinse 2018-11-15 08:23:45 -05:00
Kyle Spearrin
49af74729f update packages 2018-10-25 21:55:46 -04:00
Kyle Spearrin
aec0415cad New Crowdin translations (#398)
* New translations AppResources.resx (German)

* New translations AppResources.resx (Spanish)
2018-10-24 13:03:55 -04:00
Kyle Spearrin
8c8cec08e5 New Crowdin translations (#395)
* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Turkish)
2018-10-16 08:58:57 -04:00
Kyle Spearrin
8d0ee1caba bump version 2018-10-09 09:39:44 -04:00
Kyle Spearrin
a2a6d5a57f New Crowdin translations (#389)
* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Ukrainian)
2018-10-09 09:29:07 -04:00
Kyle Spearrin
9593f330db target android sdk 26 with fixes to HybridWebView 2018-10-08 23:21:29 -04:00
Kyle Spearrin
144d932591 null ref check 2018-10-08 15:04:18 -04:00
Kyle Spearrin
726db336a8 dont try to fill unless has username and password 2018-10-07 07:40:44 -04:00
Kyle Spearrin
8632f7cadc version bump 2018-10-06 19:26:54 -04:00
Kyle Spearrin
525b5fa19a null checks 2018-10-06 17:28:40 -04:00
Kyle Spearrin
b7c6b65a3d bump version 2018-10-03 00:35:06 -04:00
kspearrin
a4f93eea45 ios < 12 fixes 2018-10-03 00:29:42 -04:00
Kyle Spearrin
8d9a5bc08f formatting 2018-10-01 14:37:16 -04:00
Kyle Spearrin
28a93cdcb4 bump version 2018-10-01 14:19:28 -04:00
Kyle Spearrin
d32dd95e12 add minimum os version 2018-10-01 14:19:28 -04:00
kspearrin
f19a8a3cc5 os version checks on auth service apis 2018-09-29 12:14:44 -04:00
Kyle Spearrin
f8d5ee9d5d bump version 2018-09-26 12:38:26 -04:00
kspearrin
a98fb7d41e back button should be white 2018-09-26 12:36:31 -04:00
kspearrin
d2ccc5c022 remove min os 2018-09-25 14:35:41 -04:00
Kyle Spearrin
3339c8b676 fix navbar color on setup 2018-09-24 16:59:05 -04:00
kspearrin
2cc331b136 support loginSearchSegue when no service ids 2018-09-24 16:34:50 -04:00
Kyle Spearrin
df1a65e6a3 fix color on search nav bar 2018-09-24 16:20:17 -04:00
Kyle Spearrin
f416f95b77 reuse code 2018-09-24 16:11:54 -04:00
kspearrin
44fe5af4fb run on main thread fixes 2018-09-24 15:45:36 -04:00
Kyle Spearrin
f394eddc01 throttle fast type searches 2018-09-24 15:30:05 -04:00
kspearrin
07dd9df3ec no search display controller 2018-09-24 15:24:43 -04:00
Kyle Spearrin
340d4ce714 do searching 2018-09-24 15:08:16 -04:00
kspearrin
2870b8331e text changed 2018-09-24 14:57:28 -04:00
Kyle Spearrin
bc79f22e22 implement search delegate 2018-09-24 14:51:37 -04:00
Kyle Spearrin
b3e0b148a6 not translucent 2018-09-24 12:50:58 -04:00
Kyle Spearrin
6131dfeb2c add tint colors to search nav bar 2018-09-24 12:43:19 -04:00
kspearrin
42fc868b68 Search controller for autofill setup 2018-09-24 12:41:08 -04:00
Kyle Spearrin
e9ec02929d Revert "add login search view controller"
This reverts commit 389d7d77c2.
2018-09-24 11:25:43 -04:00
Kyle Spearrin
389d7d77c2 add login search view controller 2018-09-24 11:24:12 -04:00
Kyle Spearrin
03a55d38d3 move power manager check inside try/catch 2018-09-23 08:08:38 -04:00
Kyle Spearrin
5504298251 adjust check green color 2018-09-22 23:49:47 -04:00
Kyle Spearrin
0fff61de34 New Crowdin translations (#374)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)
2018-09-22 23:45:30 -04:00
Kyle Spearrin
4db7311611 remove period 2018-09-22 23:43:36 -04:00
Kyle Spearrin
650d970b5e fix GA service methods 2018-09-22 23:37:44 -04:00
Kyle Spearrin
7f796963f3 no need to install sdk 28 anymore 2018-09-22 23:31:42 -04:00
Kyle Spearrin
9231da2f1c Revert "remove credential provider from main app entitle"
This reverts commit 0d422c53d1.
2018-09-22 23:22:48 -04:00
Kyle Spearrin
0d422c53d1 remove credential provider from main app entitle 2018-09-22 23:05:21 -04:00
kspearrin
7bf9354e32 provide credentials if using fingerprint too 2018-09-22 22:06:12 -04:00
kspearrin
277fd67814 add bitwarden domain 2018-09-22 21:58:50 -04:00
Kyle Spearrin
68e9cd3779 only copy totp key is setting not disabled 2018-09-21 23:32:26 -04:00
Kyle Spearrin
73b2ae71a9 copy totp code. derp 2018-09-21 23:29:05 -04:00
kspearrin
f9028245d8 better handle service identifiers 2018-09-21 22:27:20 -04:00
Kyle Spearrin
3fff0617fe replace all on updates 2018-09-21 21:59:11 -04:00
Kyle Spearrin
d958dc6bce replace vs created on save 2018-09-21 21:53:04 -04:00
Kyle Spearrin
045ce42168 add alert for autofill extension 2018-09-21 21:52:46 -04:00
kspearrin
edef84a4f9 return instead of else 2018-09-21 20:40:34 -04:00
kspearrin
ec9b2d7f7d add item to cred store when added from extension 2018-09-21 20:22:13 -04:00
Kyle Spearrin
640beeed23 delete cipher messages passes object 2018-09-21 17:04:54 -04:00
Kyle Spearrin
a998ee84ec fix strings 2018-09-21 16:26:55 -04:00
kspearrin
bd74634201 spacing 2018-09-21 16:25:31 -04:00
Kyle Spearrin
364287028b autofill instructions 2018-09-21 16:20:17 -04:00
Kyle Spearrin
7be8513bb5 updated autofill tools page strings 2018-09-21 16:11:11 -04:00
Kyle Spearrin
89c2f62f11 autofill tools page for ios 12 2018-09-21 16:03:34 -04:00
Kyle Spearrin
fce2a7ba94 cleanup and updated resource strings for autofill 2018-09-21 15:32:12 -04:00
kspearrin
e613198252 updated 2018-09-21 15:15:02 -04:00
Kyle Spearrin
3e240c4d2f setup view controller during config 2018-09-21 15:06:23 -04:00
kspearrin
eee96bf8cf config flow 2018-09-21 14:29:42 -04:00
Kyle Spearrin
471871eb2e done use this. 2018-09-21 12:45:32 -04:00
Kyle Spearrin
225b8b8cd8 Merge branch 'master' of github.com:bitwarden/mobile 2018-09-21 12:45:16 -04:00
kspearrin
cb2d133eb0 remove base calls 2018-09-21 12:00:44 -04:00
kspearrin
d957111249 remove base method calls 2018-09-21 12:00:07 -04:00
Kyle Spearrin
f0a701e134 formatting 2018-09-21 11:25:44 -04:00
kspearrin
0c8c216fba only build id store if authed 2018-09-21 11:23:34 -04:00
kspearrin
f153c7509c build identity store for quick type bar 2018-09-21 11:22:06 -04:00
Kyle Spearrin
197683b722 messages for credential store 2018-09-21 09:57:24 -04:00
Kyle Spearrin
fbce0be457 listen to messages for credential store updates 2018-09-20 23:54:03 -04:00
Kyle Spearrin
24304c2f55 formatting 2018-09-20 23:50:02 -04:00
Kyle Spearrin
b0c6c09cea full sync and cipher modification messages 2018-09-20 23:47:19 -04:00
kspearrin
2732fc93f9 provide credential implementations 2018-09-20 23:24:59 -04:00
Kyle Spearrin
cc9a4a288a fix analytics for autofill events 2018-09-20 23:02:53 -04:00
kspearrin
f57db917d1 wire up shared view controllers 2018-09-20 22:53:23 -04:00
Kyle Spearrin
d32eb9c9bc copy classes to autofill 2018-09-20 22:24:13 -04:00
Kyle Spearrin
219af7f288 extract extension table source 2018-09-20 22:18:25 -04:00
kspearrin
e767b6c5be missing using 2018-09-20 22:06:53 -04:00
Kyle Spearrin
5f1a8017f1 moved view controllers to core library for reuse 2018-09-20 21:54:01 -04:00
kspearrin
df80122ce1 moved cipher model 2018-09-20 16:44:41 -04:00
kspearrin
6904ea118b basic autofill 2018-09-20 16:44:06 -04:00
kspearrin
0baa07daa2 load ioc and stuff 2018-09-20 13:18:30 -04:00
kspearrin
2abf407b36 move to default storyboard from xcode 2018-09-20 12:53:53 -04:00
kspearrin
55dc9cbfc7 log debug 2018-09-20 09:29:48 -04:00
Kyle Spearrin
fa15a10ae0 entitle main project for autofill 2018-09-19 23:18:53 -04:00
Kyle Spearrin
e821d8a135 reference autofill project 2018-09-19 23:10:26 -04:00
kspearrin
cefcc14d4d update autofill files 2018-09-19 23:08:39 -04:00
Kyle Spearrin
a52d1e1506 autofill project 2018-09-19 22:25:16 -04:00
Kyle Spearrin
42df1aecd5 New Crowdin translations (#371)
* New translations AppResources.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Korean)
2018-09-17 15:33:18 -04:00
Kyle Spearrin
920f4fc525 trim email 2018-09-15 23:36:32 -04:00
Kyle Spearrin
d57d583076 bump version 2018-09-14 16:36:38 -04:00
Kyle Spearrin
1c8cd2dcbb remove unused const strings 2018-09-12 15:53:27 -04:00
Kyle Spearrin
bb66a6c805 add firefox nightly, resolves #368 2018-09-10 08:17:22 -04:00
Kyle Spearrin
10ecdfbe31 add more autofill compat support 2018-09-06 00:17:26 -04:00
Kyle Spearrin
43dad1df63 dont need to rdp anymore 2018-09-05 17:37:05 -04:00
Kyle Spearrin
fdcc6b0cb8 change back to pwd, out-null 2018-09-05 17:19:53 -04:00
Kyle Spearrin
ac82d6bc6b update android using sdkmanager 2018-09-05 17:01:28 -04:00
Kyle Spearrin
a8e98cfa78 rdp for debugging 2018-09-05 16:37:13 -04:00
Kyle Spearrin
fa51314639 update-android for appveyor 2018-09-04 08:00:02 -04:00
Kyle Spearrin
3e0097c22c update android sdks on appveyor 2018-09-04 07:58:09 -04:00
Kyle Spearrin
e62ff2fe36 fix appveoyr yml 2018-09-03 23:05:54 -04:00
Kyle Spearrin
88a13eb54f update vs 2018-09-03 23:02:37 -04:00
Kyle Spearrin
355dc151c4 add more compat 2018-09-03 22:32:55 -04:00
Kyle Spearrin
4f0ea44078 update to android 9, test compat autofill mode. 2018-09-03 10:09:17 -04:00
Kyle Spearrin
9cc12fd577 check enabled too 2018-08-29 13:45:58 -04:00
Kyle Spearrin
960c2567bd can access premium for orgs 2018-08-29 12:36:44 -04:00
Kyle Spearrin
430e4dd445 rename UserPushNotification 2018-08-28 08:47:47 -04:00
Kyle Spearrin
1ec31c6899 add support for log out notification 2018-08-28 08:41:23 -04:00
Kyle Spearrin
42c21ce892 PBKDF2 is SHA256 2018-08-28 08:41:23 -04:00
kspearrin
d278fde5f2 fix missing params on extension 2018-08-24 17:10:52 -04:00
Kyle Spearrin
2616a5f500 bump versions 2018-08-21 16:29:31 -04:00
BestPig
cc58f7730e Use BaseUrl when opening web vault if defined (#360) 2018-08-20 13:32:16 -04:00
Kyle Spearrin
d49e001b21 New Crowdin translations (#358)
* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (French)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (Portuguese, Brazilian)
2018-08-16 15:18:21 -04:00
Kyle Spearrin
f12ceb69ce update public suffix list 2018-08-15 08:44:21 -04:00
Kyle Spearrin
7862005055 support for prelogin kdf params 2018-08-14 16:46:31 -04:00
Kyle Spearrin
e70dbf8d8d add UmAlQuraCalendar 2018-08-13 07:55:26 -04:00
Kyle Spearrin
16ee34d7a7 set calendars removed by linker 2018-08-13 07:54:08 -04:00
Kyle Spearrin
2ad55e8a8c New Crowdin translations (#353)
* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Ukrainian)
2018-08-09 17:34:58 -04:00
Kyle Spearrin
a8a1750d5c version bump 2018-08-09 11:48:10 -04:00
Kyle Spearrin
5407e20150 update libs 2018-08-04 00:55:01 -04:00
Kyle Spearrin
58aa37bf8e catch EnableForegroundDispatch exception. disable
back button on yubikey 2fa.
2018-08-01 15:45:32 -04:00
Kyle Spearrin
7c781b60c5 add protocol if missing 2018-08-01 15:32:12 -04:00
Kyle Spearrin
acdfce7e88 support otpath:// totp secrets 2018-07-31 12:34:10 -04:00
Kyle Spearrin
4e4b56d7fe password updated fixes 2018-07-30 22:42:54 -04:00
Kyle Spearrin
a3174d7015 New Crowdin translations (#349)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)
2018-07-30 17:14:39 -04:00
Kyle Spearrin
b595c8aeac contrib updates 2018-07-30 17:07:44 -04:00
Kyle Spearrin
a9a33ad71e save password history changes 2018-07-30 16:15:36 -04:00
Kyle Spearrin
4d08ce90cc Merge branch 'master' of github.com:bitwarden/mobile 2018-07-30 13:16:04 -04:00
Kyle Spearrin
01d9ccc110 add password history and updated dates 2018-07-30 13:15:53 -04:00
Jacob
029f069ad5 fetch image from bitwarden/brand (#345) 2018-07-19 10:51:15 -04:00
Kyle Spearrin
13b9e01604 check lock only if locked on all pages 2018-07-16 23:14:45 -04:00
Kyle Spearrin
19c46a472a fix name bug on section group names 2018-07-16 10:24:53 -04:00
Kyle Spearrin
37edfffb97 move last launch check after _lastQueriedUri 2018-07-16 10:17:05 -04:00
Kyle Spearrin
67fa653d06 prevent multiple main activities from autofill 2018-07-16 10:07:22 -04:00
Kyle Spearrin
366b9ddc4a update libs. update android security provider 2018-07-16 08:55:37 -04:00
Kyle Spearrin
c9354f79b8 add escosia browser autofill 2018-07-16 08:40:38 -04:00
Kyle Spearrin
d5b3bd5905 remove no connection alert on appearing of pages 2018-07-12 13:12:42 -04:00
Kyle Spearrin
45dd240415 include some type info with extension exception 2018-06-30 08:55:54 -04:00
Kyle Spearrin
bf99cea004 possible null pointer fix 2018-06-30 08:19:18 -04:00
Kyle Spearrin
f680b1e856 update libs 2018-06-30 00:06:41 -04:00
Kyle Spearrin
b2f40c7af0 fix track bug 2018-06-29 15:26:46 -04:00
Kyle Spearrin
82b17677b9 default track is alpha 2018-06-29 15:24:19 -04:00
Kyle Spearrin
b7df2d5441 rollout track 2018-06-29 15:05:40 -04:00
Kyle Spearrin
dd511ba365 tracks are now strings 2018-06-29 15:04:34 -04:00
Kyle Spearrin
d705e3c1fb version bump 2018-06-29 14:19:35 -04:00
Kyle Spearrin
4bd1322904 update libs 2018-06-29 14:09:53 -04:00
Kyle Spearrin
ac027ee3a0 add support for kiwi browser 2018-06-29 13:48:47 -04:00
Kyle Spearrin
e5e3ebdbba update to Xamarin forms 3.1 2018-06-29 12:45:10 -04:00
Kyle Spearrin
993fc2e6f4 bump version 2018-06-29 10:42:28 -04:00
Kyle Spearrin
61c480618c try to generate key with and without date 2018-06-29 10:39:29 -04:00
Kyle Spearrin
db7f2622c8 org.chromium.chrome support 2018-06-28 23:33:34 -04:00
kspearrin
a39e78a989 increment ios build num 2018-06-19 20:18:07 -04:00
Kyle Spearrin
5a461d68a7 New Crowdin translations (#330)
* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Ukrainian)
2018-06-19 20:07:48 -04:00
Kyle Spearrin
899816673c change icons server to bitwarden.net 2018-06-19 18:02:49 -04:00
Kyle Spearrin
84a10139c1 designer update 2018-06-19 14:28:31 -04:00
Kyle Spearrin
da3aa56d86 add ko and fa languages 2018-06-18 21:24:29 -04:00
Kyle Spearrin
a6dcd512ea update designer 2018-06-18 15:35:04 -04:00
Kyle Spearrin
572d32c1de New Crowdin translations (#329)
* New translations AppResources.resx (Bulgarian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Persian)

* New translations copy.resx (Persian)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations copy.resx (Korean)

* New translations copy.resx (Korean)

* New translations copy.resx (Romanian)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Czech)

* New translations copy.resx (Dutch)

* New translations copy.resx (Dutch)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Czech)

* New translations copy.resx (Czech)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)

* New translations copy.resx (Vietnamese)
2018-06-18 15:30:24 -04:00
Kyle Spearrin
e8b67ead1e version bump 2018-06-18 15:23:11 -04:00
Kyle Spearrin
377029226e allow non-nfc keys on android 2018-06-18 14:10:43 -04:00
Kyle Spearrin
72d1421f1d shows both accessibility and autofill from tools 2018-06-18 13:59:56 -04:00
Kyle Spearrin
d359547dab monospace fonts for card code 2018-06-18 09:12:03 -04:00
Neil Burrows
9523c7ab33 Card Security Code masked (bitwarden/desktop issue 78) (#328)
* Card Security Code masked in the same way as Passwords. (bitwarden/desktop issue 78)

By default shows Card Security Code masked in the same way as Passwords. (bitwarden/desktop issue 78)

* Creating property to store value of Masked Card Code Shown
2018-06-18 09:00:45 -04:00
Kyle Spearrin
7cac07c185 add pbkdf2 key stretching 2018-06-13 22:41:18 -04:00
Kyle Spearrin
a607a7f3ef clear cache flag on disk 2018-06-08 09:13:42 -04:00
Kyle Spearrin
b5277e89d5 add bromite autofill support 2018-06-08 08:59:54 -04:00
kspearrin
99713f8ed7 remove password generate event on disappear 2018-06-05 11:13:15 -04:00
Kyle Spearrin
145dac500c appresources for ios yubikey 2018-06-04 21:08:55 -04:00
kspearrin
eefd9bf31c update yubikey options for ios 2018-06-04 21:06:17 -04:00
Kyle Spearrin
3f47ca645b iphone yubikey images 2018-06-04 21:02:20 -04:00
Kyle Spearrin
c906f037b5 checked for locked state on activity resume.
resolves #319
2018-06-04 09:20:38 -04:00
Kyle Spearrin
ffc4e32119 run cloc on install 2018-06-01 14:45:56 -04:00
Kyle Spearrin
51eb46241b Revert "previous 2017"
This reverts commit 541416f64b.
2018-05-29 15:54:57 -04:00
Kyle Spearrin
541416f64b previous 2017 2018-05-29 15:47:39 -04:00
Kyle Spearrin
14d1d132a3 dont set key validity dates 2018-05-29 15:21:43 -04:00
Kyle Spearrin
22a0045796 try again button for ios yubikey 2018-05-24 22:43:59 -04:00
Kyle Spearrin
2e5ba0335d hide yubikey token cell for ios 2018-05-24 22:40:02 -04:00
Kyle Spearrin
3315704c14 cleanup 2018-05-24 22:34:17 -04:00
Kyle Spearrin
f90c407fb6 move nfc delegate to member of appdelegate class 2018-05-24 22:33:29 -04:00
Kyle Spearrin
d3646e10a5 clearup yubikey reading on ios 2018-05-24 15:34:09 -04:00
Kyle Spearrin
d3003efe72 remove nfc from extension 2018-05-24 14:01:00 -04:00
Kyle Spearrin
235ca947be turn on nfc in plist 2018-05-24 13:50:11 -04:00
Kyle Spearrin
e7bc9ed5ba nfc updates 2018-05-24 12:49:22 -04:00
Kyle Spearrin
740a18dbc0 stub out yubico nfc support for ios 2018-05-24 11:41:57 -04:00
Kyle Spearrin
add5189bb1 add via to oreo trusted browsers 2018-05-21 23:26:54 -04:00
Kyle Spearrin
62002b8bb3 disable test nodes 2018-05-21 22:53:32 -04:00
Kyle Spearrin
41b4ee33fe adjust max_aspect ratio for samsung full screen 2018-05-20 10:14:54 -04:00
Kyle Spearrin
85c67ac676 version bump 2018-05-18 21:42:51 -04:00
Kyle Spearrin
4637b7d93f update fingerprint lib 2018-04-28 00:25:58 -04:00
Kyle Spearrin
8b9a178c87 faceid description in info.plist 2018-04-28 00:23:31 -04:00
Kyle Spearrin
c595c381a9 bump android version 2018-04-26 00:06:43 -04:00
Kyle Spearrin
c308d7a610 look for password fields from HtmlInfo attributes 2018-04-26 00:04:07 -04:00
Kyle Spearrin
f7570122c6 ignore "edit" fields on autofill 2018-04-26 00:04:07 -04:00
Kyle Spearrin
1e5f186b58 Search Login URI as well 2018-04-26 00:04:07 -04:00
kspearrin
b732b2ffa7 remove password debug code 2018-04-20 20:14:39 -04:00
Kyle Spearrin
617a7be4f3 version bump 2018-04-17 11:28:23 -04:00
Kyle Spearrin
5c5e368d6b comment out password debug 2018-04-17 11:03:36 -04:00
Kyle Spearrin
ff9f49416a track with node id + hash code 2018-04-16 11:01:32 -04:00
Kyle Spearrin
93cae0e9cc dont check ids 2018-04-16 09:00:51 -04:00
Kyle Spearrin
61e75ce747 remove UWP projects so CI will work 2018-04-16 08:28:17 -04:00
Kyle Spearrin
50affe26c5 update resources 2018-04-16 08:18:54 -04:00
kspearrin
8566362607 no need to update vs anymore 2018-04-15 22:00:21 -04:00
kspearrin
36925770d0 show ut8 password alert 2018-04-15 21:45:05 -04:00
kspearrin
d17ca1686e ignore recipient search fields 2018-04-15 21:02:55 -04:00
kspearrin
2ad709dae4 fix ipad crash on doc picker 2018-04-07 12:15:59 -04:00
kspearrin
5a3d86a12a Only adjust insets on phone devices 2018-04-07 11:32:01 -04:00
Kyle Spearrin
1a4ba36820 add support for via browser 2018-04-03 16:08:11 -04:00
Kyle Spearrin
ddeae3b5ba add support for Duo Organization 2FA 2018-04-03 15:59:58 -04:00
Kyle Spearrin
10df9e7cd5 multibutton alert, autofill and save new uri 2018-04-02 13:37:46 -04:00
Kyle Spearrin
be11933c60 remove persian language until further verification 2018-03-29 11:46:09 -04:00
Kyle Spearrin
d2db68b781 New Crowdin translations (#299)
* New translations AppResources.resx (Bulgarian)

* New translations copy.resx (Persian)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Polish)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Persian)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Persian)

* New translations copy.resx (Italian)

* New translations copy.resx (German)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations copy.resx (French)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Vietnamese)
2018-03-29 11:42:49 -04:00
Kyle Spearrin
da6e271584 refactor ignoresearch and password terms detection 2018-03-28 11:48:49 -04:00
Kyle Spearrin
5103c80e1e set default uri on add cipher 2018-03-26 17:06:58 -04:00
Kyle Spearrin
b5c80ea267 version bump 2018-03-22 12:01:17 -04:00
Kyle Spearrin
b5747fbb44 show/hide loading are async now 2018-03-22 11:07:41 -04:00
Kyle Spearrin
215ded8a77 fixes for match detection selection 2018-03-22 09:08:19 -04:00
Kyle Spearrin
e7ab6da068 fix param names for arg null exceptions 2018-03-21 07:35:27 -04:00
Kyle Spearrin
ee881f67ee version bump 2018-03-20 20:21:11 -04:00
Kyle Spearrin
f33248aa4f crash fixes 2018-03-20 20:19:44 -04:00
Kyle Spearrin
c6a40bac03 null checks on dialogs 2018-03-19 21:07:27 -04:00
Kyle Spearrin
aa38e79d08 resource update 2018-03-19 15:57:19 -04:00
Kyle Spearrin
9cac10e559 version bump 2018-03-19 10:24:54 -04:00
Kyle Spearrin
efbd418f56 New Crowdin translations (#296)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Estonian)

* New translations copy.resx (Estonian)

* New translations AppResources.resx (French)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Ukrainian)
2018-03-19 10:15:52 -04:00
Kyle Spearrin
4ff3464abd new ic_launcher for adaptive icons 2018-03-17 17:26:10 -04:00
Kyle Spearrin
907ddbf903 collapse no folder listing if more than 99 items 2018-03-16 10:59:54 -04:00
Kyle Spearrin
7041991d5a android dialog is not cancelable 2018-03-16 10:42:07 -04:00
Kyle Spearrin
b26067e5da domain search term must be at least 3 characters 2018-03-16 10:41:53 -04:00
Kyle Spearrin
e519b13533 extension add login adjustments 2018-03-15 19:57:18 -04:00
Kyle Spearrin
30bc3867bf New Crowdin translations (#295)
* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Polish)

* New translations copy.resx (Russian)

* New translations copy.resx (Polish)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Persian)

* New translations copy.resx (Persian)

* New translations AppResources.resx (Persian)

* New translations copy.resx (Norwegian Bokmal)

* New translations copy.resx (Norwegian Bokmal)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Russian)

* New translations copy.resx (Russian)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Vietnamese)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Ukrainian)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Swedish)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Bulgarian)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Croatian)

* New translations copy.resx (Estonian)

* New translations copy.resx (Croatian)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Traditional)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Chinese Simplified)

* New translations copy.resx (Bulgarian)

* New translations AppResources.resx (Estonian)

* New translations copy.resx (Estonian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Indonesian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (German)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (Finnish)

* New translations copy.resx (Finnish)
2018-03-15 12:41:09 -04:00
Kyle Spearrin
5326c3aecc Match detection string 2018-03-15 10:37:08 -04:00
Kyle Spearrin
c95251c903 switch cell for fields, btn widths on ios too 2018-03-14 22:59:31 -04:00
Kyle Spearrin
e08a0a0938 cog alt buttons 2018-03-14 18:26:07 -04:00
Kyle Spearrin
fcb072c37d fix null ref when no uri 2018-03-14 17:41:18 -04:00
Kyle Spearrin
262c19b194 Change context options to action sheet w/ button 2018-03-13 17:33:45 -04:00
Kyle Spearrin
1031ddcd83 proper class on ExtendedViewCell 2018-03-12 22:46:46 -04:00
Kyle Spearrin
aaee0212f0 ios fixes 2018-03-12 15:42:53 -04:00
Kyle Spearrin
8fc95759ba support login uris from app extension 2018-03-12 13:29:12 -04:00
Kyle Spearrin
b6a3a0a54f noop on ios 2018-03-12 13:18:35 -04:00
Kyle Spearrin
e3091be314 Update ISSUE_TEMPLATE.md 2018-03-10 16:36:40 -05:00
Kyle Spearrin
045d0678b3 Create ISSUE_TEMPLATE.md 2018-03-10 09:47:52 -05:00
Kyle Spearrin
e3eeaddb3e normalize passwords 2018-03-09 22:29:59 -05:00
Kyle Spearrin
f2b202c714 only ignore vault.bitwarden.com 2018-03-08 10:34:07 -05:00
Kyle Spearrin
e6f3ad60ef move fields above attachments on view 2018-03-06 13:32:58 -05:00
Kyle Spearrin
fb6e0c9eb8 moved password generation link to button 2018-03-06 12:40:42 -05:00
Kyle Spearrin
fb6e488339 select URI match option from action sheet 2018-03-06 11:58:02 -05:00
Kyle Spearrin
0bccc8f0d5 loginUri no longer used 2018-03-06 08:51:05 -05:00
Kyle Spearrin
560d831e92 masked password string constant 2018-03-06 07:41:40 -05:00
Mark Cohen
7c8f6a1cc7 Don't leak password length through mask (#293) 2018-03-06 07:37:46 -05:00
Kyle Spearrin
deb1ead4ea trim Uri proper from stored json on save 2018-03-05 23:49:48 -05:00
Kyle Spearrin
005b2a4fb6 add support for uri match rules detection 2018-03-05 23:37:02 -05:00
Kyle Spearrin
4c8204f29a view/add/edit login uris 2018-03-05 22:39:56 -05:00
Kyle Spearrin
83fd19784a refactor for cipher model changes and multi-uris 2018-03-05 17:18:18 -05:00
Kyle Spearrin
1f21a2ecc7 add/edit/delete custom fields. remove field page. 2018-03-05 15:15:20 -05:00
Kyle Spearrin
c3f4d56d1e New Crowdin translations (#288)
* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Russian)

* New translations AppResources.resx (Russian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Slovak)

* New translations copy.resx (Portuguese)

* New translations AppResources.resx (Portuguese)

* New translations copy.resx (Polish)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Norwegian Bokmal)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations copy.resx (Russian)

* New translations copy.resx (Slovak)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Turkish)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations copy.resx (Ukrainian)

* New translations AppResources.resx (Ukrainian)

* New translations copy.resx (Turkish)

* New translations copy.resx (Thai)

* New translations copy.resx (Thai)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Estonian)

* New translations copy.resx (Dutch)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Czech)

* New translations copy.resx (Estonian)

* New translations AppResources.resx (Czech)

* New translations copy.resx (Croatian)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Traditional)

* New translations copy.resx (Estonian)

* New translations AppResources.resx (Finnish)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Indonesian)

* New translations AppResources.resx (Indonesian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Hungarian)

* New translations copy.resx (Hindi)

* New translations copy.resx (Finnish)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (Finnish)

* New translations copy.resx (Vietnamese)
2018-02-27 23:49:47 -05:00
Kyle Spearrin
7e4f79bacb uppercase Bitwarden 2018-02-27 13:37:46 -05:00
Kyle Spearrin
b8267d4329 Uppercase Bitwarden 2018-02-27 13:27:07 -05:00
Kyle Spearrin
205ca693b3 crowdin update_option: update_as_unapproved 2018-02-20 16:17:15 -05:00
Kyle Spearrin
23159c2201 catch ActivityNotFoundException with alert 2018-02-14 17:11:27 -05:00
Kyle Spearrin
884521ced0 premium message on attachments edit page 2018-02-12 08:54:31 -05:00
Kyle Spearrin
aeb01ba292 break if too many iterations 2018-02-10 09:39:45 -05:00
Kyle Spearrin
2b1a556e9e re-enable vs update 2018-02-10 09:38:12 -05:00
Kyle Spearrin
d5c3ae3d19 guard against infinite recursion and loops 2018-02-10 09:35:14 -05:00
Kyle Spearrin
7654bb7088 check if child is same as parent 2018-02-10 00:38:52 -05:00
Kyle Spearrin
64c301caeb password gen fixes 2018-02-09 22:02:56 -05:00
Kyle Spearrin
e875b530b1 bail out if recursiveIterations >= 100 2018-02-09 16:23:51 -05:00
Kyle Spearrin
ee8c2b5272 thread sleeps 2018-02-09 15:00:54 -05:00
Kyle Spearrin
9b8bdb0639 remove log spam 2018-02-09 14:02:17 -05:00
Kyle Spearrin
1a99bbb040 more log info 2018-02-08 22:08:00 -05:00
Kyle Spearrin
0982b45473 more log spam 2018-02-08 17:44:48 -05:00
Kyle Spearrin
bcd210d504 log spam 2018-02-08 17:27:56 -05:00
Kyle Spearrin
c71608824b fix null ref with e.source 2018-02-08 17:07:01 -05:00
Kyle Spearrin
170876ac16 event info logs 2018-02-08 16:36:49 -05:00
Kyle Spearrin
a6b172c445 log and throw accessibility exceptions 2018-02-08 16:33:52 -05:00
Kyle Spearrin
e625450100 disable vs update 2018-02-08 16:00:11 -05:00
Kyle Spearrin
fca5447094 revert accessibility throttling 2018-02-03 09:47:16 -05:00
Kyle Spearrin
89f32beec5 throttle accessibility events 2018-02-03 09:21:27 -05:00
Kyle Spearrin
65eb7662ad remove appveyor debugging. just update vs 2018-02-03 00:00:05 -05:00
Kyle Spearrin
ea090dbe18 just update 2018-02-02 23:48:46 -05:00
Kyle Spearrin
5750817620 quiet update with echos 2018-02-02 22:30:00 -05:00
Kyle Spearrin
93386d0e8b passive update 2018-02-02 22:23:39 -05:00
Kyle Spearrin
e9dd7b8f98 update vs 2018-02-02 22:19:36 -05:00
Kyle Spearrin
5010e7cb7a update visual studio manually 2018-02-02 22:00:58 -05:00
Kyle Spearrin
fb35f4fbca Previous Visual Studio 2017 2018-02-02 13:49:44 -05:00
Kyle Spearrin
00c0a93a6b revert preview image 2018-02-02 13:45:26 -05:00
Kyle Spearrin
cd9a312e0b use VS preview image 2018-02-02 13:38:49 -05:00
Kyle Spearrin
8cdb27fe43 check modal stack before popping 2018-02-01 23:38:18 -05:00
Kyle Spearrin
d84d11d064 update xamarin forms 2018-02-01 23:38:06 -05:00
Kyle Spearrin
5d646a6112 various android crash fixes 2018-02-01 23:25:48 -05:00
Kyle Spearrin
dd334858ff add timeout on timers 2018-02-01 21:20:35 -05:00
Kyle Spearrin
dfd39ebc95 check installed launchers to skip 2018-02-01 21:20:28 -05:00
Kyle Spearrin
9dbb1f15a4 filter nova prime 2018-02-01 17:26:41 -05:00
Kyle Spearrin
32fd04a7d9 more filters 2018-02-01 17:23:41 -05:00
Kyle Spearrin
3a33ff375d turn back on autofill stuff 2018-02-01 17:17:18 -05:00
Kyle Spearrin
8877e71bd2 add back SystemUiPackage 2018-02-01 17:01:37 -05:00
Kyle Spearrin
5b5385c01d add FilteredPackageNames 2018-02-01 16:56:54 -05:00
Kyle Spearrin
9c365ecc48 log events 2018-02-01 16:27:08 -05:00
Kyle Spearrin
99d1a6d043 read RootInActiveWindow after launcher checks 2018-02-01 16:12:30 -05:00
Kyle Spearrin
854ef7e645 log any exceptions 2018-02-01 15:54:39 -05:00
Kyle Spearrin
a8eeb12325 just read RootInActiveWindow 2018-02-01 15:42:07 -05:00
Kyle Spearrin
86a3f516b1 test: start processing some event info 2018-02-01 15:29:41 -05:00
Kyle Spearrin
d6818939b3 test: turn some things back on 2018-02-01 15:21:22 -05:00
Kyle Spearrin
c51449e607 test: dont even init appsettings 2018-02-01 15:03:44 -05:00
Kyle Spearrin
333894ddeb test: do nothing for autofill service 2018-02-01 15:00:43 -05:00
Kyle Spearrin
052e227b65 comment out test nodes 2018-02-01 14:31:53 -05:00
Kyle Spearrin
4dd6df5bbe set package and website independently 2018-01-26 12:15:54 -05:00
Kyle Spearrin
8847991bba show attachments properly if an organization 2018-01-26 11:48:43 -05:00
Kyle Spearrin
0ffc6e4a1a show attachments if premium or org item 2018-01-26 11:02:35 -05:00
Kyle Spearrin
9a399e06f3 decrypt attachment with org id 2018-01-26 09:13:30 -05:00
Kyle Spearrin
6afccc2aea add duckduckgo support 2018-01-26 08:56:43 -05:00
Kyle Spearrin
8cd3a21468 null and length check on name when sorting 2018-01-25 21:20:45 -05:00
Kyle Spearrin
8b6d2d2b83 comment typo 2018-01-25 09:07:19 -05:00
Kyle Spearrin
a39f4d5987 split by no-break space for yandex 2018-01-25 09:06:01 -05:00
Kyle Spearrin
e236d045b0 use MasterPasswordConfirmationValMessage 2018-01-24 20:21:54 -05:00
Alistair Francis
592c7951df UWP: Add a ExtendedTableViewRenderer (#260)
Add a base ExtendedTableViewRenderer we can use.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-19 14:04:58 -05:00
Kyle Spearrin
41efa96291 unsub from yubikey events on disappearing 2018-01-18 13:24:23 -05:00
Kyle Spearrin
53f406a267 log out after 5 failed pin attempts 2018-01-18 13:18:08 -05:00
Kyle Spearrin
1390df48b6 use random key for double hmac comparisons 2018-01-18 09:31:22 -05:00
Kyle Spearrin
01878ef00c check that mac always exists if key has MacKey 2018-01-18 08:39:34 -05:00
Kyle Spearrin
6f119f25f4 missing props on TokenCell 2018-01-18 08:09:18 -05:00
Alistair Francis
3f31d78db1 Add YubiKey keyboard support (#248)
* App: Pages: Fix the YubiKey image source

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* App: Allow YubiKey keyboard output on apps

On Android and UWP it's possible to use the YubiKey to enter text
instead of using the NFC. Allow people to do that.

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* App: Pages: Enable YubiKey support on Windows platforms

Windows platforms should always have YubiKey support.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-18 07:55:06 -05:00
Alistair Francis
014bf7777b Update some images (#257)
* UWP.Images: Update the launch.png image size

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* App: Pages: Update login toolbar button

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-17 08:29:59 -05:00
Kyle Spearrin
7191969e9c Update README.md 2018-01-14 21:43:25 -05:00
Kyle Spearrin
0950510526 scope if shorthand 2018-01-11 12:07:13 -05:00
Kyle Spearrin
9eba3064a7 formatting 2018-01-11 12:02:03 -05:00
Kyle Spearrin
a4d785258e build for configuration release 2018-01-11 09:04:58 -05:00
Kyle Spearrin
efef49f976 Revert "choose/when fdroid conditional on packages"
This reverts commit b3573f9482.
2018-01-11 09:03:05 -05:00
Kyle Spearrin
32a7b5bafb Revert "clean and rebuild FDroid"
This reverts commit 5fa080063c.
2018-01-11 09:00:29 -05:00
Kyle Spearrin
5fa080063c clean and rebuild FDroid 2018-01-11 08:52:47 -05:00
Kyle Spearrin
b3573f9482 choose/when fdroid conditional on packages 2018-01-11 08:36:37 -05:00
Kyle Spearrin
916b7ee46b reenc keystore 2018-01-10 23:26:44 -05:00
Kyle Spearrin
bfe8ad2034 quiet output 2018-01-10 23:00:10 -05:00
Kyle Spearrin
bb9db7bf9d full android project path 2018-01-10 22:36:51 -05:00
Kyle Spearrin
d7f7c8c568 build script fixes 2018-01-10 22:30:30 -05:00
Kyle Spearrin
10839588dd Invoke-Expression 2018-01-10 22:20:22 -05:00
Kyle Spearrin
12cd2b67cd ci build apks script 2018-01-10 22:10:32 -05:00
Kyle Spearrin
9a13036f4e fdroid-build script 2018-01-10 18:32:57 -05:00
Kyle Spearrin
2f025d51ff remove rdp from appveyor 2018-01-10 18:01:48 -05:00
Kyle Spearrin
6cb6d3a358 run nuget restore 2018-01-10 17:19:56 -05:00
Kyle Spearrin
0bb01d14bd clean fdroid 2018-01-10 16:53:09 -05:00
Kyle Spearrin
2229c4e4d1 enable rdp for appveyor debugging 2018-01-10 16:37:05 -05:00
Kyle Spearrin
5c90c62378 msbuild android proj only 2018-01-10 16:10:47 -05:00
Kyle Spearrin
b7ed0a29fe clean with msbuild 2018-01-10 15:55:07 -05:00
Kyle Spearrin
796c2ed58c build solution again for fdroid 2018-01-10 15:40:17 -05:00
Kyle Spearrin
39bd573d9d backup original csproj files and clean bin folders 2018-01-10 15:26:27 -05:00
Kyle Spearrin
d4aaa547a7 remove libs for fdroid build 2018-01-10 14:55:18 -05:00
Kyle Spearrin
f7e2382847 AndroidApkSigningAlgorithm of SHA1withRSA 2018-01-10 13:38:08 -05:00
Kyle Spearrin
4bb16e7d93 version bump 2018-01-10 12:18:48 -05:00
Kyle Spearrin
e7e00e4ebf add target framework to PropertyGroup conditional 2018-01-10 11:52:53 -05:00
Kyle Spearrin
55d050fca7 fdroid artifacts for build 2018-01-10 09:35:47 -05:00
Kyle Spearrin
98d4fef0ee fdroid builds without Google and Hockey services 2018-01-10 09:28:30 -05:00
Kyle Spearrin
5521892736 secure note option handled 2018-01-10 08:47:20 -05:00
Kyle Spearrin
8f0fd0dfef F-Droid build configuration 2018-01-10 00:41:29 -05:00
Kyle Spearrin
514eab0b98 Merge branch 'master' of github.com:bitwarden/mobile 2018-01-09 11:31:14 -05:00
Kyle Spearrin
e35c84245d added org.mozilla.klar to whitelist 2018-01-09 11:31:00 -05:00
Kyle Spearrin
4a2391eb1b New Crowdin translations (#247)
* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (French)

* New translations AppResources.resx (German)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Estonian)
2018-01-08 21:19:45 -05:00
Kyle Spearrin
04eb497e10 version bump 2018-01-08 21:17:05 -05:00
Kyle Spearrin
a9a5da6dc6 update ffimageloading lib 2018-01-08 11:51:23 -05:00
Kyle Spearrin
3f1aab27d6 android back on main pages goes to vault first 2018-01-08 11:33:51 -05:00
Kyle Spearrin
8f77df4ebb Don't animate loading alert 2018-01-08 09:10:58 -05:00
Alistair Francis
65a8b3fcd4 UWP.Images: Reduce the size of the camera icon (#245)
Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-05 16:33:34 -05:00
Alistair Francis
71dd4e512e App: Pages: Add a null check in OnSelectTemplate() (#243)
To avoid accessing a null poiter add a null check in OnSelectTemplate().

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-04 23:33:10 -05:00
Alistair Francis
ca03a5ecf4 App: Controls: Improve the vault view images (#240)
* App: Controls: Improve the vault view images

Make the buttons smaller and ensure the background is transparent.

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* UWP.Images: Use smaller size images

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* UWP.Images: Remove unused image

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-04 23:32:50 -05:00
Kyle Spearrin
694efb9508 unit FFImageLoading with fast renderer; TLS 1.2 2018-01-04 13:07:50 -05:00
Kyle Spearrin
c60a112039 update FFImageLoading and disable gifs on ios 2018-01-04 12:46:29 -05:00
Alistair Francis
c3570dd07a Improve the UWP toast notification colours (#239)
* UWP: Services: Improve the toast notifcation colours

This commit improves the toast notification colours and makes the
notification slightly transparent.

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* UWP: Services: Remove the unused Alignment options

These Alignment options don't have an effect on UWP, so just remove
them.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2018-01-04 08:32:18 -05:00
Kyle Spearrin
b680b190d4 update app store screenshots 2018-01-03 17:07:47 -05:00
Kyle Spearrin
310d51d859 handle null conditions from action sheet 2018-01-03 17:07:33 -05:00
Kyle Spearrin
cf9e820227 version bump 2018-01-03 14:15:45 -05:00
Kyle Spearrin
b91d2f4fb1 always use CustomTableViewModelRenderer 2018-01-03 13:37:04 -05:00
Kyle Spearrin
9456f5dc31 redraw stack layouts on ios tableviews 2018-01-03 12:18:15 -05:00
Kyle Spearrin
fa9e22730a get rid of old refection and memory services 2018-01-02 16:41:06 -05:00
1282 changed files with 83004 additions and 48089 deletions

3
.editorconfig Normal file
View File

@@ -0,0 +1,3 @@
# All files
[*]
guidelines = 120

63
.gitattributes vendored Normal file
View 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

3
.gitignore vendored
View File

@@ -197,4 +197,5 @@ FakesAssemblies/
# Other
project.lock.json
.DS_Store
.DS_Store
src/App/Css

1
CNAME Normal file
View File

@@ -0,0 +1 @@
mobileapp.bitwarden.com

View File

@@ -6,8 +6,8 @@ Code contributions are welcome! Please commit any pull requests against the `mas
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 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/mail/compose/kspearrin).
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/

5
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,5 @@
<!--
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
-->

View File

@@ -2,29 +2,30 @@
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-mobile/localized.svg)](https://crowdin.com/project/bitwarden-mobile)
[![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby)
# bitwarden mobile
# Bitwarden Mobile Application
<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://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>
<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.
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
<img src="https://i.imgur.com/Ty8wkSO.png" alt="" width="300" height="533" /> <img src="https://i.imgur.com/BYb4gVc.png" alt="" width="300" height="533" />
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android.png" alt="" width="300" height="533" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios.png" alt="" width="300" height="533" />
# Build/Run
**Requirements**
- [Visual Studio w/ Xamarin -or- Xamarin Studio](https://store.xamarin.com/)
- [Visual Studio](https://visualstudio.microsoft.com/)
- [Xamarin](https://docs.microsoft.com/en-us/xamarin/get-started/installation/?pivots=windows)
By default the app is targeting the production API. If you are running the [Core](https://github.com/bitwarden/core) API locally,
you'll need to switch the app to target your local instance. Open `src/App/Utilities/ApiHttpClient.cs` and `src/App/Utilities/IdentityHttpClient.cs` and set the `BaseAddress` to your local
API endpoints (ex. `new Uri("http://localhost:5000")`). Alternatively, you can also adjust the environment endpoints from the environment settings page on the home screen of the app (log out).
**Run the app**
After restoring the nuget packages, you can now build and 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. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file.

View File

@@ -1,4 +1,4 @@
bitwarden believes that working with security researchers across the globe is crucial to keeping our
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!
@@ -16,7 +16,7 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
# In-scope
- Security issues in any current release of bitwarden. This includes the web vault, browser extension,
- 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.
@@ -24,14 +24,14 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
The following bug classes are out-of scope:
- Bugs that are already reported on any of bitwarden's issue trackers (https://github.com/bitwarden),
- 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
- 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
@@ -39,7 +39,7 @@ 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
- 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!
Thank you for helping keep Bitwarden and our users safe!

View File

@@ -1,21 +1,143 @@
install:
- appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
before_build:
- nuget restore
- IF DEFINED keystore_dec_secret nuget install secure-file -ExcludeVersion
- IF DEFINED google_services_dec_secret secure-file\tools\secure-file -decrypt src\Android\google-services.json.enc -secret %google_services_dec_secret%
after_build:
- ps: IF($env:keystore_dec_secret) { .\src\Android\increment-version.ps1 $($env:APPVEYOR_BUILD_FOLDER) $($env:APPVEYOR_BUILD_NUMBER) }
- IF DEFINED keystore_dec_secret secure-file\tools\secure-file -decrypt src\Android\8bit.keystore.enc -secret %keystore_dec_secret%
- IF DEFINED keystore_password msbuild "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" "/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=%keystore_password%" "/p:AndroidSigningKeyStore=8bit.keystore" "/p:AndroidSigningStorePass=%keystore_password%" "src\Android\Android.csproj"
- ps: IF($env:keystore_dec_secret) { copy-item src\Android\bin\Release\com.x8bit.bitwarden-Signed.apk .\com.x8bit.bitwarden-$($env:APPVEYOR_BUILD_NUMBER).apk }
on_success:
- IF DEFINED play_dec_secret secure-file\tools\secure-file -decrypt store\google\Publisher\play_creds.json.enc -secret %play_dec_secret%
- IF DEFINED play_dec_secret dotnet store\google\Publisher\bin\Debug\netcoreapp2.0\Publisher.dll %APPVEYOR_BUILD_FOLDER%\store\google\Publisher\play_creds.json %APPVEYOR_BUILD_FOLDER%\src\Android\bin\Release\com.x8bit.bitwarden-Signed.apk alpha
artifacts:
- path: com.x8bit.bitwarden-%APPVEYOR_BUILD_NUMBER%.apk
image:
- Visual Studio 2017
- Ubuntu1804
branches:
except:
- l10n_master
skip_tags: true
image: Visual Studio 2017
- gh-pages
configuration: Release
stack: node 10
init:
- sh: |
if [ "${DEBUG_SSH}" == "true" ]
then
curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e -
fi
- ps: |
if($isWindows -and $env:DEBUG_RDP -eq "true") {
iex ((new-object net.webclient).DownloadString(`
'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
}
- ps: |
if($env:APPVEYOR_REPO_TAG -eq "true") {
$tagName = $env:APPVEYOR_REPO_TAG_NAME.TrimStart("v")
$env:RELEASE_NAME = "Version ${tagName}"
}
install:
- sh: |
curl -sflL 'https://raw.githubusercontent.com/appveyor/secure-file/master/install.sh' | bash -e -
./appveyor-tools/secure-file -decrypt ./store/fdroid/keystore.jks.enc -secret $FDROID_KEYSTORE_ENC_PASSWORD
- sh: npm install
- sh: |
sudo apt-get -qq update
sudo apt-get -qqy install --no-install-recommends fdroidserver wget
- sh: |
if [ "${APPVEYOR_REPO_TAG}" == "true" -a "${GH_TOKEN}" != "" ]
then
git config --global credential.helper store
echo "https://${GH_TOKEN}:x-oauth-basic@github.com" >> ~/.git-credentials
git config --global user.email "ci@bitwarden.com"
git config --global user.name "Bitwarden CI"
fi
- cmd: choco install cloc --no-progress
- cmd: "cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML"
#- cmd: appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
#- cmd: appveyor DownloadFile https://aka.ms/vs/15/release/vs_community.exe
#- cmd: vs_community.exe update --wait --quiet --norestart --installPath "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community"
#- cmd: ps: .\src\Android\update-android.ps1
before_build:
- ps: |
if($isWindows) {
nuget restore
if($env:KEYSTORE_DEC_SECRET -or $env:GOOGLE_SERVICES_DEC_SECRET -or $env:PLAY_DEC_SECRET) {
nuget install secure-file -ExcludeVersion
}
if($env:GOOGLE_SERVICES_DEC_SECRET) {
secure-file\tools\secure-file -decrypt src\Android\google-services.json.enc `
-secret $env:GOOGLE_SERVICES_DEC_SECRET
}
}
build_script:
- sh: |
if [ "${APPVEYOR_REPO_TAG}" == "true" ]
then
mkdir dist
cp CNAME ./dist
cd store
chmod 600 fdroid/config.py fdroid/keystore.jks
mkdir -p temp/fdroid
TEMP_DIR="$APPVEYOR_BUILD_FOLDER/store/temp/fdroid"
cd fdroid
echo "keypass=\"$FDROID_KEYSTORE_PASSWORD\"" >>config.py
echo "keystorepass=\"$FDROID_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/$APPVEYOR_REPO_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 $APPVEYOR_BUILD_FOLDER
fi
- ps: |
if($isWindows -and $env:KEYSTORE_DEC_SECRET) {
msbuild bitwarden-mobile.sln `
"/logger:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" `
"/p:Configuration=Release"
.\src\Android\ci-build-apks.ps1
Push-AppveyorArtifact .\com.x8bit.bitwarden.apk
Push-AppveyorArtifact .\com.x8bit.bitwarden-fdroid.apk
}
on_success:
- sh: |
if [ "${APPVEYOR_REPO_TAG}" == "true" -a "${GH_TOKEN}" != "" ]
then
npm run deploy
fi
- ps: |
if($isWindows -and $env:PLAY_DEC_SECRET) {
secure-file\tools\secure-file -decrypt store\google\Publisher\play_creds.json.enc -secret $env:PLAY_DEC_SECRET
cd store\google\Publisher\bin\Release\netcoreapp2.0
dotnet Publisher.dll `
$env:APPVEYOR_BUILD_FOLDER\store\google\Publisher\play_creds.json `
$env:APPVEYOR_BUILD_FOLDER\com.x8bit.bitwarden.apk `
alpha
cd $env:APPVEYOR_BUILD_FOLDER
}
on_finish:
- sh: |
if [ "${DEBUG_SSH}" == "true" ]
then
export APPVEYOR_SSH_BLOCK=true
curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e -
fi
- ps: |
if($isWindows -and $env:DEBUG_RDP -eq "true") {
$blockRdp = $true
iex ((new-object net.webclient).DownloadString(`
'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
}
deploy:
tag: $(APPVEYOR_REPO_TAG_NAME)
release: $(RELEASE_NAME)
provider: GitHub
auth_token: $(GH_TOKEN)
artifact: /.*/
force_update: true
on:
branch: master
APPVEYOR_REPO_TAG: true

View File

@@ -1,450 +1,306 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2003
VisualStudioVersion = 15.0.28307.539
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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EC730FD9-F623-4B6C-B503-95CDCFBCF277}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "test\Playground\Playground.csproj", "{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}"
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}") = "src", "src", "{D10CA4A9-F866-40E1-B658-F69051236C71}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}"
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}") = "test", "test", "{8904C536-C67D-420F-9971-51B26574C3AA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UWP", "src\UWP\UWP.csproj", "{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "UWP.Images", "src\UWP.Images\UWP.Images.shproj", "{0BE54BBB-7772-4289-BD51-1FDBB0CC2446}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{8A279EE4-4537-4656-9C93-44945E594556}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{D5D91152-CB01-4F24-A503-304D3A94408B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F0E2E596-C3DB-474A-9C88-7824662894FA}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
appveyor.yml = appveyor.yml
CONTRIBUTING.md = CONTRIBUTING.md
crowdin.yml = crowdin.yml
README.md = README.md
SECURITY.md = SECURITY.md
EndProjectSection
EndProject
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
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\UWP.Images\UWP.Images.projitems*{0be54bbb-7772-4289-bd51-1fdbb0cc2446}*SharedItemsImports = 13
src\UWP.Images\UWP.Images.projitems*{3a2d5669-ed71-4f2b-ba85-2d36baa05141}*SharedItemsImports = 4
EndGlobalSection
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|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|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
{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|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|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|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
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.ActiveCfg = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.Build.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.Deploy.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.Build.0 = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.Deploy.0 = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.ActiveCfg = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.Build.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.Deploy.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.Build.0 = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.Deploy.0 = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|Any CPU.ActiveCfg = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.ActiveCfg = Debug|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.Build.0 = Debug|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.Deploy.0 = Debug|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|iPhone.ActiveCfg = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.ActiveCfg = Debug|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.Build.0 = Debug|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.Deploy.0 = Debug|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.ActiveCfg = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.Build.0 = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.Deploy.0 = Debug|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|Any CPU.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.ActiveCfg = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.Build.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.Deploy.0 = Release|ARM
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|iPhone.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|iPhoneSimulator.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.ActiveCfg = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.Build.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.Deploy.0 = Release|x64
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.ActiveCfg = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.Build.0 = Release|x86
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.Deploy.0 = Release|x86
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|ARM.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|iPhone.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|x64.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|x64.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|x86.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.AppStore|x86.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|ARM.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|ARM.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|iPhone.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|x64.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|x64.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|x86.ActiveCfg = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Debug|x86.Build.0 = Debug|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|Any CPU.Build.0 = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|ARM.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|ARM.Build.0 = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|iPhone.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|iPhone.Build.0 = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|x64.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|x64.Build.0 = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|x86.ActiveCfg = Release|Any CPU
{8A279EE4-4537-4656-9C93-44945E594556}.Release|x86.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|ARM.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|iPhone.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|x64.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|x64.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|x86.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.AppStore|x86.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|ARM.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|ARM.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|iPhone.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|x64.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|x64.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|x86.ActiveCfg = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Debug|x86.Build.0 = Debug|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|Any CPU.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|ARM.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|ARM.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|iPhone.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|iPhone.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|x64.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|x64.Build.0 = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|x86.ActiveCfg = Release|Any CPU
{D5D91152-CB01-4F24-A503-304D3A94408B}.Release|x86.Build.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 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Deploy.0 = Debug|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 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.Build.0 = Debug|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 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = FDroid|Any CPU
{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|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{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|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
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}
{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}
{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}
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{0BE54BBB-7772-4289-BD51-1FDBB0CC2446} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{8A279EE4-4537-4656-9C93-44945E594556} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{D5D91152-CB01-4F24-A503-304D3A94408B} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
{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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {318CB2DF-0118-43A3-AC83-56BADCF71CCD}
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
EndGlobalSection
EndGlobal

View File

@@ -1,25 +1,31 @@
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
- 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
- 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

344
package-lock.json generated Normal file
View File

@@ -0,0 +1,344 @@
{
"name": "bitwarden-fdroid",
"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.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"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
View 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"
}
}

Binary file not shown.

View File

@@ -3,19 +3,16 @@ using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using System;
namespace Bit.Android
namespace Bit.Droid.Accessibility
{
[Activity(Theme = "@style/BitwardenTheme.Splash",
Label = "bitwarden",
Icon = "@drawable/icon",
WindowSoftInputMode = SoftInput.StateHidden)]
public class AutofillActivity : Activity
[Activity(Theme = "@style/LightTheme.Splash", WindowSoftInputMode = SoftInput.StateHidden)]
public class AccessibilityActivity : Activity
{
private DateTime? _lastLaunch = null;
private string _lastQueriedUri;
public static AutofillCredentials LastCredentials { get; set; }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
@@ -41,7 +38,6 @@ namespace Bit.Android
Finish();
return;
}
Intent.RemoveExtra("uri");
}
@@ -50,7 +46,7 @@ namespace Bit.Android
base.OnActivityResult(requestCode, resultCode, data);
if(data == null)
{
LastCredentials = null;
AccessibilityHelpers.LastCredentials = null;
}
else
{
@@ -58,15 +54,14 @@ namespace Bit.Android
{
if(data.GetStringExtra("canceled") != null)
{
LastCredentials = null;
AccessibilityHelpers.LastCredentials = null;
}
else
{
var uri = data.GetStringExtra("uri");
var username = data.GetStringExtra("username");
var password = data.GetStringExtra("password");
LastCredentials = new AutofillCredentials
AccessibilityHelpers.LastCredentials = new Credentials
{
Username = username,
Password = password,
@@ -77,10 +72,9 @@ namespace Bit.Android
}
catch
{
LastCredentials = null;
AccessibilityHelpers.LastCredentials = null;
}
}
Finish();
}
@@ -92,7 +86,13 @@ namespace Bit.Android
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))
{

View File

@@ -0,0 +1,246 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Android.OS;
using Android.Views.Accessibility;
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 Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
{
new Browser("com.android.chrome", "url_bar"),
new Browser("com.chrome.beta", "url_bar"),
new Browser("org.chromium.chrome", "url_bar"),
new Browser("com.android.browser", "url"),
new Browser("com.brave.browser", "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.touch", "addressbarEdit"),
new Browser("com.chrome.dev", "url_bar"),
new Browser("com.chrome.canary", "url_bar"),
new Browser("com.google.android.apps.chrome", "url_bar"),
new Browser("com.google.android.apps.chrome_dev", "url_bar"),
new Browser("org.codeaurora.swe.browser", "url_bar"),
new Browser("org.iron.srware", "url_bar"),
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.yandex.browser", "bro_omnibar_address_title_text",
(s) => s.Split(new char[]{' ', ' '}).FirstOrDefault()), // 0 = Regular Space, 1 = No-break space (00A0)
new Browser("org.mozilla.firefox", "url_bar_title"),
new Browser("org.mozilla.firefox_beta", "url_bar_title"),
new Browser("org.mozilla.fennec_aurora", "url_bar_title"),
new Browser("org.mozilla.focus", "display_url"),
new Browser("org.mozilla.klar", "display_url"),
new Browser("org.mozilla.fenix", "mozac_browser_toolbar_url_view"),
new Browser("org.mozilla.reference.browser", "mozac_browser_toolbar_url_view"),
new Browser("com.ghostery.android.ghostery", "search_field"),
new Browser("org.adblockplus.browser", "url_bar_title"),
new Browser("com.htc.sense.browser", "title"),
new Browser("com.amazon.cloud9", "url"),
new Browser("mobi.mgeek.TunnyBrowser", "title"),
new Browser("com.nubelacorp.javelin", "enterUrl"),
new Browser("com.jerky.browser2", "enterUrl"),
new Browser("com.mx.browser", "address_editor_with_progress"),
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
new Browser("com.linkbubble.playstore", "url_text"),
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
new Browser("acr.browser.lightning", "search"),
new Browser("acr.browser.barebones", "search"),
new Browser("com.microsoft.emmx", "url_bar"),
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
new Browser("mark.via.gp", "aw"),
new Browser("org.bromite.bromite", "url_bar"),
new Browser("com.kiwibrowser.browser", "url_bar"),
new Browser("com.ecosia.android", "url_bar"),
new Browser("com.qwant.liberty", "url_bar_title"),
}.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"
};
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 });
}
public static string GetUri(AccessibilityNodeInfo root)
{
var uri = string.Concat(Constants.AndroidAppProtocol, root.PackageName);
if(SupportedBrowsers.ContainsKey(root.PackageName))
{
var browser = SupportedBrowsers[root.PackageName];
var addressNode = root.FindAccessibilityNodeInfosByViewId(
$"{root.PackageName}:id/{browser.UriViewId}").FirstOrDefault();
if(addressNode != null)
{
uri = ExtractUri(uri, addressNode, browser);
addressNode.Dispose();
}
}
return uri;
}
public 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("."))
{
if(!uri.Contains("://") && !uri.Contains(" "))
{
uri = string.Concat("http://", uri);
}
else if(Build.VERSION.SdkInt <= BuildVersionCodes.KitkatWatch)
{
var parts = uri.Split(new string[] { ". " }, StringSplitOptions.None);
if(parts.Length > 1)
{
var urlPart = parts.FirstOrDefault(p => p.StartsWith("http"));
if(urlPart != null)
{
uri = urlPart.Trim();
}
}
}
}
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 < 50)
{
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(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?.Dispose();
}
return nodes;
}
public static void GetNodesAndFill(AccessibilityNodeInfo root, AccessibilityEvent e,
IEnumerable<AccessibilityNodeInfo> passwordNodes)
{
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = GetUsernameEditText(allEditTexts);
FillCredentials(usernameEditText, passwordNodes);
allEditTexts.Dispose();
usernameEditText = null;
}
public static AccessibilityNodeInfo GetUsernameEditText(IEnumerable<AccessibilityNodeInfo> allEditTexts)
{
return allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
}
}
}

View File

@@ -0,0 +1,310 @@
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.Accessibility;
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 NotificationChannel _notificationChannel;
private const int AutoFillNotificationId = 34573;
private const string BitwardenPackage = "com.x8bit.bitwarden";
private const string BitwardenWebsite = "vault.bitwarden.com";
private IStorageService _storageService;
private bool _settingAutofillPasswordField;
private bool _settingAutofillPersistNotification;
private DateTime? _lastSettingsReload = null;
private TimeSpan _settingsReloadSpan = TimeSpan.FromMinutes(1);
private long _lastNotificationTime = 0;
private string _lastNotificationUri = null;
private HashSet<string> _launcherPackageNames = null;
private DateTime? _lastLauncherSetBuilt = null;
private TimeSpan _rebuildLauncherSpan = TimeSpan.FromHours(1);
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))
{
return;
}
var root = RootInActiveWindow;
if(root == null || root.PackageName != e.PackageName)
{
return;
}
// AccessibilityHelpers.PrintTestData(root, e);
LoadServices();
var settingsTask = LoadSettingsAsync();
var notificationManager = GetSystemService(NotificationService) as NotificationManager;
var cancelNotification = true;
switch(e.EventType)
{
case EventTypes.ViewFocused:
if(e.Source == null || !e.Source.Password || !_settingAutofillPasswordField)
{
break;
}
if(e.PackageName == BitwardenPackage)
{
CancelNotification(notificationManager);
break;
}
if(ScanAndAutofill(root, e, notificationManager, cancelNotification))
{
CancelNotification(notificationManager);
}
break;
case EventTypes.WindowContentChanged:
case EventTypes.WindowStateChanged:
if(_settingAutofillPasswordField && e.Source.Password)
{
break;
}
else if(_settingAutofillPasswordField && AccessibilityHelpers.LastCredentials == null)
{
if(string.IsNullOrWhiteSpace(_lastNotificationUri))
{
CancelNotification(notificationManager);
break;
}
var uri = AccessibilityHelpers.GetUri(root);
if(uri != _lastNotificationUri)
{
CancelNotification(notificationManager);
}
else if(uri.StartsWith(Constants.AndroidAppProtocol))
{
CancelNotification(notificationManager, 30000);
}
break;
}
if(e.PackageName == BitwardenPackage)
{
CancelNotification(notificationManager);
break;
}
if(_settingAutofillPersistNotification)
{
var uri = AccessibilityHelpers.GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
var needToFill = AccessibilityHelpers.NeedToAutofill(
AccessibilityHelpers.LastCredentials, uri);
if(needToFill)
{
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e,
n => n.Password, false);
needToFill = passwordNodes.Any();
if(needToFill)
{
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
}
passwordNodes.Dispose();
}
if(!needToFill)
{
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}
AccessibilityHelpers.LastCredentials = null;
}
else
{
cancelNotification = ScanAndAutofill(root, e, notificationManager, cancelNotification);
}
if(cancelNotification)
{
CancelNotification(notificationManager);
}
break;
default:
break;
}
notificationManager?.Dispose();
root.Dispose();
e.Dispose();
}
// Suppress exceptions so that service doesn't crash.
catch { }
}
public override void OnInterrupt()
{
// Do nothing.
}
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e,
NotificationManager notificationManager, bool cancelNotification)
{
var passwordNodes = AccessibilityHelpers.GetWindowNodes(root, e, n => n.Password, false);
if(passwordNodes.Count > 0)
{
var uri = AccessibilityHelpers.GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
if(AccessibilityHelpers.NeedToAutofill(AccessibilityHelpers.LastCredentials, uri))
{
AccessibilityHelpers.GetNodesAndFill(root, e, passwordNodes);
}
else
{
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}
AccessibilityHelpers.LastCredentials = null;
}
else if(AccessibilityHelpers.LastCredentials != null)
{
Task.Run(async () =>
{
await Task.Delay(1000);
AccessibilityHelpers.LastCredentials = null;
});
}
passwordNodes.Dispose();
return cancelNotification;
}
public void CancelNotification(NotificationManager notificationManager, long limit = 250)
{
if(Java.Lang.JavaSystem.CurrentTimeMillis() - _lastNotificationTime < limit)
{
return;
}
_lastNotificationUri = null;
notificationManager?.Cancel(AutoFillNotificationId);
}
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
{
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
{
return;
}
var now = Java.Lang.JavaSystem.CurrentTimeMillis();
var intent = new Intent(this, typeof(AccessibilityActivity));
intent.PutExtra("uri", uri);
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
var notificationContent = Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch ?
AppResources.BitwardenAutofillServiceNotificationContent :
AppResources.BitwardenAutofillServiceNotificationContentOld;
var builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.shield)
.SetContentTitle(AppResources.BitwardenAutofillService)
.SetContentText(notificationContent)
.SetTicker(notificationContent)
.SetWhen(now)
.SetContentIntent(pendingIntent);
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch)
{
builder.SetVisibility(NotificationVisibility.Secret)
.SetColor(Android.Support.V4.Content.ContextCompat.GetColor(ApplicationContext,
Resource.Color.primary));
}
if(Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
if(_notificationChannel == null)
{
_notificationChannel = new NotificationChannel("bitwarden_autofill_service",
AppResources.AutofillService, NotificationImportance.Low);
notificationManager.CreateNotificationChannel(_notificationChannel);
}
builder.SetChannelId(_notificationChannel.Id);
}
if(/*Build.VERSION.SdkInt <= BuildVersionCodes.N && */_settingAutofillPersistNotification)
{
builder.SetPriority(-2);
}
_lastNotificationTime = now;
_lastNotificationUri = uri;
notificationManager.Notify(AutoFillNotificationId, builder.Build());
builder.Dispose();
}
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");
}
}
private async Task LoadSettingsAsync()
{
var now = DateTime.UtcNow;
if(_lastSettingsReload == null || (now - _lastSettingsReload.Value) > _settingsReloadSpan)
{
_lastSettingsReload = now;
_settingAutofillPasswordField = await _storageService.GetAsync<bool>(
Constants.AccessibilityAutofillPasswordFieldKey);
_settingAutofillPersistNotification = await _storageService.GetAsync<bool>(
Constants.AccessibilityAutofillPersistNotificationKey);
}
}
}
}

View 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;
}
}

View File

@@ -1,6 +1,6 @@
namespace Bit.Android
namespace Bit.Droid.Accessibility
{
public class AutofillCredentials
public class Credentials
{
public string Username { get; set; }
public string Password { get; set; }

View File

@@ -0,0 +1,17 @@
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.Dispose();
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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");

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,68 +1,111 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using Android.Content;
using Android.Service.Autofill;
using Android.Widget;
using System.Linq;
using Android.App;
using Bit.App.Abstractions;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Enums;
using Bit.Core.Enums;
using Android.Views.Autofill;
using Bit.Core.Abstractions;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
public static class AutofillHelpers
{
private static int _pendingIntentId = 0;
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService service)
// These browser work natively with the autofill framework
public static HashSet<string> TrustedBrowsers = new HashSet<string>
{
var items = new List<FilledItem>();
"org.mozilla.focus",
"org.mozilla.klar",
"com.duckduckgo.mobile.android",
};
// These browsers work using the compatibility shim for the autofill framework
public static HashSet<string> CompatBrowsers = new HashSet<string>
{
"org.mozilla.firefox",
"org.mozilla.firefox_beta",
"com.microsoft.emmx",
"com.android.chrome",
"com.chrome.beta",
"com.android.browser",
"com.brave.browser",
"com.opera.browser",
"com.opera.browser.beta",
"com.opera.mini.native",
"com.chrome.dev",
"com.chrome.canary",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
"com.yandex.browser",
"com.sec.android.app.sbrowser",
"com.sec.android.app.sbrowser.beta",
"org.codeaurora.swe.browser",
"com.amazon.cloud9",
"mark.via.gp",
"org.bromite.bromite",
"org.chromium.chrome",
"com.kiwibrowser.browser",
"com.ecosia.android",
"com.opera.mini.native.beta",
"org.mozilla.fennec_aurora",
"com.qwant.liberty",
"com.opera.touch",
"org.mozilla.fenix",
"org.mozilla.reference.browser",
"org.mozilla.rocket",
};
// The URLs are blacklisted from autofilling
public static HashSet<string> BlacklistedUris = new HashSet<string>
{
"androidapp://android",
"androidapp://com.x8bit.bitwarden",
"androidapp://com.oneplus.applocker",
"androidapp://com.android.settings",
};
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService cipherService)
{
if(parser.FieldCollection.FillableForLogin)
{
var ciphers = await service.GetAllAsync(parser.Uri);
var ciphers = await cipherService.GetAllDecryptedByUrlAsync(parser.Uri);
if(ciphers.Item1.Any() || ciphers.Item2.Any())
{
var allCiphers = ciphers.Item1.ToList();
allCiphers.AddRange(ciphers.Item2.ToList());
foreach(var cipher in allCiphers)
{
items.Add(new FilledItem(cipher));
}
return allCiphers.Select(c => new FilledItem(c)).ToList();
}
}
else if(parser.FieldCollection.FillableForCard)
{
var ciphers = await service.GetAllAsync();
foreach(var cipher in ciphers.Where(c => c.Type == CipherType.Card))
{
items.Add(new FilledItem(cipher));
}
var ciphers = await cipherService.GetAllDecryptedAsync();
return ciphers.Where(c => c.Type == CipherType.Card).Select(c => new FilledItem(c)).ToList();
}
return items;
return new List<FilledItem>();
}
public static FillResponse BuildFillResponse(Context context, Parser parser, List<FilledItem> items, bool locked)
public static FillResponse BuildFillResponse(Parser parser, List<FilledItem> items, bool locked)
{
var responseBuilder = new FillResponse.Builder();
if(items != null && items.Count > 0)
{
foreach(var item in items)
{
var dataset = BuildDataset(context, parser.FieldCollection, item);
var dataset = BuildDataset(parser.ApplicationContext, parser.FieldCollection, item);
if(dataset != null)
{
responseBuilder.AddDataset(dataset);
}
}
}
responseBuilder.AddDataset(BuildVaultDataset(context, parser.FieldCollection, parser.Uri, locked));
AddSaveInfo(responseBuilder, parser.FieldCollection);
responseBuilder.AddDataset(BuildVaultDataset(parser.ApplicationContext, parser.FieldCollection,
parser.Uri, locked));
AddSaveInfo(parser, responseBuilder, parser.FieldCollection);
responseBuilder.SetIgnoredIds(parser.FieldCollection.IgnoreAutofillIds.ToArray());
return responseBuilder.Build();
}
@@ -70,7 +113,7 @@ namespace Bit.Android.Autofill
public static Dataset BuildDataset(Context context, FieldCollection fields, FilledItem filledItem)
{
var datasetBuilder = new Dataset.Builder(
BuildListView(context.PackageName, filledItem.Name, filledItem.Subtitle, filledItem.Icon));
BuildListView(filledItem.Name, filledItem.Subtitle, filledItem.Icon, context));
if(filledItem.ApplyToFields(fields, datasetBuilder))
{
return datasetBuilder.Build();
@@ -102,8 +145,11 @@ namespace Bit.Android.Autofill
var pendingIntent = PendingIntent.GetActivity(context, ++_pendingIntentId, intent,
PendingIntentFlags.CancelCurrent);
var view = BuildListView(context.PackageName, AppResources.AutofillWithBitwarden,
locked ? AppResources.VaultIsLocked : AppResources.GoToMyVault, Resource.Drawable.icon);
var view = BuildListView(
AppResources.AutofillWithBitwarden,
locked ? AppResources.VaultIsLocked : AppResources.GoToMyVault,
Resource.Drawable.icon,
context);
var datasetBuilder = new Dataset.Builder(view);
datasetBuilder.SetAuthentication(pendingIntent.IntentSender);
@@ -113,21 +159,29 @@ namespace Bit.Android.Autofill
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
}
return datasetBuilder.Build();
}
public static RemoteViews BuildListView(string packageName, string text, string subtext, int iconId)
public static RemoteViews BuildListView(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.text, text);
view.SetTextViewText(Resource.Id.text1, text);
view.SetTextViewText(Resource.Id.text2, subtext);
view.SetImageViewResource(Resource.Id.icon, iconId);
return view;
}
public static void AddSaveInfo(FillResponse.Builder responseBuilder, FieldCollection fields)
public static void AddSaveInfo(Parser parser, FillResponse.Builder responseBuilder, FieldCollection fields)
{
// Docs state that password fields cannot be reliably saved in Compat mode since they will show as
// masked values.
var compatBrowser = CompatBrowsers.Contains(parser.PackageName);
if(compatBrowser && fields.SaveType == SaveDataType.Password)
{
return;
}
var requiredIds = fields.GetRequiredSaveFields();
if(fields.SaveType == SaveDataType.Generic || requiredIds.Length == 0)
{
@@ -140,7 +194,11 @@ namespace Bit.Android.Autofill
{
saveBuilder.SetOptionalIds(optionalIds);
}
if(compatBrowser)
{
saveBuilder.SetFlags(SaveFlags.SaveOnAllViewsInvisible);
}
responseBuilder.SetSaveInfo(saveBuilder.Build());
}
}
}
}

View File

@@ -5,25 +5,27 @@ using Android.OS;
using Android.Runtime;
using Android.Service.Autofill;
using Android.Widget;
using Bit.App;
using Bit.App.Abstractions;
using Bit.App.Enums;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Linq;
using XLabs.Ioc;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
[Service(Permission = Manifest.Permission.BindAutofillService, Label = "bitwarden")]
[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 : global::Android.Service.Autofill.AutofillService
public class AutofillService : Android.Service.Autofill.AutofillService
{
private ICipherService _cipherService;
private ILockService _lockService;
private IStorageService _storageService;
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback)
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
FillCallback callback)
{
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if(structure == null)
@@ -31,38 +33,42 @@ namespace Bit.Android.Autofill
return;
}
var parser = new Parser(structure);
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
if(string.IsNullOrWhiteSpace(parser.Uri) || parser.Uri == "androidapp://com.x8bit.bitwarden" ||
parser.Uri == "androidapp://android" || !parser.FieldCollection.Fillable)
if(_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var shouldAutofill = await parser.ShouldAutofillAsync(_storageService);
if(!shouldAutofill)
{
return;
}
if(_lockService == null)
{
_lockService = Resolver.Resolve<ILockService>();
_lockService = ServiceContainer.Resolve<ILockService>("lockService");
}
List<FilledItem> items = null;
var locked = (await _lockService.GetLockTypeAsync(false)) != LockType.None;
var locked = await _lockService.IsLockedAsync();
if(!locked)
{
if(_cipherService == null)
{
_cipherService = Resolver.Resolve<ICipherService>();
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
}
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService);
}
// build response
var response = AutofillHelpers.BuildFillResponse(this, parser, items, locked);
var response = AutofillHelpers.BuildFillResponse(parser, items, locked);
callback.OnSuccess(response);
}
public override void OnSaveRequest(SaveRequest request, SaveCallback callback)
public async override void OnSaveRequest(SaveRequest request, SaveCallback callback)
{
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if(structure == null)
@@ -70,7 +76,18 @@ namespace Bit.Android.Autofill
return;
}
var parser = new Parser(structure);
if(_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var disableSavePrompt = await _storageService.GetAsync<bool?>(Constants.AutofillDisableSavePromptKey);
if(disableSavePrompt.GetValueOrDefault())
{
return;
}
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
var savedItem = parser.FieldCollection.GetSavedItem();

View File

@@ -7,7 +7,7 @@ using static Android.App.Assist.AssistStructure;
using Android.Text;
using static Android.Views.ViewStructure;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
public class Field
{
@@ -16,6 +16,7 @@ namespace Bit.Android.Autofill
public Field(ViewNode node)
{
Id = node.Id;
TrackingId = $"{node.Id}_{node.GetHashCode()}";
IdEntry = node.IdEntry;
AutofillId = node.AutofillId;
AutofillType = node.AutofillType;
@@ -68,6 +69,7 @@ namespace Bit.Android.Autofill
}
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; }
@@ -84,6 +86,69 @@ namespace Bit.Android.Autofill
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;
@@ -126,72 +191,5 @@ namespace Bit.Android.Autofill
}
}
}
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;
}
}
}
}

View File

@@ -5,14 +5,15 @@ using System.Linq;
using Android.Text;
using Android.Views;
namespace Bit.Android.Autofill
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 HashSet<int> Ids { get; private set; } = new HashSet<int>();
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
public SaveDataType SaveType
{
@@ -32,9 +33,8 @@ namespace Bit.Android.Autofill
}
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<int, Field> IdToFieldMap { get; private set; } =
new Dictionary<int, 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>();
@@ -47,7 +47,6 @@ namespace Bit.Android.Autofill
{
return _passwordFields;
}
if(Hints.Any())
{
_passwordFields = new List<Field>();
@@ -58,24 +57,12 @@ namespace Bit.Android.Autofill
}
else
{
_passwordFields = Fields
.Where(f =>
(!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
(!f.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
(
f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
f.InputType.HasFlag(InputTypes.TextVariationWebPassword)
)
).ToList();
_passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
if(!_passwordFields.Any())
{
_passwordFields = Fields.Where(f =>
(f.IdEntry?.ToLowerInvariant().Contains("password") ?? false)
|| (f.Hint?.ToLowerInvariant().Contains("password") ?? false)).ToList();
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
}
}
return _passwordFields;
}
}
@@ -88,7 +75,6 @@ namespace Bit.Android.Autofill
{
return _usernameFields;
}
_usernameFields = new List<Field>();
if(Hints.Any())
{
@@ -105,45 +91,49 @@ namespace Bit.Android.Autofill
{
foreach(var passwordField in PasswordFields)
{
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
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 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(Ids.Contains(field.Id))
if(field == null || FieldTrackingIds.Contains(field.TrackingId))
{
return;
}
_passwordFields = _usernameFields = null;
if(field.Id > -1)
{
Ids.Add(field.Id);
IdToFieldMap.Add(field.Id, field);
}
FieldTrackingIds.Add(field.TrackingId);
Fields.Add(field);
AutofillIds.Add(field.AutofillId);
@@ -156,12 +146,10 @@ namespace Bit.Android.Autofill
{
FocusedHints.Add(hint);
}
if(!HintToFieldsMap.ContainsKey(hint))
{
HintToFieldsMap.Add(hint, new List<Field>());
}
HintToFieldsMap[hint].Add(field);
}
}
@@ -179,7 +167,7 @@ namespace Bit.Android.Autofill
var savedItem = new SavedItem
{
Type = App.Enums.CipherType.Login,
Type = Core.Enums.CipherType.Login,
Login = new SavedItem.LoginItem
{
Password = GetFieldValue(passwordField)
@@ -188,14 +176,13 @@ namespace Bit.Android.Autofill
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 = App.Enums.CipherType.Card,
Type = Core.Enums.CipherType.Card,
Card = new SavedItem.CardItem
{
Number = GetFieldValue(View.AutofillHintCreditCardNumber),
@@ -205,10 +192,8 @@ namespace Bit.Android.Autofill
Code = GetFieldValue(View.AutofillHintCreditCardSecurityCode)
}
};
return savedItem;
}
return null;
}
@@ -239,7 +224,6 @@ namespace Bit.Android.Autofill
}
return fieldList.Select(f => f.AutofillId).ToArray();
}
return new AutofillId[0];
}
@@ -253,7 +237,6 @@ namespace Bit.Android.Autofill
{
return HintToFieldsMap[View.AutofillHintCreditCardNumber].Select(f => f.AutofillId).ToArray();
}
return new AutofillId[0];
}
@@ -275,7 +258,6 @@ namespace Bit.Android.Autofill
}
}
}
return null;
}
@@ -285,7 +267,6 @@ namespace Bit.Android.Autofill
{
return null;
}
if(!string.IsNullOrWhiteSpace(field.TextValue))
{
if(field.AutofillType == AutofillType.List && field.ListValue.HasValue && monthValue)
@@ -309,8 +290,53 @@ namespace Bit.Android.Autofill
{
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));
}
}
}

View File

@@ -1,107 +1,56 @@
using System;
using Android.Service.Autofill;
using Android.Service.Autofill;
using Android.Views.Autofill;
using System.Linq;
using Bit.App.Models;
using Bit.App.Enums;
using Bit.Core.Enums;
using Android.Views;
using Bit.Core.Models.View;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
public class FilledItem
{
private Lazy<string> _password;
private Lazy<string> _cardName;
private string _password;
private string _cardName;
private string _cardNumber;
private Lazy<string> _cardExpMonth;
private Lazy<string> _cardExpYear;
private Lazy<string> _cardCode;
private Lazy<string> _idPhone;
private Lazy<string> _idEmail;
private Lazy<string> _idUsername;
private Lazy<string> _idAddress;
private Lazy<string> _idPostalCode;
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(Cipher cipher)
public FilledItem(CipherView cipher)
{
Name = cipher.Name?.Decrypt(cipher.OrganizationId) ?? "--";
Name = cipher.Name;
Type = cipher.Type;
Subtitle = cipher.SubTitle;
switch(Type)
{
case CipherType.Login:
Subtitle = cipher.Login.Username?.Decrypt(cipher.OrganizationId) ?? string.Empty;
Icon = Resource.Drawable.login;
_password = new Lazy<string>(() => cipher.Login.Password?.Decrypt(cipher.OrganizationId));
_password = cipher.Login.Password;
break;
case CipherType.Card:
Subtitle = cipher.Card.Brand?.Decrypt(cipher.OrganizationId);
_cardNumber = cipher.Card.Number?.Decrypt(cipher.OrganizationId);
if(!string.IsNullOrWhiteSpace(_cardNumber) && _cardNumber.Length >= 4)
{
if(!string.IsNullOrWhiteSpace(_cardNumber))
{
Subtitle += ", ";
}
Subtitle += ("*" + _cardNumber.Substring(_cardNumber.Length - 4));
}
_cardNumber = cipher.Card.Number;
Icon = Resource.Drawable.card;
_cardName = new Lazy<string>(() => cipher.Card.CardholderName?.Decrypt(cipher.OrganizationId));
_cardCode = new Lazy<string>(() => cipher.Card.Code?.Decrypt(cipher.OrganizationId));
_cardExpMonth = new Lazy<string>(() => cipher.Card.ExpMonth?.Decrypt(cipher.OrganizationId));
_cardExpYear = new Lazy<string>(() => cipher.Card.ExpYear?.Decrypt(cipher.OrganizationId));
_cardName = cipher.Card.CardholderName;
_cardCode = cipher.Card.Code;
_cardExpMonth = cipher.Card.ExpMonth;
_cardExpYear = cipher.Card.ExpYear;
break;
case CipherType.Identity:
var firstName = cipher.Identity?.FirstName?.Decrypt(cipher.OrganizationId) ?? " ";
var lastName = cipher.Identity?.LastName?.Decrypt(cipher.OrganizationId) ?? " ";
Subtitle = " ";
if(!string.IsNullOrWhiteSpace(firstName))
{
Subtitle = firstName;
}
if(!string.IsNullOrWhiteSpace(lastName))
{
if(!string.IsNullOrWhiteSpace(Subtitle))
{
Subtitle += " ";
}
Subtitle += lastName;
}
Icon = Resource.Drawable.id;
_idPhone = new Lazy<string>(() => cipher.Identity.Phone?.Decrypt(cipher.OrganizationId));
_idEmail = new Lazy<string>(() => cipher.Identity.Email?.Decrypt(cipher.OrganizationId));
_idUsername = new Lazy<string>(() => cipher.Identity.Username?.Decrypt(cipher.OrganizationId));
_idAddress = new Lazy<string>(() =>
{
var address = cipher.Identity.Address1?.Decrypt(cipher.OrganizationId);
var address2 = cipher.Identity.Address2?.Decrypt(cipher.OrganizationId);
if(!string.IsNullOrWhiteSpace(address2))
{
if(!string.IsNullOrWhiteSpace(address))
{
address += ", ";
}
address += address2;
}
var address3 = cipher.Identity.Address3?.Decrypt(cipher.OrganizationId);
if(!string.IsNullOrWhiteSpace(address3))
{
if(!string.IsNullOrWhiteSpace(address))
{
address += ", ";
}
address += address3;
}
return address;
});
_idPostalCode = new Lazy<string>(() => cipher.Identity.PostalCode?.Decrypt(cipher.OrganizationId));
_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;
}
}
@@ -121,11 +70,11 @@ namespace Bit.Android.Autofill
var setValues = false;
if(Type == CipherType.Login)
{
if(fieldCollection.PasswordFields.Any() && !string.IsNullOrWhiteSpace(_password.Value))
if(fieldCollection.PasswordFields.Any() && !string.IsNullOrWhiteSpace(_password))
{
foreach(var f in fieldCollection.PasswordFields)
{
var val = ApplyValue(f, _password.Value);
var val = ApplyValue(f, _password);
if(val != null)
{
setValues = true;
@@ -133,7 +82,6 @@ namespace Bit.Android.Autofill
}
}
}
if(fieldCollection.UsernameFields.Any() && !string.IsNullOrWhiteSpace(Subtitle))
{
foreach(var f in fieldCollection.UsernameFields)
@@ -149,68 +97,73 @@ namespace Bit.Android.Autofill
}
else if(Type == CipherType.Card)
{
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardNumber,
new Lazy<string>(() => _cardNumber)))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardNumber,
_cardNumber))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardSecurityCode, _cardCode))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardSecurityCode,
_cardCode))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardExpirationMonth, _cardExpMonth, true))
if(ApplyValue(datasetBuilder, fieldCollection,
Android.Views.View.AutofillHintCreditCardExpirationMonth, _cardExpMonth, true))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardExpirationYear, _cardExpYear))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintCreditCardExpirationYear,
_cardExpYear))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintName, _cardName))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintName, _cardName))
{
setValues = true;
}
}
else if(Type == CipherType.Identity)
{
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPhone, _idPhone))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPhone, _idPhone))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintEmailAddress, _idEmail))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintEmailAddress, _idEmail))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintUsername, _idUsername))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintUsername,
_idUsername))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPostalAddress, _idAddress))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPostalAddress,
_idAddress))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPostalCode, _idPostalCode))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintPostalCode,
_idPostalCode))
{
setValues = true;
}
if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintName, new Lazy<string>(() => Subtitle)))
if(ApplyValue(datasetBuilder, fieldCollection, Android.Views.View.AutofillHintName, Subtitle))
{
setValues = true;
}
}
return setValues;
}
private static bool ApplyValue(Dataset.Builder builder, FieldCollection fieldCollection,
string hint, Lazy<string> value, bool monthValue = false)
string hint, string value, bool monthValue = false)
{
bool setValues = false;
if(fieldCollection.HintToFieldsMap.ContainsKey(hint) && !string.IsNullOrWhiteSpace(value.Value))
if(fieldCollection.HintToFieldsMap.ContainsKey(hint) && !string.IsNullOrWhiteSpace(value))
{
foreach(var f in fieldCollection.HintToFieldsMap[hint])
{
var val = ApplyValue(f, value.Value, monthValue);
var val = ApplyValue(f, value, monthValue);
if(val != null)
{
setValues = true;
@@ -245,7 +198,6 @@ namespace Bit.Android.Autofill
return AutofillValue.ForList(monthIndex - 1);
}
}
for(var i = 0; i < field.AutofillOptions.Count; i++)
{
if(field.AutofillOptions[i].Equals(value))
@@ -266,7 +218,6 @@ namespace Bit.Android.Autofill
default:
break;
}
return null;
}
}

View File

@@ -1,33 +1,33 @@
using static Android.App.Assist.AssistStructure;
using Android.App.Assist;
using Bit.App;
using System.Collections.Generic;
using Bit.Core;
using Android.Content;
using Bit.Core.Abstractions;
using System.Threading.Tasks;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
public class Parser
{
public static HashSet<string> TrustedBrowsers = new HashSet<string>
public static HashSet<string> _excludedPackageIds = new HashSet<string>
{
"org.mozilla.focus","org.mozilla.firefox","org.mozilla.firefox_beta","com.microsoft.emmx",
"com.android.chrome","com.chrome.beta","com.android.browser","com.brave.browser","com.opera.browser",
"com.opera.browser.beta","com.opera.mini.native","com.chrome.dev","com.chrome.canary",
"com.google.android.apps.chrome","com.google.android.apps.chrome_dev","com.yandex.browser",
"com.sec.android.app.sbrowser","com.sec.android.app.sbrowser.beta","org.codeaurora.swe.browser",
"com.amazon.cloud9"
"android"
};
private readonly AssistStructure _structure;
private string _uri;
private string _packageName;
private string _webDomain;
public Parser(AssistStructure structure)
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
@@ -36,12 +36,12 @@ namespace Bit.Android.Autofill
{
return _uri;
}
if(string.IsNullOrWhiteSpace(WebDomain) && string.IsNullOrWhiteSpace(PackageName))
var webDomainNull = string.IsNullOrWhiteSpace(WebDomain);
if(webDomainNull && string.IsNullOrWhiteSpace(PackageName))
{
_uri = null;
}
else if(!string.IsNullOrWhiteSpace(WebDomain))
else if(!webDomainNull)
{
_uri = string.Concat("http://", WebDomain);
}
@@ -49,10 +49,10 @@ namespace Bit.Android.Autofill
{
_uri = string.Concat(Constants.AndroidAppProtocol, PackageName);
}
return _uri;
}
}
public string PackageName
{
get => _packageName;
@@ -62,10 +62,10 @@ namespace Bit.Android.Autofill
{
_packageName = _uri = null;
}
_packageName = value;
}
}
public string WebDomain
{
get => _webDomain;
@@ -75,11 +75,25 @@ namespace Bit.Android.Autofill
{
_webDomain = _uri = null;
}
_webDomain = 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()
{
for(var i = 0; i < _structure.WindowNodeCount; i++)
@@ -87,32 +101,24 @@ namespace Bit.Android.Autofill
var node = _structure.GetWindowNodeAt(i);
ParseNode(node.RootViewNode);
}
if(!AutofillHelpers.TrustedBrowsers.Contains(PackageName) &&
!AutofillHelpers.CompatBrowsers.Contains(PackageName))
{
WebDomain = 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)
{
if(PackageName == null)
{
PackageName = node.IdPackage;
}
if(WebDomain == null && TrustedBrowsers.Contains(node.IdPackage))
{
WebDomain = node.WebDomain;
}
FieldCollection.Add(new Field(node));
}
else
{
if(WebDomain == null && TrustedBrowsers.Contains(node.IdPackage))
{
WebDomain = node.WebDomain;
}
FieldCollection.IgnoreAutofillIds.Add(node.AutofillId);
}
@@ -121,5 +127,18 @@ namespace Bit.Android.Autofill
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(WebDomain) && !string.IsNullOrWhiteSpace(node.WebDomain))
{
WebDomain = node.WebDomain;
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
using Bit.App.Enums;
using Bit.Core.Enums;
namespace Bit.Android.Autofill
namespace Bit.Droid.Autofill
{
public class SavedItem
{

View File

@@ -1,473 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Android.AccessibilityServices;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Views.Accessibility;
using Bit.App.Abstractions;
using XLabs.Ioc;
using Bit.App.Resources;
namespace Bit.Android
{
[Service(Permission = global::Android.Manifest.Permission.BindAccessibilityService, Label = "bitwarden")]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
public class AutofillService : AccessibilityService
{
private NotificationChannel _notificationChannel;
private const int AutoFillNotificationId = 34573;
private const string SystemUiPackage = "com.android.systemui";
private const string BitwardenPackage = "com.x8bit.bitwarden";
private const string BitwardenWebsite = "bitwarden.com";
private static Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
{
new Browser("com.android.chrome", "url_bar"),
new Browser("com.chrome.beta", "url_bar"),
new Browser("com.android.browser", "url"),
new Browser("com.brave.browser", "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.chrome.dev", "url_bar"),
new Browser("com.chrome.canary", "url_bar"),
new Browser("com.google.android.apps.chrome", "url_bar"),
new Browser("com.google.android.apps.chrome_dev", "url_bar"),
new Browser("org.codeaurora.swe.browser", "url_bar"),
new Browser("org.iron.srware", "url_bar"),
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.yandex.browser", "bro_omnibar_address_title_text",
(s) => s.Split(' ').FirstOrDefault()),
new Browser("org.mozilla.firefox", "url_bar_title"),
new Browser("org.mozilla.firefox_beta", "url_bar_title"),
new Browser("org.mozilla.focus", "display_url"),
new Browser("com.ghostery.android.ghostery", "search_field"),
new Browser("org.adblockplus.browser", "url_bar_title"),
new Browser("com.htc.sense.browser", "title"),
new Browser("com.amazon.cloud9", "url"),
new Browser("mobi.mgeek.TunnyBrowser", "title"),
new Browser("com.nubelacorp.javelin", "enterUrl"),
new Browser("com.jerky.browser2", "enterUrl"),
new Browser("com.mx.browser", "address_editor_with_progress"),
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
new Browser("com.linkbubble.playstore", "url_text"),
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
new Browser("acr.browser.lightning", "search"),
new Browser("acr.browser.barebones", "search"),
new Browser("com.microsoft.emmx", "url_bar")
}.ToDictionary(n => n.PackageName);
private readonly IAppSettingsService _appSettings;
private long _lastNotificationTime = 0;
private string _lastNotificationUri = null;
public AutofillService()
{
_appSettings = Resolver.Resolve<IAppSettingsService>();
}
public override void OnAccessibilityEvent(AccessibilityEvent e)
{
var powerManager = (PowerManager)GetSystemService(PowerService);
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch && !powerManager.IsInteractive)
{
return;
}
else if(Build.VERSION.SdkInt < BuildVersionCodes.Lollipop && !powerManager.IsScreenOn)
{
return;
}
try
{
var root = RootInActiveWindow;
if(e == null || root == null || string.IsNullOrWhiteSpace(e.PackageName) ||
e.PackageName == SystemUiPackage || e.PackageName.Contains("launcher") ||
root.PackageName != e.PackageName)
{
return;
}
//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 });
//testNodes.Dispose();
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
var cancelNotification = true;
switch(e.EventType)
{
case EventTypes.ViewFocused:
if(!e.Source.Password || !_appSettings.AutofillPasswordField)
{
break;
}
if(e.PackageName == BitwardenPackage)
{
CancelNotification(notificationManager);
break;
}
if(ScanAndAutofill(root, e, notificationManager, cancelNotification))
{
CancelNotification(notificationManager);
}
break;
case EventTypes.WindowContentChanged:
case EventTypes.WindowStateChanged:
if(_appSettings.AutofillPasswordField && e.Source.Password)
{
break;
}
else if(_appSettings.AutofillPasswordField && AutofillActivity.LastCredentials == null)
{
if(string.IsNullOrWhiteSpace(_lastNotificationUri))
{
CancelNotification(notificationManager);
break;
}
var uri = GetUri(root);
if(uri != _lastNotificationUri)
{
CancelNotification(notificationManager);
}
else if(uri.StartsWith(App.Constants.AndroidAppProtocol))
{
CancelNotification(notificationManager, 30000);
}
break;
}
if(e.PackageName == BitwardenPackage)
{
CancelNotification(notificationManager);
break;
}
if(_appSettings.AutofillPersistNotification)
{
var uri = GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
var needToFill = NeedToAutofill(AutofillActivity.LastCredentials, uri);
if(needToFill)
{
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
needToFill = passwordNodes.Any();
if(needToFill)
{
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
FillCredentials(usernameEditText, passwordNodes);
allEditTexts.Dispose();
usernameEditText.Dispose();
}
passwordNodes.Dispose();
}
if(!needToFill)
{
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}
AutofillActivity.LastCredentials = null;
}
else
{
cancelNotification = ScanAndAutofill(root, e, notificationManager, cancelNotification);
}
if(cancelNotification)
{
CancelNotification(notificationManager);
}
break;
default:
break;
}
notificationManager?.Dispose();
root.Dispose();
e.Dispose();
}
// Suppress exceptions so that service doesn't crash
catch { }
}
public override void OnInterrupt()
{
}
public bool ScanAndAutofill(AccessibilityNodeInfo root, AccessibilityEvent e,
NotificationManager notificationManager, bool cancelNotification)
{
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
if(passwordNodes.Count > 0)
{
var uri = GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
if(NeedToAutofill(AutofillActivity.LastCredentials, uri))
{
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
FillCredentials(usernameEditText, passwordNodes);
allEditTexts.Dispose();
usernameEditText.Dispose();
}
else
{
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}
AutofillActivity.LastCredentials = null;
}
else if(AutofillActivity.LastCredentials != null)
{
System.Threading.Tasks.Task.Run(async () =>
{
await System.Threading.Tasks.Task.Delay(1000);
AutofillActivity.LastCredentials = null;
});
}
passwordNodes.Dispose();
return cancelNotification;
}
public void CancelNotification(NotificationManager notificationManager, long limit = 250)
{
if(Java.Lang.JavaSystem.CurrentTimeMillis() - _lastNotificationTime < limit)
{
return;
}
_lastNotificationUri = null;
notificationManager?.Cancel(AutoFillNotificationId);
}
private string GetUri(AccessibilityNodeInfo root)
{
var uri = string.Concat(App.Constants.AndroidAppProtocol, root.PackageName);
if(SupportedBrowsers.ContainsKey(root.PackageName))
{
var addressNode = root.FindAccessibilityNodeInfosByViewId(
$"{root.PackageName}:id/{SupportedBrowsers[root.PackageName].UriViewId}").FirstOrDefault();
if(addressNode != null)
{
uri = ExtractUri(uri, addressNode, SupportedBrowsers[root.PackageName]);
addressNode.Dispose();
}
}
return uri;
}
private string ExtractUri(string uri, AccessibilityNodeInfo addressNode, Browser browser)
{
if(addressNode?.Text != null)
{
uri = browser.GetUriFunction(addressNode.Text).Trim();
if(uri != null && uri.Contains("."))
{
if(!uri.Contains("://") && !uri.Contains(" "))
{
uri = string.Concat("http://", uri);
}
else if(Build.VERSION.SdkInt <= BuildVersionCodes.KitkatWatch)
{
var parts = uri.Split(new string[] { ". " }, StringSplitOptions.None);
if(parts.Length > 1)
{
var urlPart = parts.FirstOrDefault(p => p.StartsWith("http"));
if(urlPart != null)
{
uri = urlPart.Trim();
}
}
}
}
}
return uri;
}
/// <summary>
/// Check to make sure it is ok to autofill still on the current screen
/// </summary>
private bool NeedToAutofill(AutofillCredentials creds, string currentUriString)
{
if(creds == null)
{
return false;
}
Uri lastUri, currentUri;
if(Uri.TryCreate(creds.LastUri, UriKind.Absolute, out lastUri) &&
Uri.TryCreate(currentUriString, UriKind.Absolute, out currentUri) &&
lastUri.Host == currentUri.Host)
{
return true;
}
return false;
}
private static bool EditText(AccessibilityNodeInfo n)
{
return n?.ClassName?.Contains("EditText") ?? false;
}
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
{
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
{
return;
}
var now = Java.Lang.JavaSystem.CurrentTimeMillis();
var intent = new Intent(this, typeof(AutofillActivity));
intent.PutExtra("uri", uri);
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
var notificationContent = Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch ?
AppResources.BitwardenAutofillServiceNotificationContent :
AppResources.BitwardenAutofillServiceNotificationContentOld;
var builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.notification_sm)
.SetContentTitle(AppResources.BitwardenAutofillService)
.SetContentText(notificationContent)
.SetTicker(notificationContent)
.SetWhen(now)
.SetContentIntent(pendingIntent);
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch)
{
builder.SetVisibility(NotificationVisibility.Secret)
.SetColor(global::Android.Support.V4.Content.ContextCompat.GetColor(ApplicationContext,
Resource.Color.primary));
}
if(Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
if(_notificationChannel == null)
{
_notificationChannel = new NotificationChannel("bitwarden_autofill_service",
AppResources.AutofillService, NotificationImportance.Low);
notificationManager.CreateNotificationChannel(_notificationChannel);
}
builder.SetChannelId(_notificationChannel.Id);
}
if(/*Build.VERSION.SdkInt <= BuildVersionCodes.N && */_appSettings.AutofillPersistNotification)
{
builder.SetPriority(-2);
}
_lastNotificationTime = now;
_lastNotificationUri = uri;
notificationManager.Notify(AutoFillNotificationId, builder.Build());
builder.Dispose();
}
private void FillCredentials(AccessibilityNodeInfo usernameNode, IEnumerable<AccessibilityNodeInfo> passwordNodes)
{
FillEditText(usernameNode, AutofillActivity.LastCredentials?.Username);
foreach(var n in passwordNodes)
{
FillEditText(n, AutofillActivity.LastCredentials?.Password);
}
}
private static void FillEditText(AccessibilityNodeInfo editTextNode, string value)
{
if(editTextNode == null || value == null)
{
return;
}
var bundle = new Bundle();
bundle.PutString(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, value);
editTextNode.PerformAction(global::Android.Views.Accessibility.Action.SetText, bundle);
}
private NodeList GetWindowNodes(AccessibilityNodeInfo n, AccessibilityEvent e,
Func<AccessibilityNodeInfo, bool> condition, bool disposeIfUnused, NodeList nodes = null)
{
if(nodes == null)
{
nodes = new NodeList();
}
if(n != null)
{
var dispose = disposeIfUnused;
if(n.WindowId == e.WindowId && !(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) && condition(n))
{
dispose = false;
nodes.Add(n);
}
for(var i = 0; i < n.ChildCount; i++)
{
GetWindowNodes(n.GetChild(i), e, condition, true, nodes);
}
if(dispose)
{
n.Dispose();
}
}
return nodes;
}
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;
}
public class NodeList : List<AccessibilityNodeInfo>, IDisposable
{
public void Dispose()
{
foreach(var item in this)
{
item.Dispose();
}
}
}
}
}

View File

@@ -1,35 +0,0 @@
using System;
using System.ComponentModel;
using Android.Content;
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
{
public CustomButtonRenderer(Context context)
: base(context)
{ }
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));
}
// This will prevent all screen overlay apps from being able to interact with buttons.
// Ex: apps that change the screen color for "night mode"
// Control.FilterTouchesWhenObscured = true;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}
}

View File

@@ -1,21 +0,0 @@
using Android.Content;
using Bit.Android.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]
namespace Bit.Android.Controls
{
public class CustomLabelRenderer : LabelRenderer
{
public CustomLabelRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
Control.SetMaxLines(int.MaxValue);
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.ComponentModel;
using Android.Content;
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
{
public CustomSearchBarRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
Control.SetPadding((int)global::Android.App.Application.Context.ToPixels(-8), 0, 0, 0);
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
using Bit.Android.Controls;
using Xamarin.Forms;
using Android.Content;
using Xamarin.Forms.Platform.Android;
using Android.Support.V4.Content.Res;
[assembly: ExportRenderer(typeof(Slider), typeof(CustomSliderRenderer))]
namespace Bit.Android.Controls
{
public class CustomSliderRenderer : SliderRenderer
{
public CustomSliderRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if(Control != null)
{
var thumb = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
Control.SetThumb(thumb);
}
}
}
}

View File

@@ -1,67 +0,0 @@
using System;
using System.ComponentModel;
using Android.Content;
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
{
public ExtendedButtonRenderer(Context context)
: base(context)
{ }
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;
}
}
}
}
}

View File

@@ -1,86 +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.Text.Method;
using Android.Views;
using Android.Content;
[assembly: ExportRenderer(typeof(ExtendedEditor), typeof(ExtendedEditorRenderer))]
namespace Bit.Android.Controls
{
public class ExtendedEditorRenderer : EditorRenderer
{
public ExtendedEditorRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
var view = (ExtendedEditor)Element;
SetBorder(view);
SetScrollable();
}
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);
}
}
private void SetScrollable()
{
// While scrolling inside Editor stop scrolling parent view.
Control.OverScrollMode = OverScrollMode.Always;
Control.ScrollBarStyle = ScrollbarStyles.InsideInset;
Control.SetOnTouchListener(new EditorTouchListener());
// For Scrolling in Editor innner area
Control.VerticalScrollBarEnabled = true;
Control.ScrollBarStyle = ScrollbarStyles.InsideInset;
// Force scrollbars to be displayed
var arr = Control.Context.Theme.ObtainStyledAttributes(new int[0]);
InitializeScrollbars(arr);
arr.Recycle();
}
public class EditorTouchListener : Java.Lang.Object, IOnTouchListener
{
public bool OnTouch(global::Android.Views.View v, MotionEvent e)
{
v.Parent?.RequestDisallowInterceptTouchEvent(true);
if((e.Action & MotionEventActions.Up) != 0 && (e.ActionMasked & MotionEventActions.Up) != 0)
{
v.Parent?.RequestDisallowInterceptTouchEvent(false);
}
return false;
}
}
}
}

View File

@@ -1,212 +0,0 @@
using System;
using System.ComponentModel;
using Android.Content;
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 Plugin.CurrentActivity;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRenderer))]
namespace Bit.Android.Controls
{
public class ExtendedEntryRenderer : EntryRenderer
{
public ExtendedEntryRenderer(Context context)
: base(context)
{ }
private bool _isPassword;
private bool _toggledPassword;
private bool _isDisposed;
private ExtendedEntry _view;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
_view = (ExtendedEntry)Element;
_isPassword = _view.IsPassword;
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 += Control_EditorAction;
if(_view.DisableAutocapitalize)
{
Control.SetRawInputType(Control.InputType |= InputTypes.TextVariationEmailAddress);
}
if(_view.Autocorrect.HasValue)
{
Control.SetRawInputType(Control.InputType |= InputTypes.TextFlagNoSuggestions);
}
if(_view.IsPassword)
{
Control.SetRawInputType(InputTypes.TextFlagNoSuggestions | InputTypes.TextVariationVisiblePassword);
}
_view.ToggleIsPassword += ToggleIsPassword;
if(_view.FontFamily == "monospace")
{
Control.Typeface = Typeface.Monospace;
}
if(_view.HideCursor)
{
Control.SetCursorVisible(false);
}
}
private void ToggleIsPassword(object sender, EventArgs e)
{
var cursorStart = Control.SelectionStart;
var cursorEnd = Control.SelectionEnd;
Control.TransformationMethod = _isPassword ? null : new PasswordTransformationMethod();
Control.SetRawInputType(InputTypes.TextFlagNoSuggestions | InputTypes.TextVariationVisiblePassword);
// set focus
Control.RequestFocus();
if(_toggledPassword)
{
// restore cursor position
Control.SetSelection(cursorStart, cursorEnd);
}
else
{
// set cursor to end
Control.SetSelection(Control.Text.Length);
}
// show keyboard
var imm = CrossCurrentActivity.Current.Activity.GetSystemService(Context.InputMethodService) as InputMethodManager;
imm.ShowSoftInput(Control, ShowFlags.Forced);
imm.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
_isPassword = _view.IsPasswordFromToggled = !_isPassword;
_toggledPassword = true;
}
private void Control_EditorAction(object sender, TextView.EditorActionEventArgs e)
{
if(_view.ReturnType != ReturnType.Next)
{
_view.Unfocus();
}
// Call all the methods attached to base_entry event handler Completed
_view.InvokeCompleted();
}
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());
}
}
if(view.FontFamily == "monospace")
{
Control.Typeface = Typeface.Monospace;
}
}
protected override void Dispose(bool disposing)
{
if(_isDisposed)
{
return;
}
_isDisposed = true;
if(disposing && Control != null)
{
_view.ToggleIsPassword -= ToggleIsPassword;
Control.EditorAction -= Control_EditorAction;
}
base.Dispose(disposing);
}
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) });
}
}
}

View File

@@ -1,54 +0,0 @@
using System;
using System.ComponentModel;
using Android.Content;
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
{
public ExtendedPickerRenderer(Context context)
: base(context)
{ }
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);
}
}
}
}

View File

@@ -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());
}
}
}
}

View File

@@ -1,441 +0,0 @@
using System;
using Bit.Android.Controls;
using Bit.App.Controls;
using Xamarin.Forms;
using Com.Ittianyu.Bottomnavigationviewex;
using Xamarin.Forms.Platform.Android;
using RelativeLayout = Android.Widget.RelativeLayout;
using Platform = Xamarin.Forms.Platform.Android.Platform;
using Android.Content;
using Android.Views;
using Android.Widget;
using Android.Support.Design.Internal;
using System.IO;
using System.Linq;
using System.ComponentModel;
using Android.Support.Design.Widget;
[assembly: ExportRenderer(typeof(ExtendedTabbedPage), typeof(ExtendedTabbedPageRenderer))]
namespace Bit.Android.Controls
{
public class ExtendedTabbedPageRenderer : VisualElementRenderer<ExtendedTabbedPage>,
BottomNavigationView.IOnNavigationItemSelectedListener
{
public static bool ShouldUpdateSelectedIcon;
public static Action<IMenuItem, FileImageSource, bool> MenuItemIconSetter;
public static float? BottomBarHeight = 50;
private RelativeLayout _rootLayout;
private FrameLayout _pageContainer;
private BottomNavigationViewEx _bottomNav;
private readonly int _barId;
public static global::Android.Graphics.Color? BackgroundColor;
public ExtendedTabbedPageRenderer(Context context)
: base(context)
{
AutoPackage = false;
_barId = GenerateViewId();
}
IPageController TabbedController => Element as IPageController;
public int LastSelectedIndex { get; internal set; }
public bool OnNavigationItemSelected(IMenuItem item)
{
this.SwitchPage(item);
return true;
}
internal void SetupTabItems()
{
this.SetupTabItems(_bottomNav);
}
internal void SetupBottomBar()
{
_bottomNav = this.SetupBottomBar(_rootLayout, _bottomNav, _barId);
}
public static readonly Action<IMenuItem, FileImageSource, bool> DefaultMenuItemIconSetter = (menuItem, icon, selected) =>
{
var tabIconId = ResourceUtils.IdFromTitle(icon, ResourceManager.DrawableClass);
menuItem.SetIcon(tabIconId);
};
protected override void OnElementChanged(ElementChangedEventArgs<ExtendedTabbedPage> e)
{
base.OnElementChanged(e);
if(e.OldElement != null)
{
e.OldElement.ChildAdded -= PagesChanged;
e.OldElement.ChildRemoved -= PagesChanged;
e.OldElement.ChildrenReordered -= PagesChanged;
}
if(e.NewElement == null)
{
return;
}
UpdateIgnoreContainerAreas();
if(_rootLayout == null)
{
SetupNativeView();
}
this.HandlePagesChanged();
SwitchContent(Element.CurrentPage);
Element.ChildAdded += PagesChanged;
Element.ChildRemoved += PagesChanged;
Element.ChildrenReordered += PagesChanged;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if(e.PropertyName == nameof(TabbedPage.CurrentPage))
{
SwitchContent(Element.CurrentPage);
}
}
void PagesChanged(object sender, EventArgs e)
{
this.HandlePagesChanged();
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
TabbedController?.SendAppearing();
}
protected override void OnDetachedFromWindow()
{
base.OnDetachedFromWindow();
TabbedController?.SendDisappearing();
}
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
{
var width = right - left;
var height = bottom - top;
base.OnLayout(changed, left, top, right, bottom);
if(width <= 0 || height <= 0)
{
return;
}
this.Layout(width, height);
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
Element.ChildAdded -= PagesChanged;
Element.ChildRemoved -= PagesChanged;
Element.ChildrenReordered -= PagesChanged;
if(_rootLayout != null)
{
RemoveAllViews();
foreach(Page pageToRemove in Element.Children)
{
var pageRenderer = Platform.GetRenderer(pageToRemove);
if(pageRenderer != null)
{
pageRenderer.View.RemoveFromParent();
pageRenderer.Dispose();
}
}
if(_bottomNav != null)
{
_bottomNav.SetOnNavigationItemSelectedListener(null);
_bottomNav.Dispose();
_bottomNav = null;
}
_rootLayout.Dispose();
_rootLayout = null;
}
}
base.Dispose(disposing);
}
internal void SetupNativeView()
{
_rootLayout = this.CreateRoot(_barId, GenerateViewId(), out _pageContainer);
AddView(_rootLayout);
}
void SwitchContent(Page page)
{
this.ChangePage(_pageContainer, page);
}
void UpdateIgnoreContainerAreas()
{
foreach(var child in Element.Children)
{
child.IgnoresContainerArea = false;
}
}
}
internal static class TabExtensions
{
public static Rectangle CreateRect(this Context context, int width, int height)
{
return new Rectangle(0, 0, context.FromPixels(width), context.FromPixels(height));
}
public static void HandlePagesChanged(this ExtendedTabbedPageRenderer renderer)
{
renderer.SetupBottomBar();
renderer.SetupTabItems();
if(renderer.Element.Children.Count == 0)
{
return;
}
EnsureTabIndex(renderer);
}
static void EnsureTabIndex(ExtendedTabbedPageRenderer renderer)
{
var rootLayout = (RelativeLayout)renderer.GetChildAt(0);
var bottomNav = (BottomNavigationViewEx)rootLayout.GetChildAt(1);
var menu = (BottomNavigationMenu)bottomNav.Menu;
var itemIndex = menu.FindItemIndex(bottomNav.SelectedItemId);
var pageIndex = renderer.Element.Children.IndexOf(renderer.Element.CurrentPage);
if(pageIndex >= 0 && pageIndex != itemIndex && pageIndex < bottomNav.ItemCount)
{
var menuItem = menu.GetItem(pageIndex);
bottomNav.SelectedItemId = menuItem.ItemId;
if(ExtendedTabbedPageRenderer.ShouldUpdateSelectedIcon && ExtendedTabbedPageRenderer.MenuItemIconSetter != null)
{
ExtendedTabbedPageRenderer.MenuItemIconSetter?.Invoke(menuItem, renderer.Element.CurrentPage.Icon, true);
if(renderer.LastSelectedIndex != pageIndex)
{
var lastSelectedPage = renderer.Element.Children[renderer.LastSelectedIndex];
var lastSelectedMenuItem = menu.GetItem(renderer.LastSelectedIndex);
ExtendedTabbedPageRenderer.MenuItemIconSetter?.Invoke(lastSelectedMenuItem, lastSelectedPage.Icon, false);
renderer.LastSelectedIndex = pageIndex;
}
}
}
}
public static void SwitchPage(this ExtendedTabbedPageRenderer renderer, IMenuItem item)
{
var rootLayout = (RelativeLayout)renderer.GetChildAt(0);
var bottomNav = (BottomNavigationViewEx)rootLayout.GetChildAt(1);
var menu = (BottomNavigationMenu)bottomNav.Menu;
var index = menu.FindItemIndex(item.ItemId);
var pageIndex = index % renderer.Element.Children.Count;
var currentPageIndex = renderer.Element.Children.IndexOf(renderer.Element.CurrentPage);
if(currentPageIndex != pageIndex)
{
renderer.Element.CurrentPage = renderer.Element.Children[pageIndex];
}
}
public static void Layout(this ExtendedTabbedPageRenderer renderer, int width, int height)
{
var rootLayout = (RelativeLayout)renderer.GetChildAt(0);
var bottomNav = (BottomNavigationViewEx)rootLayout.GetChildAt(1);
var Context = renderer.Context;
rootLayout.Measure(MakeMeasureSpec(width, MeasureSpecMode.Exactly),
MakeMeasureSpec(height, MeasureSpecMode.AtMost));
((IPageController)renderer.Element).ContainerArea =
Context.CreateRect(rootLayout.MeasuredWidth, rootLayout.GetChildAt(0).MeasuredHeight);
rootLayout.Measure(MakeMeasureSpec(width, MeasureSpecMode.Exactly),
MakeMeasureSpec(height, MeasureSpecMode.Exactly));
rootLayout.Layout(0, 0, rootLayout.MeasuredWidth, rootLayout.MeasuredHeight);
if(renderer.Element.Children.Count == 0)
{
return;
}
int tabsHeight = bottomNav.MeasuredHeight;
var item = (ViewGroup)bottomNav.GetChildAt(0);
item.Measure(MakeMeasureSpec(width, MeasureSpecMode.Exactly),
MakeMeasureSpec(tabsHeight, MeasureSpecMode.Exactly));
item.Layout(0, 0, width, tabsHeight);
int item_w = width / item.ChildCount;
for(int i = 0; i < item.ChildCount; i++)
{
var frame = (FrameLayout)item.GetChildAt(i);
frame.Measure(MakeMeasureSpec(item_w, MeasureSpecMode.Exactly),
MakeMeasureSpec(tabsHeight, MeasureSpecMode.Exactly));
frame.Layout(i * item_w, 0, i * item_w + item_w, tabsHeight);
}
}
public static void SetupTabItems(this ExtendedTabbedPageRenderer renderer, BottomNavigationViewEx bottomNav)
{
var element = renderer.Element;
var menu = (BottomNavigationMenu)bottomNav.Menu;
menu.ClearAll();
var tabsCount = Math.Min(element.Children.Count, bottomNav.MaxItemCount);
for(int i = 0; i < tabsCount; i++)
{
var page = element.Children[i];
var menuItem = menu.Add(0, i, 0, page.Title);
var setter = ExtendedTabbedPageRenderer.MenuItemIconSetter ?? ExtendedTabbedPageRenderer.DefaultMenuItemIconSetter;
setter.Invoke(menuItem, page.Icon, renderer.LastSelectedIndex == i);
}
if(element.Children.Count > 0)
{
bottomNav.EnableShiftingMode(false);
bottomNav.EnableItemShiftingMode(false);
bottomNav.EnableAnimation(false);
bottomNav.SetTextVisibility(false);
bottomNav.SetBackgroundResource(Resource.Drawable.bottom_nav_bg);
bottomNav.SetIconSize(24, 24);
bottomNav.SetIconsMarginTop(32);
if(element.Children.Count > 3)
{
bottomNav.SetIconSizeAt(3, 29, 29);
bottomNav.SetIconMarginTop(3, 28);
}
var stateList = new global::Android.Content.Res.ColorStateList(
new int[][] {
new int[] { global::Android.Resource.Attribute.StateChecked },
new int[] { global::Android.Resource.Attribute.StateEnabled}
},
new int[] {
element.TintColor.ToAndroid(), // Selected
Color.FromHex("A1A1A1").ToAndroid() // Normal
});
bottomNav.ItemIconTintList = stateList;
}
}
public static BottomNavigationViewEx SetupBottomBar(this ExtendedTabbedPageRenderer renderer,
global::Android.Widget.RelativeLayout rootLayout, BottomNavigationViewEx bottomNav, int barId)
{
if(bottomNav != null)
{
rootLayout.RemoveView(bottomNav);
bottomNav.SetOnNavigationItemSelectedListener(null);
}
var barParams = new global::Android.Widget.RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MatchParent,
ExtendedTabbedPageRenderer.BottomBarHeight.HasValue ?
(int)rootLayout.Context.ToPixels(ExtendedTabbedPageRenderer.BottomBarHeight.Value) :
ViewGroup.LayoutParams.WrapContent);
barParams.AddRule(LayoutRules.AlignParentBottom);
bottomNav = new BottomNavigationViewEx(rootLayout.Context)
{
LayoutParameters = barParams,
Id = barId
};
if(ExtendedTabbedPageRenderer.BackgroundColor.HasValue)
{
bottomNav.SetBackgroundColor(ExtendedTabbedPageRenderer.BackgroundColor.Value);
}
bottomNav.SetOnNavigationItemSelectedListener(renderer);
rootLayout.AddView(bottomNav, 1, barParams);
return bottomNav;
}
public static void ChangePage(this ExtendedTabbedPageRenderer renderer, FrameLayout pageContainer, Page page)
{
renderer.Context.HideKeyboard(renderer);
if(page == null)
{
return;
}
if(Platform.GetRenderer(page) == null)
{
Platform.SetRenderer(page, Platform.CreateRendererWithContext(page, renderer.Context));
}
var pageContent = Platform.GetRenderer(page).View;
pageContainer.AddView(pageContent);
if(pageContainer.ChildCount > 1)
{
pageContainer.RemoveViewAt(0);
}
EnsureTabIndex(renderer);
}
public static RelativeLayout CreateRoot(this ExtendedTabbedPageRenderer renderer, int barId, int pageContainerId, out FrameLayout pageContainer)
{
var rootLayout = new RelativeLayout(renderer.Context)
{
LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent),
};
var pageParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
pageParams.AddRule(LayoutRules.Above, barId);
pageContainer = new FrameLayout(renderer.Context)
{
LayoutParameters = pageParams,
Id = pageContainerId
};
rootLayout.AddView(pageContainer, 0, pageParams);
return rootLayout;
}
private static int MakeMeasureSpec(int size, MeasureSpecMode mode)
{
return size + (int)mode;
}
}
public static class ResourceUtils
{
public static int IdFromTitle(string title, Type type)
{
var name = Path.GetFileNameWithoutExtension(title);
var id = GetId(type, name);
return id;
}
public static int GetId(Type type, string propertyName)
{
var props = type.GetFields();
var prop = props.Select(p => p).FirstOrDefault(p => p.Name == propertyName);
if(prop != null)
{
return (int)prop.GetValue(type);
}
return 0;
}
}
}

View File

@@ -1,179 +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
{
public ExtendedTableViewRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
{
base.OnElementChanged(e);
Control.Divider = null;
Control.DividerHeight = 0;
if(e.NewElement is ExtendedTableView tableView)
{
if(tableView.BottomPadding > 0)
{
Control.SetPadding(0, 0, 0, tableView.BottomPadding);
Control.SetClipToPadding(false);
Control.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
}
}
}
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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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());
}
}
}
}

View File

@@ -0,0 +1,26 @@
using Android.Support.Design.BottomNavigation;
using Android.Support.Design.Widget;
using Android.Views;
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()
{
}
}
}

View File

@@ -0,0 +1,26 @@
using Android.Support.Design.BottomNavigation;
using Android.Support.Design.Widget;
using Android.Views;
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()
{
}
}
}

View File

@@ -0,0 +1,31 @@
using Android.Support.Design.BottomNavigation;
using Android.Support.Design.Widget;
using Android.Views;
using Bit.Droid.Effects;
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()
{
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using Android.App;
using Android.Content;
using Bit.App;
using Bit.App.Abstractions;
using Firebase.Iid;
using Plugin.Settings.Abstractions;
using XLabs.Ioc;
namespace Bit.Android
{
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseInstanceIdService : Firebase.Iid.FirebaseInstanceIdService
{
public override void OnTokenRefresh()
{
var settings = Resolver.Resolve<ISettings>();
settings.AddOrUpdateValue(Constants.PushRegisteredToken, FirebaseInstanceId.Instance.Token);
Resolver.Resolve<IPushNotificationService>()?.Register();
}
}
}

View File

@@ -1,185 +1,210 @@
using System;
using Android.App;
using Android.App;
using Android.Content.PM;
using Android.Views;
using Android.Runtime;
using Android.OS;
using Bit.App.Abstractions;
using XLabs.Ioc;
using Plugin.Settings.Abstractions;
using Plugin.Connectivity.Abstractions;
using Android.Content;
using System.Reflection;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using System.Threading.Tasks;
using Bit.App;
using Android.Nfc;
using System.IO;
using Bit.Core;
using System.Linq;
using Bit.App.Abstractions;
using Bit.Core.Utilities;
using Bit.Core.Abstractions;
using System.IO;
using System;
using Android.Content;
using Bit.Droid.Utilities;
using Bit.Droid.Receivers;
using Bit.App.Models;
using Bit.App.Enums;
using Bit.Core.Enums;
using Android.Nfc;
using Bit.App.Utilities;
using System.Threading.Tasks;
namespace Bit.Android
namespace Bit.Droid
{
[Activity(Label = "bitwarden",
Icon = "@drawable/icon",
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
Exported = false)]
public class MainActivity : FormsAppCompatActivity
[Activity(
Label = "Bitwarden",
Icon = "@mipmap/ic_launcher",
Theme = "@style/LightTheme.Splash",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[Register("com.x8bit.bitwarden.MainActivity")]
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
private Java.Util.Regex.Pattern _otpPattern = Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
private IDeviceActionService _deviceActionService;
private ISettings _settings;
private AppOptions _appOptions;
protected override void OnCreate(Bundle bundle)
private IDeviceActionService _deviceActionService;
private IMessagingService _messagingService;
private IBroadcasterService _broadcasterService;
private IUserService _userService;
private IAppIdService _appIdService;
private IStorageService _storageService;
private IStateService _stateService;
private PendingIntent _lockAlarmPendingIntent;
private PendingIntent _clearClipboardPendingIntent;
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})$");
protected override void OnCreate(Bundle savedInstanceState)
{
if(!Resolver.IsSet)
{
MainApplication.SetIoc(Application);
}
var alarmIntent = new Intent(this, typeof(LockAlarmReceiver));
_lockAlarmPendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent,
PendingIntentFlags.UpdateCurrent);
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
PendingIntentFlags.UpdateCurrent);
var policy = new StrictMode.ThreadPolicy.Builder().PermitAll().Build();
StrictMode.SetThreadPolicy(policy);
ToolbarResource = Resource.Layout.toolbar;
TabLayoutResource = Resource.Layout.tabs;
_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");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
base.OnCreate(bundle);
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
// workaround for app compat bug
// ref https://forums.xamarin.com/discussion/62414/app-resuming-results-in-crash-with-formsappcompatactivity
Task.Delay(10).Wait();
Console.WriteLine("A OnCreate");
if(!App.Utilities.Helpers.InDebugMode())
UpdateTheme(ThemeManager.GetTheme());
base.OnCreate(savedInstanceState);
if(!CoreHelpers.InDebugMode())
{
Window.AddFlags(WindowManagerFlags.Secure);
Window.AddFlags(Android.Views.WindowManagerFlags.Secure);
}
var appIdService = Resolver.Resolve<IAppIdService>();
var authService = Resolver.Resolve<IAuthService>();
#if !FDROID
var hockeyAppListener = new HockeyAppCrashManagerListener(_appIdService, _userService);
var hockeyAppTask = hockeyAppListener.InitAsync();
HockeyApp.Android.CrashManager.Register(this, HockeyAppId, hockeyAppListener);
#endif
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"));
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
_settings = Resolver.Resolve<ISettings>();
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
_appOptions = GetOptions();
LoadApplication(new App.App(
_appOptions,
Resolver.Resolve<IAuthService>(),
Resolver.Resolve<IConnectivity>(),
Resolver.Resolve<IDatabaseService>(),
Resolver.Resolve<ISyncService>(),
_settings,
Resolver.Resolve<ILockService>(),
Resolver.Resolve<ILocalizeService>(),
Resolver.Resolve<IAppInfoService>(),
Resolver.Resolve<IAppSettingsService>(),
_deviceActionService));
LoadApplication(new App.App(_appOptions));
if(_appOptions?.Uri == null)
_broadcasterService.Subscribe(_activityKey, (message) =>
{
MessagingCenter.Subscribe<Xamarin.Forms.Application, bool>(Xamarin.Forms.Application.Current,
"ListenYubiKeyOTP", (sender, listen) => ListenYubiKey(listen));
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current,
"FinishMainActivity", (sender) => Finish());
}
if(message.Command == "scheduleLockTimer")
{
var lockOptionMinutes = (int)message.Data;
var lockOptionMs = lockOptionMinutes * 60000;
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + lockOptionMs + 10;
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
alarmManager.Set(AlarmType.RtcWakeup, triggerMs, _lockAlarmPendingIntent);
}
else if(message.Command == "cancelLockTimer")
{
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
alarmManager.Cancel(_lockAlarmPendingIntent);
}
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();
ListenYubiKey(false);
}
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();
}
protected override void OnResume()
{
base.OnResume();
Console.WriteLine("A OnResume");
// workaround for app compat bug
// ref https://bugzilla.xamarin.com/show_bug.cgi?id=36907
Task.Delay(10).Wait();
if(Utilities.NfcEnabled())
if(_deviceActionService.SupportsNfc())
{
MessagingCenter.Send(Xamarin.Forms.Application.Current, "ResumeYubiKey");
try
{
_messagingService.Send("resumeYubiKey");
}
catch { }
}
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
Console.WriteLine("A OnNewIntent");
ParseYubiKey(intent.DataString);
if(intent.GetBooleanExtra("generatorTile", false))
{
_messagingService.Send("popAllAndGoToTabGenerator");
if(_appOptions != null)
{
_appOptions.GeneratorTile = true;
}
}
if(intent.GetBooleanExtra("myVaultTile", false))
{
_messagingService.Send("popAllAndGoToTabMyVault");
if(_appOptions != null)
{
_appOptions.MyVaultTile = true;
}
}
else
{
ParseYubiKey(intent.DataString);
}
}
public async override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
public async override void OnRequestPermissionsResult(int requestCode, string[] permissions,
[GeneratedEnum] Permission[] grantResults)
{
if(requestCode == Constants.SelectFilePermissionRequestCode)
{
if(grantResults.Any(r => r != Permission.Granted))
{
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileCameraPermissionDenied");
_messagingService.Send("selectFileCameraPermissionDenied");
}
await _deviceActionService.SelectFileAsync();
return;
}
ZXing.Net.Mobile.Forms.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
else
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
ZXing.Net.Mobile.Forms.Android.PermissionsHandler.OnRequestPermissionsResult(
requestCode, permissions, grantResults);
}
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if(requestCode == Constants.SelectFileRequestCode && resultCode == Result.Ok)
{
global::Android.Net.Uri uri = null;
Android.Net.Uri uri = null;
string fileName = null;
if(data != null && data.Data != null)
{
uri = data.Data;
fileName = Utilities.GetFileName(ApplicationContext, uri);
fileName = AndroidHelpers.GetFileName(ApplicationContext, uri);
}
else
{
// camera
var root = new Java.IO.File(global::Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
var root = new Java.IO.File(Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
var file = new Java.IO.File(root, "temp_camera_photo.jpg");
uri = global::Android.Net.Uri.FromFile(file);
uri = Android.Net.Uri.FromFile(file);
fileName = $"photo_{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.jpg";
}
@@ -187,58 +212,60 @@ namespace Bit.Android
{
return;
}
using(var stream = ContentResolver.OpenInputStream(uri))
using(var memoryStream = new MemoryStream())
try
{
stream.CopyTo(memoryStream);
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
new Tuple<byte[], string>(memoryStream.ToArray(), fileName ?? "unknown_file_name"));
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(!Utilities.NfcEnabled())
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 };
// register for foreground dispatch so we'll receive tags according to our intent filters
adapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
try
{
// register for foreground dispatch so we'll receive tags according to our intent filters
adapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
}
catch { }
}
else
{
adapter.DisableForegroundDispatch(this);
}
}
private void ParseYubiKey(string data)
{
if(data == null)
{
return;
}
var otpMatch = _otpPattern.Matcher(data);
if(otpMatch.Matches())
{
var otp = otpMatch.Group(1);
MessagingCenter.Send(Xamarin.Forms.Application.Current, "GotYubiKeyOTP", otp);
try
{
adapter.DisableForegroundDispatch(this);
}
catch { }
}
}
@@ -248,15 +275,14 @@ namespace Bit.Android
{
Uri = Intent.GetStringExtra("uri") ?? Intent.GetStringExtra("autofillFrameworkUri"),
MyVaultTile = Intent.GetBooleanExtra("myVaultTile", false),
GeneratorTile = Intent.GetBooleanExtra("generatorTile", false),
FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false)
};
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);
@@ -269,8 +295,82 @@ namespace Bit.Android
options.SaveCardExpYear = Intent.GetStringExtra("autofillFrameworkCardExpYear");
options.SaveCardCode = Intent.GetStringExtra("autofillFrameworkCardCode");
}
return options;
}
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 == "dark")
{
SetTheme(Resource.Style.DarkTheme);
}
else if(theme == "black")
{
SetTheme(Resource.Style.BlackTheme);
}
else if(theme == "nord")
{
SetTheme(Resource.Style.NordTheme);
}
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;
}
await _stateService.SaveAsync(Constants.LastClipboardValueKey, data.Item1);
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);
}
}
}

View File

@@ -1,172 +1,157 @@
using System;
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 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 XLabs.Ioc;
using System.Threading.Tasks;
using Plugin.Settings.Abstractions;
using FFImageLoading.Forms.Droid;
using XLabs.Ioc.SimpleInjectorContainer;
using SimpleInjector;
#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)
{
//AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser;
if(!Resolver.IsSet)
if(ServiceContainer.RegisteredServices.Count == 0)
{
SetIoc(this);
RegisterLocalServices();
ServiceContainer.Init();
if(App.Migration.MigrationHelpers.NeedsMigration())
{
var task = App.Migration.MigrationHelpers.PerformMigrationAsync();
Task.Delay(2000).Wait();
}
}
}
private void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
var message = Utilities.AppendExceptionToMessage("", e.Exception);
//Utilities.SaveCrashFile(message, true);
Utilities.SendCrashEmail(message, false);
#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;
Bootstrap();
CrossCurrentActivity.Current.Init(this);
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
public void OnProviderInstallFailed(int errorCode, Intent recoveryIntent)
{
}
public void OnActivityPaused(Activity activity)
public void OnProviderInstalled()
{
}
public void OnActivityResumed(Activity activity)
private void RegisterLocalServices()
{
CrossCurrentActivity.Current.Activity = activity;
}
ServiceContainer.Register<ILogService>("logService", new AndroidLogService());
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
if(App.Migration.MigrationHelpers.NeedsMigration())
{
ServiceContainer.Register<App.Migration.Abstractions.IOldSecureStorageService>(
"oldSecureStorageService", new Migration.AndroidKeyStoreStorageService());
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
public static void SetIoc(Application application)
{
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
CachedImageRenderer.Init();
ZXing.Net.Mobile.Forms.Android.Platform.Init();
// Note: This might cause a race condition. Investigate more.
Task.Run(() =>
{
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
{
FadeAnimationEnabled = false,
FadeAnimationForCachedImages = false
});
ZXing.Net.Mobile.Forms.Android.Platform.Init();
});
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
CrossFingerprint.SetDialogFragmentType<CustomFingerprintDialogFragment>();
//var container = new UnityContainer();
var container = new Container();
var preferencesStorage = new PreferencesStorageService(null);
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));
liteDbStorage.InitAsync();
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);
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
broadcasterService);
// Android Stuff
container.RegisterSingleton(application.ApplicationContext);
container.RegisterSingleton<Application>(application);
// Services
container.RegisterSingleton<IDatabaseService, DatabaseService>();
container.RegisterSingleton<ISqlService, SqlService>();
container.RegisterSingleton<ISecureStorageService, AndroidKeyStoreStorageService>();
container.RegisterSingleton<ICryptoService, CryptoService>();
container.RegisterSingleton<IKeyDerivationService, BouncyCastleKeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ICollectionService, CollectionService>();
container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
container.RegisterSingleton<IAppIdService, AppIdService>();
container.RegisterSingleton<IPasswordGenerationService, PasswordGenerationService>();
container.RegisterSingleton<IReflectionService, ReflectionService>();
container.RegisterSingleton<ILockService, LockService>();
container.RegisterSingleton<IAppInfoService, AppInfoService>();
container.RegisterSingleton<IGoogleAnalyticsService, GoogleAnalyticsService>();
container.RegisterSingleton<IDeviceInfoService, DeviceInfoService>();
container.RegisterSingleton<ILocalizeService, LocalizeService>();
container.RegisterSingleton<ILogService, LogService>();
container.RegisterSingleton<IHttpService, HttpService>();
container.RegisterSingleton<ITokenService, TokenService>();
container.RegisterSingleton<ISettingsService, SettingsService>();
container.RegisterSingleton<IMemoryService, MemoryService>();
container.RegisterSingleton<IAppSettingsService, AppSettingsService>();
// Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
container.RegisterSingleton<ICipherApiRepository, CipherApiRepository>();
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
container.RegisterSingleton<ICollectionRepository, CollectionRepository>();
container.RegisterSingleton<ICipherCollectionRepository, CipherCollectionRepository>();
// Other
container.RegisterSingleton(CrossSettings.Current);
container.RegisterSingleton(CrossConnectivity.Current);
container.RegisterSingleton(CrossFingerprint.Current);
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);
// Push
container.RegisterSingleton<IPushNotificationListener, PushNotificationListener>();
container.RegisterSingleton<IPushNotificationService, AndroidPushNotificationService>();
#if FDROID
ServiceContainer.Register<IPushNotificationListenerService>(
"pushNotificationListenerService", new NoopPushNotificationListenerService());
ServiceContainer.Register<IPushNotificationService>(
"pushNotificationService", new NoopPushNotificationService());
#else
var notificationListenerService = new PushNotificationListenerService();
ServiceContainer.Register<IPushNotificationListenerService>(
"pushNotificationListenerService", notificationListenerService);
var androidPushNotificationService = new AndroidPushNotificationService(
mobileStorageService, notificationListenerService);
ServiceContainer.Register<IPushNotificationService>(
"pushNotificationService", androidPushNotificationService);
#endif
}
container.Verify();
Resolver.SetResolver(new SimpleInjectorResolver(container));
private void Bootstrap()
{
(ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService).Init();
ServiceContainer.Resolve<IAuthService>("authService").Init();
// Note: This is not awaited
var bootstrapTask = BootstrapAsync();
}
private async Task BootstrapAsync()
{
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();
}
}
}

View File

@@ -8,14 +8,16 @@ using Javax.Security.Auth.X500;
using Java.Math;
using Android.Security.Keystore;
using Android.App;
using Plugin.Settings.Abstractions;
using Java.Util;
using Javax.Crypto.Spec;
using Android.Preferences;
using Bit.App.Migration;
using Bit.Core.Utilities;
using Bit.App.Migration.Abstractions;
namespace Bit.Android.Services
namespace Bit.Droid.Migration
{
public class AndroidKeyStoreStorageService : ISecureStorageService
public class AndroidKeyStoreStorageService : IOldSecureStorageService
{
private const string AndroidKeyStore = "AndroidKeyStore";
private const string AesMode = "AES/GCM/NoPadding";
@@ -31,21 +33,31 @@ namespace Bit.Android.Services
private readonly string _rsaMode;
private readonly bool _oldAndroid;
private readonly ISettings _settings;
private readonly SettingsShim _settings;
private readonly KeyStore _keyStore;
public AndroidKeyStoreStorageService(ISettings settings)
public AndroidKeyStoreStorageService()
{
_oldAndroid = Build.VERSION.SdkInt < BuildVersionCodes.M;
_rsaMode = _oldAndroid ? "RSA/ECB/PKCS1Padding" : "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
_settings = settings;
_settings = ServiceContainer.Resolve<SettingsShim>("settingsShim");
_keyStore = KeyStore.GetInstance(AndroidKeyStore);
_keyStore.Load(null);
GenerateStoreKey();
/*
try
{
GenerateStoreKey(true);
}
catch
{
GenerateStoreKey(false);
}
GenerateAesKey();
*/
}
public bool Contains(string key)
@@ -87,7 +99,7 @@ namespace Bit.Android.Services
try
{
return App.Utilities.Crypto.AesCbcDecrypt(new App.Models.CipherString(cs), aesKey);
return App.Migration.Crypto.AesCbcDecrypt(new App.Migration.Models.CipherString(cs), aesKey);
}
catch
{
@@ -117,7 +129,7 @@ namespace Bit.Android.Services
try
{
var cipherString = App.Utilities.Crypto.AesCbcEncrypt(dataBytes, aesKey);
var cipherString = App.Migration.Crypto.AesCbcEncrypt(dataBytes, aesKey);
_settings.AddOrUpdateValue(formattedKey, cipherString.EncryptedString);
}
catch
@@ -128,7 +140,7 @@ namespace Bit.Android.Services
}
}
private void GenerateStoreKey()
private void GenerateStoreKey(bool withDate)
{
if(_keyStore.ContainsAlias(KeyAlias))
{
@@ -144,27 +156,33 @@ namespace Bit.Android.Services
{
var subject = new X500Principal($"CN={KeyAlias}");
var spec = new KeyPairGeneratorSpec.Builder(Application.Context)
var builder = new KeyPairGeneratorSpec.Builder(Application.Context)
.SetAlias(KeyAlias)
.SetSubject(subject)
.SetSerialNumber(BigInteger.Ten)
.SetStartDate(new Date(0))
.SetEndDate(end.Time)
.Build();
.SetSerialNumber(BigInteger.Ten);
if(withDate)
{
builder.SetStartDate(new Date(0)).SetEndDate(end.Time);
}
var spec = builder.Build();
var gen = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, AndroidKeyStore);
gen.Initialize(spec);
gen.GenerateKeyPair();
}
else
{
var spec = new KeyGenParameterSpec.Builder(KeyAlias, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
var builder = new KeyGenParameterSpec.Builder(KeyAlias, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
.SetBlockModes(KeyProperties.BlockModeGcm)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone)
.SetKeyValidityStart(new Date(0))
.SetKeyValidityEnd(end.Time)
.Build();
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone);
if(withDate)
{
builder.SetKeyValidityStart(new Date(0)).SetKeyValidityEnd(end.Time);
}
var spec = builder.Build();
var gen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, AndroidKeyStore);
gen.Init(spec);
gen.GenerateKey();
@@ -183,12 +201,12 @@ namespace Bit.Android.Services
return;
}
var key = App.Utilities.Crypto.RandomBytes(512 / 8);
var key = App.Migration.Crypto.RandomBytes(512 / 8);
var encKey = _oldAndroid ? RsaEncrypt(key) : AesEncrypt(key);
_settings.AddOrUpdateValue(AesKey, encKey);
}
private App.Models.SymmetricCryptoKey GetAesKey(bool v1 = false)
private App.Migration.Models.SymmetricCryptoKey GetAesKey(bool v1 = false)
{
try
{
@@ -208,7 +226,7 @@ namespace Bit.Android.Services
{
var encKeyBytes = Convert.FromBase64String(encKey);
var key = RsaDecrypt(encKeyBytes, v1);
return new App.Models.SymmetricCryptoKey(key);
return new App.Migration.Models.SymmetricCryptoKey(key);
}
else
{
@@ -221,7 +239,7 @@ namespace Bit.Android.Services
var ivBytes = Convert.FromBase64String(parts[0]);
var encKeyBytes = Convert.FromBase64String(parts[1]);
var key = AesDecrypt(ivBytes, encKeyBytes);
return new App.Models.SymmetricCryptoKey(key);
return new App.Migration.Models.SymmetricCryptoKey(key);
}
}
catch
@@ -303,7 +321,7 @@ namespace Bit.Android.Services
try
{
var cs = _settings.GetValueOrDefault(formattedKeyV1, null);
var value = App.Utilities.Crypto.AesCbcDecrypt(new App.Models.CipherString(cs), aesKeyV1);
var value = App.Migration.Crypto.AesCbcDecrypt(new App.Migration.Models.CipherString(cs), aesKeyV1);
Store(key, value);
return value;
}

View File

@@ -1,23 +0,0 @@
using Android.App;
using Android.Content;
using Bit.App.Abstractions;
using Bit.App.Utilities;
using Plugin.Settings.Abstractions;
using System;
using XLabs.Ioc;
namespace Bit.Android
{
[BroadcastReceiver(Name = "com.x8bit.bitwarden.PackageReplacedReceiver", Exported = false)]
[IntentFilter(new[] { Intent.ActionMyPackageReplaced })]
public class PackageReplacedReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("Bitwarden App Updated!!");
Helpers.PerformUpdateTasks(Resolver.Resolve<ISettings>(),
Resolver.Resolve<IAppInfoService>(), Resolver.Resolve<IDatabaseService>(),
Resolver.Resolve<ISyncService>());
}
}
}

View File

@@ -1,39 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.14.1" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="1"
android:versionName="2.0.1"
package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<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.ACCESS_NETWORK_STATE"/>
<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/BitwardenTheme" android:allowBackup="false">
<application
android:label="Bitwarden"
android:theme="@style/LightTheme.Splash"
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="android.support.v4.content.FileProvider"
android:authorities="com.x8bit.bitwarden.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
android:name="android.support.v4.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" />
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
<category android:name="com.x8bit.bitwarden" />
</intent-filter>
</receiver>
<activity android:name="net.hockeyapp.android.UpdateActivity" android:exported="false" android:icon="@drawable/icon" />
<meta-data android:name="android.max_aspect" android:value="2.1" />
</application>
</manifest>

View File

@@ -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
@@ -10,8 +8,8 @@ using Android.App;
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("8bit Solutions LLC")]
[assembly: AssemblyProduct("bitwarden")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyProduct("Bitwarden")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View File

@@ -0,0 +1,25 @@
#if !FDROID
using Android.App;
using Android.Content;
using Bit.App.Abstractions;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Firebase.Iid;
namespace Bit.Droid.Push
{
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseInstanceIdService : Firebase.Iid.FirebaseInstanceIdService
{
public async override void OnTokenRefresh()
{
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
var pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService");
await storageService.SaveAsync(Constants.PushRegisteredTokenKey, FirebaseInstanceId.Instance.Token);
await pushNotificationService.RegisterAsync();
}
}
}
#endif

View File

@@ -1,37 +1,36 @@
using System;
#if !FDROID
using Android.App;
using Android.Content;
using Bit.App.Abstractions;
using Bit.Core.Utilities;
using Firebase.Messaging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.Android
namespace Bit.Droid.Push
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseMessagingService : Firebase.Messaging.FirebaseMessagingService
{
public override void OnMessageReceived(RemoteMessage message)
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 = Resolver.Resolve<IPushNotificationListener>();
listener.OnMessage(obj, Device.Android);
var listener = ServiceContainer.Resolve<IPushNotificationListenerService>(
"pushNotificationListenerService");
await listener.OnMessageAsync(obj, Device.Android);
}
catch(JsonReaderException ex)
{
@@ -40,3 +39,4 @@ namespace Bit.Android
}
}
}
#endif

View File

@@ -0,0 +1,23 @@
using Android.Content;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
namespace Bit.Droid.Receivers
{
[BroadcastReceiver(Name = "com.x8bit.bitwarden.ClearClipboardAlarmReceiver", Exported = false)]
public class ClearClipboardAlarmReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
{
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var clipboardManager = context.GetSystemService(Context.ClipboardService) as ClipboardManager;
var lastClipboardValue = await stateService.GetAsync<string>(Constants.LastClipboardValueKey);
await stateService.RemoveAsync(Constants.LastClipboardValueKey);
if(lastClipboardValue == clipboardManager.Text)
{
clipboardManager.Text = string.Empty;
}
}
}
}

View 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.LockAlarmReceiver", Exported = false)]
public class LockAlarmReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
{
var lockService = ServiceContainer.Resolve<ILockService>("lockService");
await lockService.CheckLockAsync();
}
}
}

View 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);
}
}
}

View File

@@ -0,0 +1,241 @@
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using FFImageLoading;
using FFImageLoading.Views;
using FFImageLoading.Work;
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CipherViewCell), typeof(CipherViewCellRenderer))]
namespace Bit.Droid.Renderers
{
public class CipherViewCellRenderer : ViewCellRenderer
{
private static Typeface _faTypeface;
private static Typeface _miTypeface;
private static Android.Graphics.Color _textColor;
private static Android.Graphics.Color _mutedColor;
private static Android.Graphics.Color _disabledIconColor;
private AndroidCipherCell _cell;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView,
ViewGroup parent, Context context)
{
if(_faTypeface == null)
{
_faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
}
if(_miTypeface == null)
{
_miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
}
if(_textColor == default(Android.Graphics.Color))
{
_textColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["TextColor"])
.ToAndroid();
}
if(_mutedColor == default(Android.Graphics.Color))
{
_mutedColor = ((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["MutedColor"])
.ToAndroid();
}
if(_disabledIconColor == default(Android.Graphics.Color))
{
_disabledIconColor =
((Xamarin.Forms.Color)Xamarin.Forms.Application.Current.Resources["DisabledIconColor"])
.ToAndroid();
}
var cipherCell = item as CipherViewCell;
_cell = convertView as AndroidCipherCell;
if(_cell == null)
{
_cell = new AndroidCipherCell(context, cipherCell, _faTypeface, _miTypeface);
}
else
{
_cell.CipherViewCell.PropertyChanged -= CellPropertyChanged;
}
cipherCell.PropertyChanged += CellPropertyChanged;
_cell.UpdateCell(cipherCell);
_cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
return _cell;
}
public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var cipherCell = sender as CipherViewCell;
_cell.CipherViewCell = cipherCell;
if(e.PropertyName == CipherViewCell.CipherProperty.PropertyName)
{
_cell.UpdateCell(cipherCell);
}
else if(e.PropertyName == CipherViewCell.WebsiteIconsEnabledProperty.PropertyName)
{
_cell.UpdateIconImage(cipherCell);
}
}
}
public class AndroidCipherCell : LinearLayout, INativeElementView
{
private readonly Typeface _faTypeface;
private readonly Typeface _miTypeface;
private IScheduledWork _currentTask;
public AndroidCipherCell(Context context, CipherViewCell cipherView, Typeface faTypeface, Typeface miTypeface)
: base(context)
{
CipherViewCell = cipherView;
_faTypeface = faTypeface;
_miTypeface = miTypeface;
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.CipherViewCell, null);
IconImage = view.FindViewById<IconImageView>(Resource.Id.CipherCellIconImage);
Icon = view.FindViewById<TextView>(Resource.Id.CipherCellIcon);
Name = view.FindViewById<TextView>(Resource.Id.CipherCellName);
SubTitle = view.FindViewById<TextView>(Resource.Id.CipherCellSubTitle);
SharedIcon = view.FindViewById<TextView>(Resource.Id.CipherCellSharedIcon);
AttachmentsIcon = view.FindViewById<TextView>(Resource.Id.CipherCellAttachmentsIcon);
MoreButton = view.FindViewById<Android.Widget.Button>(Resource.Id.CipherCellButton);
MoreButton.Click += MoreButton_Click;
Icon.Typeface = _faTypeface;
SharedIcon.Typeface = _faTypeface;
AttachmentsIcon.Typeface = _faTypeface;
MoreButton.Typeface = _miTypeface;
var small = (float)Device.GetNamedSize(NamedSize.Small, typeof(Label));
Icon.SetTextSize(ComplexUnitType.Pt, 10);
Name.SetTextSize(ComplexUnitType.Sp, (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label)));
SubTitle.SetTextSize(ComplexUnitType.Sp, small);
SharedIcon.SetTextSize(ComplexUnitType.Sp, small);
AttachmentsIcon.SetTextSize(ComplexUnitType.Sp, small);
MoreButton.SetTextSize(ComplexUnitType.Sp, 25);
AddView(view);
}
public CipherViewCell CipherViewCell { get; set; }
public Element Element => CipherViewCell;
public IconImageView IconImage { get; set; }
public TextView Icon { get; set; }
public TextView Name { get; set; }
public TextView SubTitle { get; set; }
public TextView SharedIcon { get; set; }
public TextView AttachmentsIcon { get; set; }
public Android.Widget.Button MoreButton { get; set; }
public void UpdateCell(CipherViewCell cipherCell)
{
UpdateIconImage(cipherCell);
var cipher = cipherCell.Cipher;
Name.Text = cipher.Name;
if(!string.IsNullOrWhiteSpace(cipher.SubTitle))
{
SubTitle.Text = cipher.SubTitle;
SubTitle.Visibility = ViewStates.Visible;
}
else
{
SubTitle.Visibility = ViewStates.Invisible;
}
SharedIcon.Visibility = cipher.Shared ? ViewStates.Visible : ViewStates.Gone;
AttachmentsIcon.Visibility = cipher.HasAttachments ? ViewStates.Visible : ViewStates.Gone;
}
public void UpdateIconImage(CipherViewCell cipherCell)
{
if(_currentTask != null && !_currentTask.IsCancelled && !_currentTask.IsCompleted)
{
_currentTask.Cancel();
}
var cipher = cipherCell.Cipher;
var iconImage = cipherCell.GetIconImage(cipher);
if(iconImage.Item2 != null)
{
IconImage.SetImageResource(Resource.Drawable.login);
IconImage.Visibility = ViewStates.Visible;
Icon.Visibility = ViewStates.Gone;
_currentTask = ImageService.Instance.LoadUrl(iconImage.Item2).DownSample(64).Into(IconImage);
IconImage.Key = iconImage.Item2;
}
else
{
IconImage.Visibility = ViewStates.Gone;
Icon.Visibility = ViewStates.Visible;
Icon.Text = iconImage.Item1;
}
}
public void UpdateColors(Android.Graphics.Color textColor, Android.Graphics.Color mutedColor,
Android.Graphics.Color iconDisabledColor)
{
Name.SetTextColor(textColor);
SubTitle.SetTextColor(mutedColor);
Icon.SetTextColor(mutedColor);
SharedIcon.SetTextColor(mutedColor);
AttachmentsIcon.SetTextColor(mutedColor);
MoreButton.SetTextColor(iconDisabledColor);
}
private void MoreButton_Click(object sender, EventArgs e)
{
if(CipherViewCell.ButtonCommand?.CanExecute(CipherViewCell.Cipher) ?? false)
{
CipherViewCell.ButtonCommand.Execute(CipherViewCell.Cipher);
}
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
MoreButton.Click -= MoreButton_Click;
}
base.Dispose(disposing);
}
}
[Android.Runtime.Preserve(AllMembers = true)]
[Register("bit.droid.renderers.IconImageView")]
public class IconImageView : ImageViewAsync
{
public IconImageView(Context context) : base(context)
{ }
public IconImageView(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{ }
public IconImageView(Context context, IAttributeSet attrs)
: base(context, attrs)
{ }
public string Key { get; set; }
protected override void JavaFinalize()
{
SetImageDrawable(null);
SetImageBitmap(null);
ImageService.Instance.InvalidateCacheEntryAsync(Key, FFImageLoading.Cache.CacheType.Memory);
base.JavaFinalize();
}
}
}

View File

@@ -0,0 +1,28 @@
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)
{ }
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;
}
}
}
}

View File

@@ -0,0 +1,28 @@
using Android.Content;
using Android.Views.InputMethods;
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;
}
}
}
}

View 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);
}
}
}
}

View 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);
}
}
}
}

View File

@@ -1,13 +1,12 @@
using System;
using Bit.Android.Controls;
using Android.Content;
using Android.Views;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Content;
using Android.Views;
[assembly: ExportRenderer(typeof(ExtendedListView), typeof(ExtendedListViewRenderer))]
namespace Bit.Android.Controls
namespace Bit.Droid.Renderers
{
public class ExtendedListViewRenderer : ListViewRenderer
{
@@ -18,15 +17,12 @@ namespace Bit.Android.Controls
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if(e.NewElement is ExtendedListView listView)
if(Control != null && e.NewElement != null && e.NewElement is ExtendedListView listView)
{
if(listView.BottomPadding > 0)
{
Control.SetPadding(0, 0, 0, listView.BottomPadding);
Control.SetClipToPadding(false);
Control.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
}
// Pad for FAB
Control.SetPadding(0, 0, 0, 170);
Control.SetClipToPadding(false);
Control.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
}
}
}

View File

@@ -0,0 +1,33 @@
using Android.Content;
using Android.Graphics.Drawables;
using Android.Support.V4.Content.Res;
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)
{
thumb.SetColor(view.ThumbColor.ToAndroid());
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
Control.SetThumb(thumb);
}
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using Bit.Android.Controls;
using Bit.App.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -7,18 +6,23 @@ using Android.Webkit;
using AWebkit = Android.Webkit;
using Java.Interop;
using Android.Content;
using Plugin.CurrentActivity;
using Bit.Droid.Renderers;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace Bit.Android.Controls
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)
{
@@ -26,31 +30,30 @@ namespace Bit.Android.Controls
if(Control == null)
{
var webView = new AWebkit.WebView(CrossCurrentActivity.Current.Activity);
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);
InjectJS(JSFunction);
}
}
private void InjectJS(string script)
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(Control != null)
base.OnElementPropertyChanged(sender, e);
if(e.PropertyName == HybridWebView.UriProperty.PropertyName)
{
Control.LoadUrl(string.Format("javascript: {0}", script));
Control.LoadUrl(Element.Uri);
}
}
@@ -67,12 +70,29 @@ namespace Bit.Android.Controls
[Export("invokeAction")]
public void InvokeAction(string data)
{
HybridWebViewRenderer hybridRenderer;
if(_hybridWebViewRenderer != null && _hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
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);
}
}
}
}

View File

@@ -1,50 +0,0 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

File diff suppressed because it is too large Load Diff

15621
src/Android/Resources/Resource.designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 B

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

Some files were not shown because too many files have changed in this diff Show More