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

Compare commits

...

203 Commits

Author SHA1 Message Date
Kyle Spearrin
3f04b465f3 version bump 2017-05-06 21:31:09 -04:00
Kyle Spearrin
3f5c8fe2cb IdentityHttpClient url fix 2017-05-06 21:21:20 -04:00
Kyle Spearrin
d1cf6c68f3 identity server client for auth 2017-05-06 20:20:57 -04:00
Kyle Spearrin
7117f00480 bump build number 2017-05-03 22:35:45 -04:00
Kyle Spearrin
d4f37343a2 added required NSPhotoLibraryUsageDescription key 2017-05-03 22:25:00 -04:00
Kyle Spearrin
71e15e9cab remove CFBundleExecutable again 2017-05-03 22:01:20 -04:00
Kyle Spearrin
eadf00feba testing add back CFBundleExecutable 2017-05-03 15:37:32 -04:00
Kyle Spearrin
95f28fad2b remove CFBundleExecutable 2017-05-03 15:11:21 -04:00
Kyle Spearrin
9753137a72 version bump 2017-05-03 11:43:56 -04:00
Kyle Spearrin
e4f7436dfb do not animate autofill on mobile
- Animate seems to now cause a JS error when autofilling on iOS, which
stops the password from autofilling. Turn the option off.
2017-05-03 09:53:40 -04:00
Kyle Spearrin
d39211310d make notes taller. autofocus name field on add 2017-05-02 19:41:57 -04:00
Kyle Spearrin
0a6fb3ec0a Comment out test nodes 2017-04-30 17:17:40 -04:00
Kyle Spearrin
5232cf7cec remove beta tag from autofill in tools listing 2017-04-28 12:27:03 -04:00
Kyle Spearrin
6e16ffe05f autofill listing page name for android app fixes 2017-04-28 12:25:29 -04:00
Kyle Spearrin
2d6895aeea android app match fixes 2017-04-28 12:14:53 -04:00
Kyle Spearrin
b5311e1448 moved locked sets to AppSettingsService 2017-04-28 11:34:02 -04:00
Kyle Spearrin
cc63eb383d check that now is > LastActivity Date 2017-04-28 11:19:43 -04:00
Kyle Spearrin
01736ca685 Lock Screen Fixes
- Move settings to AppSettingsService
- Update activity on page disappaearing
- Always check if app is currently locked before updating last activity
date
2017-04-28 11:07:26 -04:00
Kyle Spearrin
be47bb7263 (none) => No folder 2017-04-27 16:46:50 -04:00
Kyle Spearrin
bcb7d88ed7 Double HMAC comparison to prevent timing attacks 2017-04-27 12:14:45 -04:00
Kyle Spearrin
cf58c1b4b5 only fetch keys if there are some orgs 2017-04-26 11:58:52 -04:00
Kyle Spearrin
70c57928e7 Compat. - no header for AesCbc256_B64 cipherstring 2017-04-26 11:28:03 -04:00
Kyle Spearrin
c8219b29c0 encrypted private key and org keys at rest 2017-04-25 16:05:13 -04:00
Kyle Spearrin
15a9f80430 Tools share cell 2017-04-25 14:48:42 -04:00
Kyle Spearrin
0684dfe869 only parse list as URL if dict case fails 2017-04-24 22:22:12 -04:00
Kyle Spearrin
83a89566ac parse url for older extension 2017-04-24 18:05:23 -04:00
Kyle Spearrin
04f486b003 process string for firefox browsers 2017-04-24 17:40:17 -04:00
Kyle Spearrin
f135c92434 add new dependencies to extention container 2017-04-24 16:56:34 -04:00
Kyle Spearrin
78b095d01a new share icon size/color 2017-04-24 16:05:16 -04:00
Kyle Spearrin
1b8bd494e2 disable GA exception reporting 2017-04-24 16:04:54 -04:00
Kyle Spearrin
481925ac78 added share icons to ios project 2017-04-24 15:17:11 -04:00
Kyle Spearrin
4854b2b1c0 share icon on vault listing 2017-04-24 15:00:55 -04:00
Kyle Spearrin
2d7b33459e remove refs to "google" 2017-04-24 14:26:16 -04:00
Kyle Spearrin
27e0c7421b rename CryptoKey to SymmetricCryptoKey 2017-04-22 14:37:01 -04:00
Kyle Spearrin
b26c3d050c sync org keys and refactors 2017-04-21 22:33:09 -04:00
Kyle Spearrin
439370e25a new push notification changes and syncing 2017-04-21 14:57:23 -04:00
Kyle Spearrin
1be4f6e20c add support for rsa oaep sha1 enc type 2017-04-21 13:40:29 -04:00
Kyle Spearrin
2714c7cce9 Added more api uris. lock screen bug in ios ext 2017-04-21 09:12:30 -04:00
Kyle Spearrin
952935de23 copy notes when tapped 2017-04-20 16:07:34 -04:00
Kyle Spearrin
bdb8b5ea39 fix crypto tests 2017-04-20 15:53:17 -04:00
Kyle Spearrin
3ad4e28a2c no inline out 2017-04-20 15:49:25 -04:00
Kyle Spearrin
48d0d068d1 try inline out again 2017-04-20 15:44:51 -04:00
Kyle Spearrin
56e166d61a build engine doesnt like inline out params 2017-04-20 15:38:31 -04:00
Kyle Spearrin
672d753adf update libs 2017-04-20 14:54:39 -04:00
Kyle Spearrin
0d9ba92db4 null check on key retrievals 2017-04-20 14:23:58 -04:00
Kyle Spearrin
8cf25d3602 remove old, unnecessary refs for client handler 2017-04-20 14:23:40 -04:00
Kyle Spearrin
a6bc44dc10 No need for custom handler anymore - xam bug fixed 2017-04-20 14:22:11 -04:00
Kyle Spearrin
408d66ee74 update xamarin forms. empty string section titles
There appears to be a bug regression introduced with the new xamarin
forms that removes headers if there is no title. Hack to fix it for now
is to include a empty string header title.
2017-04-20 14:18:16 -04:00
Kyle Spearrin
b136bb74b8 encrypt with org key if needed 2017-04-20 11:40:39 -04:00
Kyle Spearrin
18b2b6f447 set org keys on login and decrypt org ciphers 2017-04-20 11:23:30 -04:00
Kyle Spearrin
490d1775a2 sync folders & added org id for ciphers/logins 2017-04-20 10:47:14 -04:00
Kyle Spearrin
458de2d2e0 set private key on login 2017-04-20 10:29:18 -04:00
Kyle Spearrin
51ae3fc62f clear keys on logout 2017-04-20 10:20:50 -04:00
Kyle Spearrin
58c5c55d09 extend crypto service for org keys 2017-04-20 10:20:24 -04:00
Kyle Spearrin
4c2bcb9e6b IsNullOrWhiteSpace InitializationVector 2017-04-20 00:10:36 -04:00
Kyle Spearrin
498379bb7e privatekey, rsa decryption, org key management 2017-04-20 00:06:11 -04:00
Kyle Spearrin
e7f3b115a4 refactor for enc type header and cryptokey 2017-04-19 23:16:09 -04:00
Kyle Spearrin
0ebfe85d8e centralize login code into auth service 2017-04-19 22:04:43 -04:00
Kyle Spearrin
8e29a990cb Remove userid from Ga service, not being used 2017-04-19 21:05:03 -04:00
Kyle Spearrin
a960ccd786 IP for desktop from emulator 2017-04-19 20:57:40 -04:00
Kyle Spearrin
6b86e836d7 update target framework 2017-04-19 17:11:06 -04:00
Shan
fb35b9b10a Fixes #8 Disable Google Analytics (#55)
* Opt-out of Google Analytics

* Move OptOut to Other in Settings

* Change OptOut Order and Resource key
2017-03-30 18:22:14 -04:00
Kyle Spearrin
a45773e1ca Update README.md 2017-03-21 18:12:21 -04:00
Kyle Spearrin
2405a6f21e Android version bump 2017-03-11 15:05:09 -05:00
Kyle Spearrin
533dd6135e revert test project to target framework 6.0 2017-03-11 12:36:46 -05:00
Kyle Spearrin
efc25543ca revert to target framework 6 2017-03-11 12:32:44 -05:00
Kyle Spearrin
82d4745da3 catch sql crashes in sync service 2017-03-11 12:26:10 -05:00
Kyle Spearrin
ac6e95c442 Added sbrowser beta to supported browsers list 2017-03-09 20:22:06 -05:00
Kyle Spearrin
375f23ac9e parse uri with Uri.TryCreate 2017-02-25 22:03:18 -05:00
Kyle Spearrin
8e5a01d82c More null checks. Catch null exception in accessibility service. 2017-02-25 16:10:18 -05:00
Kyle Spearrin
910658aa93 android version bump 2017-02-23 23:29:00 -05:00
Kyle Spearrin
d766ffa040 dont null out disposed objects 2017-02-23 23:12:39 -05:00
Kyle Spearrin
b960640e03 version bump 2017-02-22 22:56:08 -05:00
Kyle Spearrin
c984617b1c null out testNodesData 2017-02-22 22:54:18 -05:00
Kyle Spearrin
a12a7127c0 Update README.md
amazon app badge
2017-02-22 19:49:25 -05:00
Kyle Spearrin
98a6a5c93d Added null checking throughout autofill service 2017-02-22 19:00:50 -05:00
Kyle Spearrin
27202fd740 amazon store information 2017-02-22 00:19:42 -05:00
Kyle Spearrin
c01d02de27 dispose nodes instead of manual GC 2017-02-20 18:22:24 -05:00
Kyle Spearrin
1d23bcc979 Update README.md 2017-02-19 23:20:51 -05:00
Kyle Spearrin
ac8abdaa17 readme store badge updates 2017-02-19 23:19:55 -05:00
Kyle Spearrin
613977c6f9 updates to manual GC 2017-02-19 17:29:00 -05:00
Kyle Spearrin
54159c9d05 Do some manual GCing 2017-02-18 21:33:06 -05:00
Kyle Spearrin
8d5d477b4a version bump 2017-02-18 17:47:27 -05:00
Kyle Spearrin
2c73906ad3 fix GetWindowNodes recusion 2017-02-18 15:48:24 -05:00
Kyle Spearrin
079fb34120 pass nodes as reference 2017-02-18 10:50:27 -05:00
Kyle Spearrin
17ed1cdc00 increase autofill toast timeout to 10 seconds 2017-02-18 00:23:47 -05:00
Kyle Spearrin
d53ea584ba Better way of checking for autofill sevrice running 2017-02-17 23:22:02 -05:00
Kyle Spearrin
b435256911 handle locked status better. once locked, stay locked. 2017-02-17 23:03:54 -05:00
Kyle Spearrin
27e996dba0 Detach events 2017-02-17 21:18:59 -05:00
Kyle Spearrin
22f3bd1073 tearing down event handlers on page disappears 2017-02-17 00:16:09 -05:00
Kyle Spearrin
fb564fa817 add support for CM browser 2017-02-16 23:09:40 -05:00
Kyle Spearrin
be9db2930f autofill intent fixes 2017-02-16 22:22:19 -05:00
Kyle Spearrin
5bce95a686 Added support for Yandex browser. Turned push sevrice back on 2017-02-16 21:14:37 -05:00
maxlandry
f6ca9b9d0f Corrections + new french translations (#46)
Various grammar and spelling corrections.
Replace all «sites» mentions with «logins» (identifiants) mentions.
Add and translate lines 760 to 819.
2017-02-16 20:57:06 -05:00
Kyle Spearrin
88f186907b backets for PS commands 2017-02-16 20:05:20 -05:00
Kyle Spearrin
9faf1d9de5 appveyor env checks for powershell commands 2017-02-16 19:57:35 -05:00
Kyle Spearrin
8b1d1d0f6d http ref for ios core 2017-02-15 23:06:26 -05:00
Kyle Spearrin
8c19e2c3f2 system.net.http ref for ios 2017-02-15 23:02:33 -05:00
Kyle Spearrin
d2d8ee504d cached images 2017-02-15 21:56:02 -05:00
Kyle Spearrin
d96b279beb disable push service 2017-02-15 19:55:52 -05:00
Kyle Spearrin
f5e7f9249c attach and detach event handlers onappearing and ondisappearing to free up views for GC 2017-02-15 00:28:05 -05:00
Kyle Spearrin
56c33ee82b Aitpfill fixes for main page set. Memory service for monitoring memory use on Android. 2017-02-14 19:47:00 -05:00
Kyle Spearrin
b05dd4cc2c autofill search UX improvements 2017-02-13 22:35:16 -05:00
Kyle Spearrin
36d4ce8718 more updates to autofill flow 2017-02-13 22:10:34 -05:00
Kyle Spearrin
ddec7ab643 app veyor env checks 2017-02-13 21:57:11 -05:00
Kyle Spearrin
75201c9b30 Added fuzzy matches to autofill listing page. Allow autofilling from main vault search page when arriving from autofill service 2017-02-13 19:12:02 -05:00
Peter Karlsson
99c81e5a5d Swedish translation additional strings update (#39)
* Add files via upload

* Sync

* Swedish translation additional strings update

* Updated short description (too long)
2017-02-11 12:58:14 -05:00
Kyle Spearrin
b84ad39133 appveyor.yml 2017-02-11 01:13:03 -05:00
Kyle Spearrin
4a19e2b673 added max character info to captions 2017-02-11 00:31:23 -05:00
Kyle Spearrin
475c3559f6 new screenshots and caption for google store 2017-02-11 00:14:16 -05:00
Kyle Spearrin
58246f72dd version bump 2017-02-10 19:31:37 -05:00
Kyle Spearrin
b90ce2a2af token refresh bad requests are to be treated as unauthorized 2017-02-10 19:16:23 -05:00
Kyle Spearrin
4a0fc5ca0e crash fixes 2017-02-09 22:06:39 -05:00
Kyle Spearrin
c29d902b8e Autofill service alert when adding new login for the first time and autofill isnt turned on. Added fi language to project. 2017-02-09 21:43:03 -05:00
Kyle Spearrin
ab629c2048 autofill intent is only valid for limited time 2017-02-09 21:06:47 -05:00
Kyle Spearrin
e970ca49e8 Clear intent from autofill. Background app when back button on lock page. 2017-02-09 18:12:34 -05:00
Kyle Spearrin
99e78092ed dont compare the creds uri since it could be a different, equivalent domain 2017-02-09 00:20:29 -05:00
Kyle Spearrin
4af91b5ab6 Update ios extension to use new login service lookup by uristring 2017-02-09 00:12:09 -05:00
Kyle Spearrin
539121070a Added equivalent domain checks to autofill listing filter. centralized logic in login service. 2017-02-08 23:58:37 -05:00
Kyle Spearrin
2a1bd92e1a sync domain settings 2017-02-08 22:04:07 -05:00
Kyle Spearrin
2c1ebc0439 setup settings api repository 2017-02-08 21:19:09 -05:00
Kyle Spearrin
2d605f5dfb remove old sync helper for removing ciphers (was for inc syncing) 2017-02-08 20:45:56 -05:00
Kyle Spearrin
0cd09cf03a setup new settings service 2017-02-08 20:44:35 -05:00
Kyle Spearrin
3ad1e8a3ba set up user settings data table and access repository 2017-02-08 20:39:37 -05:00
Kyle Spearrin
230722945e move settings pages to modals instead of navigation pages 2017-02-08 19:18:34 -05:00
Kyle Spearrin
a429dcf978 Fix wrong key when decrypting cipher with mac 2017-02-08 19:07:38 -05:00
Kyle Spearrin
0131031ac4 Skip event if no package name 2017-02-08 18:19:59 -05:00
Kyle Spearrin
a418fc810a log out when checking account reivison if authentication issue 2017-02-08 00:19:30 -05:00
Kyle Spearrin
e71adbd26d null checks when error handling 2017-02-07 21:56:28 -05:00
Kyle Spearrin
8a525aee8a check old auth bearer for logged in status as well 2017-02-07 21:19:23 -05:00
Kyle Spearrin
463b0fa28a remove incremental syncs and move to full syncs with revision checks 2017-02-06 23:40:24 -05:00
Kyle Spearrin
007ebadf16 removed root var 2017-02-06 22:02:29 -05:00
Kyle Spearrin
c7af81bf0c Cleanup hacks because of Intent LaunchedFromHistory bug 2017-02-06 19:39:07 -05:00
Kyle Spearrin
749508871b Handle all exceptions from API calls 2017-02-06 09:55:35 -05:00
Kyle Spearrin
d112e0ea42 two-factor login re-worked with new auth flow 2017-02-06 09:39:07 -05:00
Kyle Spearrin
54f8771a9c better error parsing 2017-02-06 09:15:10 -05:00
Kyle Spearrin
0a3c83288e Added AutofillService to GA 2017-02-05 23:59:43 -05:00
Kyle Spearrin
52a866147e Optimized startup tasks to only happen when necessary. Added some GA telemetry to autofill. 2017-02-05 23:55:58 -05:00
Igetin
6629eaf485 Added Finnish translations (#37)
* Added strings for Finnish translation

* Added Finnish App Store description

* Added Finnish captions for screenshots

* Added Finnish Play Store description

* Added Finnish captions for screenshots
2017-02-05 07:16:29 -05:00
Kyle Spearrin
74239521cd HandleTokenStateAsync before each API call for refresh and auth bearer migration 2017-02-04 23:31:37 -05:00
Kyle Spearrin
8ae95c4e30 dont read line at end of publisher script 2017-02-04 21:53:56 -05:00
Kyle Spearrin
c31e191d7e add backslashes 2017-02-04 21:40:46 -05:00
Kyle Spearrin
c3134f779d args for increment version script 2017-02-04 21:35:02 -05:00
Kyle Spearrin
d4749c139b increment version script 2017-02-04 21:19:54 -05:00
Kyle Spearrin
63d6c32063 play store creds 2017-02-04 20:52:20 -05:00
Kyle Spearrin
08299902e3 switch to google creds 2017-02-04 19:05:39 -05:00
Kyle Spearrin
db04d6e642 Create google play publisher console application 2017-02-04 12:04:57 -05:00
Kyle Spearrin
6ddbd77009 encrypted keystore for CI builds 2017-02-04 01:33:16 -05:00
Kyle Spearrin
4a4779fc63 Converted auth to identity server endpoints and utilize bearer2 access token 2017-02-04 01:12:25 -05:00
Kyle Spearrin
46bb8d2cb5 added back FromAutofillService functionality 2017-02-03 23:21:40 -05:00
Kyle Spearrin
31b2eeb293 remove lots of mainpage code since we allow closing of autofill page now 2017-02-03 00:26:55 -05:00
Kyle Spearrin
8e9becd579 dont main page on sleep 2017-02-03 00:12:53 -05:00
Kyle Spearrin
d067de086d autofill fixes 2017-02-02 23:36:40 -05:00
Kyle Spearrin
8c6d395d89 remove uri extra after captured 2017-02-02 23:05:24 -05:00
Kyle Spearrin
f66b26a866 beta title 2017-02-02 22:30:34 -05:00
Kyle Spearrin
83f00d69ce added close button to autofill list page. if uri is a website on api level < 21, do not autofill and present modal for copying 2017-02-02 22:20:45 -05:00
Kyle Spearrin
8b2923b56d Add more browser support for fetching URL 2017-02-02 19:39:00 -05:00
Kyle Spearrin
46af313c25 AutoFillServiceDescription 2017-02-01 22:03:35 -05:00
Kyle Spearrin
85dda759ec updated autofill service tools page with new tutorial images 2017-02-01 21:55:00 -05:00
Kyle Spearrin
27fb44277f Accessibility service setup pages 2017-02-01 00:38:35 -05:00
Kyle Spearrin
ea1aafbab2 WIP on accessibility service 2017-01-31 22:53:32 -05:00
Kyle Spearrin
2c446f939e accessibility service WIP 2017-01-31 20:45:51 -05:00
Kyle Spearrin
47e427a851 wip autofill tweaks 2017-01-31 00:30:41 -05:00
Kyle Spearrin
95b8efae20 set color for autofill notification 2017-01-30 23:41:39 -05:00
Kyle Spearrin
53774735d4 autofill wip 2017-01-30 23:33:02 -05:00
Kyle Spearrin
36c6c5a35e Accessibility service WIP 2017-01-30 19:26:39 -05:00
Kyle Spearrin
0beb07c87e Update CONTRIBUTING.md 2017-01-29 11:32:48 -05:00
Kyle Spearrin
64fd8e3be9 autofill service WIP 2017-01-28 23:58:26 -05:00
Kyle Spearrin
45c516ea3f cleanup on autofill 2017-01-27 23:32:48 -05:00
Kyle Spearrin
26667c0a59 autofill WIP into main activity. created login selection page 2017-01-27 23:13:28 -05:00
Kyle Spearrin
61e0379eb3 autofill cleanup WIP 2017-01-23 23:32:52 -05:00
Kyle Spearrin
759df9bdd5 Autofill WIP 2017-01-23 21:28:38 -05:00
Johannes Grönvall
33e7ca08d8 Changes (#32)
Refined the Swedish translations
2017-01-13 08:26:40 -05:00
Primokorn
c3d0d8bf63 Update AppResources.fr.resx (#33) 2017-01-13 08:26:21 -05:00
Kyle Spearrin
8387f1e204 Update packages 2017-01-05 23:54:14 -05:00
Kyle Spearrin
fe778293c1 renaming files for Site => Login refactor 2017-01-03 00:25:17 -05:00
Kyle Spearrin
991afb7722 Reactor rename Sites => Logins 2017-01-03 00:17:15 -05:00
Kyle Spearrin
a176542114 ARM64 architecutre on app extension 2016-12-31 11:47:35 -05:00
Kyle Spearrin
a3f555e816 added new translations for credits page 2016-12-30 22:49:58 -05:00
Kyle Spearrin
dae5453e13 Added translators to credits page 2016-12-30 22:44:17 -05:00
Kyle Spearrin
082826287e Added french translation to the build 2016-12-30 22:39:21 -05:00
Primokorn
7418691cf3 Create french CAPTIONS.md (#28) 2016-12-30 22:28:03 -05:00
Primokorn
29e72de64b Create french COPY.md (#29)
* Create french COPY.md

* Update COPY.md
2016-12-30 22:27:52 -05:00
Primokorn
4955b4a4a8 Create french CAPTIONS.md (#30) 2016-12-30 22:27:12 -05:00
Primokorn
7c76595314 Create french COPY.md (#31) 2016-12-30 22:26:57 -05:00
Primokorn
1495003103 Create AppResources.fr.resx (#27) 2016-12-30 10:42:39 -05:00
Peter Karlsson
fc1b74d48f Fix and missed translations (#26) 2016-12-29 02:39:11 -05:00
Kyle Spearrin
830d0e9e7a readme updates 2016-12-29 00:40:09 -05:00
Kyle Spearrin
7310c06162 readme updates 2016-12-29 00:38:53 -05:00
Kyle Spearrin
045ccaa219 readme updates 2016-12-29 00:26:14 -05:00
Peter Karlsson
9d6a276342 Additional strings update (#25) 2016-12-26 21:31:31 -05:00
Kyle Spearrin
9204d25b62 Applied i18n strings to missing parts in app extension 2016-12-26 21:22:55 -05:00
Kyle Spearrin
6c847292c7 simplified chinese used for all chinese languages for now 2016-12-26 14:38:18 -05:00
Kyle Spearrin
b2712119d1 Chinese support on iOS 2016-12-26 13:39:14 -05:00
Kyle Spearrin
7728046309 layout fixes 2016-12-26 11:30:57 -05:00
Kyle Spearrin
17e18a2a7a Added contains and clear implementations for iOS Settings 2016-12-26 10:49:34 -05:00
Kyle Spearrin
ce8bedb340 zh-Hans fix 2016-12-24 22:44:47 -05:00
Kyle Spearrin
14dc42e148 Fixes for language resources 2016-12-24 22:43:50 -05:00
Peter Karlsson
442c2294e9 Update AppResources.sv.resx (#23) 2016-12-24 22:19:24 -05:00
Peter Karlsson
5334514d55 Swedish translation (#22) 2016-12-24 20:43:06 -05:00
Kyle Spearrin
0d5b431e6a version bump 2016-12-24 11:57:37 -05:00
Kyle Spearrin
8b10ee0028 better error handling in base repo 2016-12-24 11:47:29 -05:00
Kyle Spearrin
9682abdded HttpService abstraction with CustomAndroidClientHandler to handle xamarin android bug with error response body 2016-12-24 10:54:18 -05:00
289 changed files with 10497 additions and 2986 deletions

33
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,33 @@
Code contributions are welcome! Please commit any pull requests against the `master` branch.
# Internationalization (i18n)
If you are interested in helping translate the bitwarden mobile app into another language, please follow these steps
when creating your pull request:
1. Create a new resource file under `/src/App/Resources` by copy/pasting the master English file, `AppResources.resx`.
2. Rename your `AppResources.resx` copy to include the proper .NET culture code for your language (typically the two
letter code, ex. `sv`). You can find a list of culture codes here: <http://timtrott.co.uk/culture-codes/>. For
example, if I want to create a new translation for Swedish, I will rename my `AppResources.resx` copy to
`AppResources.sv.resx`.
3. Open the `AppResources.XX.resx` file for your newly created language and start translating the `<value>` tags for
each `<data>` element. The `<data>` and `<comment>` properties should not be translated and remain in English.
4. Repeat the same process for the store `COPY.md` and `CAPTIONS.md` files in `/store/apple` and `/store/google` by
creating a new folder for your language in each. Do not copy over the `assets` and `screenshots` folders to your new
language. We will update these based on your translations provided in `CAPTIONS.md`. Finally, do not translate the
titles in the markdown files (ex. `# Name` and `# Screenshot 1`). These are only for reference.
5. If you have a Xamarin development environment setup, test your translations to make sure they look correct in the
app on iOS and Android. Sometimes the UI can break due to translations taking up more space than the original UI was
built for. If possible, use a shorter or abbreviated version of the word/sentence to accomedate the available space.
If you are unable to accomedate the avaialable space for a particular translation, just let us know in your pull
request comments. If you are unable to test your translations, just let us know in your pull request comments so
that we can check it for you.
6. Be sure to watch for [future changes](https://github.com/bitwarden/mobile/commits/master/src/App/Resources/AppResources.resx)
to the `/src/App/Resources/AppResources.resx` file so that your translation will stay up to date.
You can find an example of a proper translation pull request here: <https://github.com/bitwarden/mobile/pull/22/files>
You can read more about localizing a Xamarin.Forms app here:
<https://developer.xamarin.com/guides/xamarin-forms/advanced/localization/>
TIP: If you have Visual Studio installed, it provides a nice tabular UI for editing `resx` XML files.

View File

@@ -1,14 +1,27 @@
[![appveyor build](https://ci.appveyor.com/api/projects/status/github/bitwarden/mobile?branch=master&svg=true)] (https://ci.appveyor.com/project/bitwarden/mobile)
[![appveyor build](https://ci.appveyor.com/api/projects/status/github/bitwarden/mobile?branch=master&svg=true)](https://ci.appveyor.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
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://developer.android.com/images/brand/en_generic_rgb_wo_45.png"width="129" height="45"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://linkmaker.itunes.apple.com/images/badges/en-us/badge_appstore-lrg.svg" width="165" height="40"></a>
<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://www.amazon.com/dp/B06XMYGPMV" target="_blank"><img src="https://imgur.com/f75uYeM.png" width="132" height="45"></a>
The bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
# Build/Run
**Requirements**
- [Visual Studio w/ Xamarin -or- Xamarin Studio](https://store.xamarin.com/)
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 API. Open `src/App/Utilities/ApiHttpClient.cs` and set `BaseAddress` to your local
API instance (ex. `new Uri("http://localhost:4000")`).
After restoring the nuget packages, you can now 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.
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.

14
appveyor.yml Normal file
View File

@@ -0,0 +1,14 @@
skip_tags: true
before_build:
- nuget restore
- IF DEFINED keystore_dec_secret nuget install secure-file -ExcludeVersion
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 store\google\Publisher\bin\Debug\Publisher.exe %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

View File

@@ -23,6 +23,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Test", "test\iOS.Test\i
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android.Test", "test\Android.Test\Android.Test.csproj", "{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}"
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}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{428CACAB-CC26-4F41-9062-1E4A9BC82640}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -411,6 +417,54 @@ Global
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.ActiveCfg = Release|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Build.0 = Release|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Deploy.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|Any CPU.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|ARM.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|ARM.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhone.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x64.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x64.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x86.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x86.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|Any CPU.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|ARM.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|ARM.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhone.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|Any CPU.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|Any CPU.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|ARM.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|ARM.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhone.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhone.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x64.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x64.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x86.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -424,5 +478,7 @@ Global
{B2538ADA-B605-4D6F-ACD2-62A409680F84} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{6702027A-F726-4149-863E-7CB924674B9A} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
{428CACAB-CC26-4F41-9062-1E4A9BC82640} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@@ -17,7 +17,7 @@
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
@@ -76,12 +76,10 @@
<Private>True</Private>
</Reference>
<Reference Include="Acr.UserDialogs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Acr.UserDialogs.6.3.2\lib\MonoAndroid10\Acr.UserDialogs.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Acr.UserDialogs.6.3.10\lib\MonoAndroid10\Acr.UserDialogs.dll</HintPath>
</Reference>
<Reference Include="Acr.UserDialogs.Interface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Acr.UserDialogs.6.3.2\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Acr.UserDialogs.6.3.10\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll</HintPath>
</Reference>
<Reference Include="AndHUD, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\AndHUD.1.2.0\lib\MonoAndroid\AndHUD.dll</HintPath>
@@ -91,17 +89,26 @@
<HintPath>..\..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FFImageLoading, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.dll</HintPath>
</Reference>
<Reference Include="FFImageLoading.Forms, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.dll</HintPath>
</Reference>
<Reference Include="FFImageLoading.Forms.Droid, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\MonoAndroid10\FFImageLoading.Forms.Droid.dll</HintPath>
</Reference>
<Reference Include="FFImageLoading.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.Platform.dll</HintPath>
</Reference>
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
</Reference>
<Reference Include="HockeySDK, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0\lib\MonoAndroid403\HockeySDK.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\MonoAndroid403\HockeySDK.dll</HintPath>
</Reference>
<Reference Include="HockeySDK.AndroidBindings, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0\lib\MonoAndroid403\HockeySDK.AndroidBindings.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\MonoAndroid403\HockeySDK.AndroidBindings.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
@@ -137,13 +144,11 @@
<HintPath>..\..\packages\PInvoke.Windows.Core.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Connectivity, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Connectivity, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
@@ -157,13 +162,11 @@
<HintPath>..\..\packages\Plugin.Fingerprint.1.2.0\lib\MonoAndroid\Plugin.Fingerprint.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Settings, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Settings, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.dll</HintPath>
@@ -194,27 +197,28 @@
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.1\lib\MonoAndroid\SQLitePCLRaw.batteries_green.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\MonoAndroid\SQLitePCLRaw.batteries_green.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.1\lib\MonoAndroid\SQLitePCLRaw.batteries_v2.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\MonoAndroid\SQLitePCLRaw.batteries_v2.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.1\lib\MonoAndroid\SQLitePCLRaw.core.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.2\lib\MonoAndroid\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.lib.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4ad490600e2234c, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.lib.e_sqlite3.android.1.1.1\lib\MonoAndroid\SQLitePCLRaw.lib.e_sqlite3.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.lib.e_sqlite3.android.1.1.2\lib\MonoAndroid\SQLitePCLRaw.lib.e_sqlite3.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.android.1.1.1\lib\MonoAndroid\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.android.1.1.2\lib\MonoAndroid\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="Validation, Version=2.3.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
<HintPath>..\..\packages\Validation.2.3.7\lib\dotnet\Validation.dll</HintPath>
<Private>True</Private>
@@ -252,20 +256,16 @@
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Analytics, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Analytics.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Analytics.dll</HintPath>
@@ -298,6 +298,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AutofillActivity.cs" />
<Compile Include="AutofillCredentials.cs" />
<Compile Include="Controls\CustomSearchBarRenderer.cs" />
<Compile Include="Controls\CustomButtonRenderer.cs" />
<Compile Include="Controls\ExtendedButtonRenderer.cs" />
@@ -311,6 +312,7 @@
<Compile Include="Controls\ExtendedTextCellRenderer.cs" />
<Compile Include="Controls\ExtendedPickerRenderer.cs" />
<Compile Include="Controls\ExtendedEntryRenderer.cs" />
<Compile Include="Services\HttpService.cs" />
<Compile Include="Services\LocalizeService.cs" />
<Compile Include="MainApplication.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
@@ -323,14 +325,17 @@
<Compile Include="MainActivity.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\LogService.cs" />
<Compile Include="Services\MemoryService.cs" />
<Compile Include="Services\ReflectionService.cs" />
<Compile Include="Services\SqlService.cs" />
<Compile Include="SplashActivity.cs" />
</ItemGroup>
<ItemGroup>
<None Include="8bit.keystore.enc" />
<None Include="app.config">
<SubType>Designer</SubType>
</None>
<None Include="increment-version.ps1" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
@@ -740,7 +745,115 @@
<AndroidResource Include="Resources\drawable\icon.png" />
</ItemGroup>
<ItemGroup>
<AndroidEnvironment Include="EnvironmentVariables.txt" />
<AndroidResource Include="Resources\drawable\notification_sm.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\notification_sm.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\notification_sm.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\notification_sm.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\notification_sm.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\accessibility_step1.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\accessibility_step2.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step1.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step1.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step1.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_step2.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_step2.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\accessibility_step2.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_notification.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_notification.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\accessibility_notification.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\accessibility_notification.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\accessibility_notification_icon.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\accessibility_notification_icon.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\accessibility_notification_icon.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\accessibility_notification_icon.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\search.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\share.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\share.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\share.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\share.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\share.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\share_tools.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\share_tools.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\share_tools.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\share_tools.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\share_tools.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
@@ -750,10 +863,10 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
</Target>
<Import Project="..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets" Condition="Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@@ -1,58 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Bit.App.Models;
namespace Bit.Android
{
//[Activity(Label = "Autofill", LaunchMode = global::Android.Content.PM.LaunchMode.SingleInstance, Theme = "@style/android:Theme.Material.Light")]
[Activity(Theme = "@style/BitwardenTheme.Splash",
Label = "bitwarden",
Icon = "@drawable/icon",
WindowSoftInputMode = SoftInput.StateHidden)]
public class AutofillActivity : Activity
{
private string _lastQueriedUri;
public static AutofillCredentials LastCredentials { get; set; }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
var url = Intent.GetStringExtra("url");
_lastQueriedUrl = url;
//StartActivityForResult(Kp2aControl.GetQueryEntryIntent(url), 123);
LaunchMainActivity(Intent, 932473);
}
string _lastQueriedUrl;
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
LaunchMainActivity(intent, 489729);
}
protected override void OnDestroy()
{
base.OnDestroy();
}
protected override void OnResume()
{
base.OnResume();
if(!Intent.HasExtra("uri"))
{
Finish();
return;
}
Intent.RemoveExtra("uri");
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(data == null)
{
LastCredentials = null;
}
else
{
try
{
if(data.GetStringExtra("canceled") != null)
{
LastCredentials = null;
}
else
{
var uri = data.GetStringExtra("uri");
var username = data.GetStringExtra("username");
var password = data.GetStringExtra("password");
try
{
// TODO: lookup site
LastReceivedCredentials = new Credentials { User = "username", Password = "12345678", Url = _lastQueriedUrl };
LastCredentials = new AutofillCredentials
{
Username = username,
Password = password,
Uri = uri,
LastUri = _lastQueriedUri
};
}
}
catch
{
LastCredentials = null;
}
}
catch(Exception e)
{
//Android.Util.Log.Debug("KP2AAS", "Exception while receiving credentials: " + e.ToString());
}
finally
Finish();
}
private void LaunchMainActivity(Intent callingIntent, int requestCode)
{
_lastQueriedUri = callingIntent?.GetStringExtra("uri");
if(_lastQueriedUri == null)
{
Finish();
return;
}
}
public static Credentials LastReceivedCredentials;
public class Credentials
{
public string User;
public string Password;
public string Url;
var intent = new Intent(this, typeof(MainActivity));
if(!callingIntent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
{
intent.PutExtra("uri", _lastQueriedUri);
}
StartActivityForResult(intent, requestCode);
}
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Bit.Android
{
public class AutofillCredentials
{
public string Username { get; set; }
public string Password { get; set; }
public string Uri { get; set; }
public string LastUri { get; set; }
}
}

View File

@@ -1,105 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.AccessibilityServices;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Views.Accessibility;
using Android.Widget;
namespace Bit.Android
{
//[Service(Permission = "android.permission.BIND_ACCESSIBILITY_SERVICE", Label = "bitwarden")]
//[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
//[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
[Service(Permission = "android.permission.BIND_ACCESSIBILITY_SERVICE", Label = "bitwarden")]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
public class AutofillService : AccessibilityService
{
private const int autoFillNotificationId = 0;
private const string androidAppPrefix = "androidapp://";
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.iron.srware", "url_bar"),
new Browser("com.sec.android.app.sbrowser", "sbrowser_url_bar"),
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("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")
}.ToDictionary(n => n.PackageName);
public override void OnAccessibilityEvent(AccessibilityEvent e)
{
var eventType = e.EventType;
var package = e.PackageName;
switch(eventType)
try
{
case EventTypes.ViewTextSelectionChanged:
//if(e.Source.Password && string.IsNullOrWhiteSpace(e.Source.Text))
//{
// var bundle = new Bundle();
// bundle.PutCharSequence(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, "mypassword");
// e.Source.PerformAction(global::Android.Views.Accessibility.Action.SetText, bundle);
//}
break;
case EventTypes.WindowContentChanged:
case EventTypes.WindowStateChanged:
if(e.PackageName == "com.android.systemui")
{
break;
}
var root = RootInActiveWindow;
if((ExistsNodeOrChildren(root, n => n.WindowId == e.WindowId) && !ExistsNodeOrChildren(root, n => (n.ViewIdResourceName != null) && (n.ViewIdResourceName.StartsWith("com.android.systemui")))))
{
bool cancelNotification = true;
var root = RootInActiveWindow;
if(e == null || root == null || string.IsNullOrWhiteSpace(e.PackageName) ||
e.PackageName == SystemUiPackage || root.PackageName != e.PackageName)
{
return;
}
var allEditTexts = GetNodeOrChildren(root, n => { return IsEditText(n); });
/*
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 usernameEdit = allEditTexts.TakeWhile(edit => (edit.Password == false)).LastOrDefault();
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
switch(e.EventType)
{
case EventTypes.WindowContentChanged:
case EventTypes.WindowStateChanged:
var cancelNotification = true;
string searchString = androidAppPrefix + root.PackageName;
string url = androidAppPrefix + root.PackageName;
if(root.PackageName == "com.android.chrome")
if(e.PackageName == BitwardenPackage)
{
var addressField = root.FindAccessibilityNodeInfosByViewId("com.android.chrome:id/url_bar").FirstOrDefault();
UrlFromAddressField(ref url, addressField);
}
else if(root.PackageName == "com.android.browser")
{
var addressField = root.FindAccessibilityNodeInfosByViewId("com.android.browser:id/url").FirstOrDefault();
UrlFromAddressField(ref url, addressField);
notificationManager?.Cancel(AutoFillNotificationId);
break;
}
var emptyPasswordFields = GetNodeOrChildren(root, n => { return IsPasswordField(n); }).ToList();
if(emptyPasswordFields.Any())
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
if(passwordNodes.Count > 0)
{
if((AutofillActivity.LastReceivedCredentials != null) && IsSame(AutofillActivity.LastReceivedCredentials.Url, url))
var uri = GetUri(root);
if(uri != null && !uri.Contains(BitwardenWebsite))
{
//Android.Util.Log.Debug("KP2AAS", "Filling credentials for " + url);
FillPassword(url, usernameEdit, emptyPasswordFields);
}
else
{
//Android.Util.Log.Debug("KP2AAS", "Notif for " + url);
if(AutofillActivity.LastReceivedCredentials != null)
if(NeedToAutofill(AutofillActivity.LastCredentials, uri))
{
//Android.Util.Log.Debug("KP2AAS", LookupCredentialsActivity.LastReceivedCredentials.Url);
//Android.Util.Log.Debug("KP2AAS", url);
}
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
FillCredentials(usernameEditText, passwordNodes);
AskFillPassword(url, usernameEdit, emptyPasswordFields);
cancelNotification = false;
allEditTexts.Dispose();
usernameEditText.Dispose();
}
else
{
NotifyToAutofill(uri, notificationManager);
cancelNotification = false;
}
}
AutofillActivity.LastCredentials = null;
}
passwordNodes.Dispose();
if(cancelNotification)
{
((NotificationManager)GetSystemService(NotificationService)).Cancel(autoFillNotificationId);
//Android.Util.Log.Debug("KP2AAS", "Cancel notif");
notificationManager?.Cancel(AutoFillNotificationId);
}
}
break;
default:
break;
break;
default:
break;
}
notificationManager?.Dispose();
root.Dispose();
e.Dispose();
}
// Some unknown condition is causing NullReferenceException's in production. Suppress it for now.
catch(NullReferenceException) { }
}
public override void OnInterrupt()
@@ -107,123 +131,190 @@ namespace Bit.Android
}
private static void UrlFromAddressField(ref string url, AccessibilityNodeInfo addressField)
private string GetUri(AccessibilityNodeInfo root)
{
if(addressField != null)
var uri = string.Concat(App.Constants.AndroidAppProtocol, root.PackageName);
if(SupportedBrowsers.ContainsKey(root.PackageName))
{
url = addressField.Text;
if(!url.Contains("://"))
url = "http://" + url;
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 bool IsSame(string url1, string url2)
private string ExtractUri(string uri, AccessibilityNodeInfo addressNode, Browser browser)
{
if(url1.StartsWith("androidapp://"))
return url1 == url2;
//return KeePassLib.Utility.UrlUtil.GetHost(url1) == KeePassLib.Utility.UrlUtil.GetHost(url2);
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 IsPasswordField(AccessibilityNodeInfo n)
private static bool EditText(AccessibilityNodeInfo n)
{
//if (n.Password) Android.Util.Log.Debug(_logTag, "pwdx with " + (n.Text == null ? "null" : n.Text));
var res = n.Password && string.IsNullOrEmpty(n.Text);
// if (n.Password) Android.Util.Log.Debug(_logTag, "pwd with " + n.Text + res);
return res;
return n?.ClassName?.Contains("EditText") ?? false;
}
private static bool IsEditText(AccessibilityNodeInfo n)
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
{
//it seems like n.Editable is not a good check as this is false for some fields which are actually editable, at least in tests with Chrome.
return (n.ClassName != null) && (n.ClassName.Contains("EditText"));
}
private void AskFillPassword(string url, AccessibilityNodeInfo usernameEdit, IEnumerable<AccessibilityNodeInfo> passwordFields)
{
var runSearchIntent = new Intent(this, typeof(AutofillActivity));
runSearchIntent.PutExtra("url", url);
runSearchIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pending = PendingIntent.GetActivity(this, 0, runSearchIntent, PendingIntentFlags.UpdateCurrent);
var targetName = url;
if(url.StartsWith(androidAppPrefix))
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
{
var packageName = url.Substring(androidAppPrefix.Length);
try
{
var appInfo = PackageManager.GetApplicationInfo(packageName, 0);
targetName = (string)(appInfo != null ? PackageManager.GetApplicationLabel(appInfo) : packageName);
}
catch(Exception e)
{
//Android.Util.Log.Debug(_logTag, e.ToString());
targetName = packageName;
}
}
else
{
//targetName = KeePassLib.Utility.UrlUtil.GetHost(url);
return;
}
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 builder = new Notification.Builder(this);
//TODO icon
//TODO plugin icon
builder.SetSmallIcon(Resource.Drawable.icon)
.SetContentText("Content Text")
.SetContentTitle("Content Title")
builder.SetSmallIcon(Resource.Drawable.notification_sm)
.SetContentTitle(App.Resources.AppResources.BitwardenAutofillService)
.SetContentText(App.Resources.AppResources.BitwardenAutofillServiceNotificationContent)
.SetTicker(App.Resources.AppResources.BitwardenAutofillServiceNotificationContent)
.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis())
.SetTicker("Ticker Text")
.SetVisibility(NotificationVisibility.Secret)
.SetContentIntent(pending);
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(autoFillNotificationId, builder.Build());
.SetContentIntent(pendingIntent);
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch)
{
builder.SetVisibility(NotificationVisibility.Secret)
.SetColor(global::Android.Support.V4.Content.ContextCompat.GetColor(ApplicationContext,
Resource.Color.primary));
}
notificationManager.Notify(AutoFillNotificationId, builder.Build());
builder.Dispose();
}
private void FillPassword(string url, AccessibilityNodeInfo usernameEdit, IEnumerable<AccessibilityNodeInfo> passwordFields)
private void FillCredentials(AccessibilityNodeInfo usernameNode, IEnumerable<AccessibilityNodeInfo> passwordNodes)
{
FillDataInTextField(usernameEdit, AutofillActivity.LastReceivedCredentials.User);
foreach(var pwd in passwordFields)
FillDataInTextField(pwd, AutofillActivity.LastReceivedCredentials.Password);
AutofillActivity.LastReceivedCredentials = null;
FillEditText(usernameNode, AutofillActivity.LastCredentials?.Username);
foreach(var n in passwordNodes)
{
FillEditText(n, AutofillActivity.LastCredentials?.Password);
}
}
private static void FillDataInTextField(AccessibilityNodeInfo edit, string newValue)
private static void FillEditText(AccessibilityNodeInfo editTextNode, string value)
{
Bundle b = new Bundle();
b.PutString(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, newValue);
edit.PerformAction(global::Android.Views.Accessibility.Action.SetText, b);
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 bool ExistsNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
private NodeList GetWindowNodes(AccessibilityNodeInfo n, AccessibilityEvent e,
Func<AccessibilityNodeInfo, bool> condition, bool disposeIfUnused, NodeList nodes = null)
{
return GetNodeOrChildren(n, p).Any();
}
if(nodes == null)
{
nodes = new NodeList();
}
private IEnumerable<AccessibilityNodeInfo> GetNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
{
if(n != null)
{
if(p(n))
var dispose = disposeIfUnused;
if(n.WindowId == e.WindowId && !(n.ViewIdResourceName?.StartsWith(SystemUiPackage) ?? false) && condition(n))
{
yield return n;
dispose = false;
nodes.Add(n);
}
for(int i = 0; i < n.ChildCount; i++)
for(var i = 0; i < n.ChildCount; i++)
{
foreach(var x in GetNodeOrChildren(n.GetChild(i), p))
{
yield return x;
}
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

@@ -18,13 +18,15 @@ namespace Bit.Android.Controls
{
private bool _isPassword;
private bool _toggledPassword;
private bool _isDisposed;
private ExtendedEntry _view;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var view = (ExtendedEntry)Element;
_isPassword = view.IsPassword;
_view = (ExtendedEntry)Element;
_isPassword = _view.IsPassword;
if(Control != null)
{
@@ -36,69 +38,74 @@ namespace Bit.Android.Controls
}
}
SetBorder(view);
SetMaxLength(view);
SetReturnType(view);
SetBorder(_view);
SetMaxLength(_view);
SetReturnType(_view);
// Editor Action is called when the return button is pressed
Control.EditorAction += (object sender, TextView.EditorActionEventArgs args) =>
{
if(view.ReturnType != ReturnType.Next)
{
view.Unfocus();
}
Control.EditorAction += Control_EditorAction;
// Call all the methods attached to base_entry event handler Completed
view.InvokeCompleted();
};
if(view.DisableAutocapitalize)
if(_view.DisableAutocapitalize)
{
Control.SetRawInputType(Control.InputType |= InputTypes.TextVariationEmailAddress);
}
if(view.Autocorrect.HasValue)
if(_view.Autocorrect.HasValue)
{
Control.SetRawInputType(Control.InputType |= InputTypes.TextFlagNoSuggestions);
}
view.ToggleIsPassword += (object sender, EventArgs args) =>
{
var cursorStart = Control.SelectionStart;
var cursorEnd = Control.SelectionEnd;
_view.ToggleIsPassword += ToggleIsPassword;
Control.TransformationMethod = _isPassword ? null : new PasswordTransformationMethod();
// 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 app = XLabs.Ioc.Resolver.Resolve<global::Android.App.Application>();
var inputMethodManager =
app.GetSystemService(global::Android.Content.Context.InputMethodService) as InputMethodManager;
inputMethodManager.ShowSoftInput(Control, ShowFlags.Forced);
inputMethodManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
_isPassword = view.IsPasswordFromToggled = !_isPassword;
_toggledPassword = true;
};
if(view.FontFamily == "monospace")
if(_view.FontFamily == "monospace")
{
Control.Typeface = Typeface.Monospace;
}
}
private void ToggleIsPassword(object sender, EventArgs e)
{
var cursorStart = Control.SelectionStart;
var cursorEnd = Control.SelectionEnd;
Control.TransformationMethod = _isPassword ? null : new PasswordTransformationMethod();
// 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 app = XLabs.Ioc.Resolver.Resolve<global::Android.App.Application>();
var inputMethodManager =
app.GetSystemService(global::Android.Content.Context.InputMethodService) as InputMethodManager;
inputMethodManager.ShowSoftInput(Control, ShowFlags.Forced);
inputMethodManager.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;
@@ -124,6 +131,23 @@ namespace Bit.Android.Controls
}
}
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)

View File

@@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using Bit.Android.Controls;
using Bit.App.Controls;
using Xamarin.Forms;

View File

@@ -1 +0,0 @@
XA_HTTP_CLIENT_HANDLER_TYPE=Xamarin.Android.Net.AndroidClientHandler

View File

@@ -14,6 +14,7 @@ using System.Reflection;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using System.Threading.Tasks;
using Bit.App.Models.Page;
namespace Bit.Android
{
@@ -27,6 +28,12 @@ namespace Bit.Android
protected override void OnCreate(Bundle bundle)
{
var uri = Intent.GetStringExtra("uri");
if(!Resolver.IsSet)
{
MainApplication.SetIoc(Application);
}
var policy = new StrictMode.ThreadPolicy.Builder().PermitAll().Build();
StrictMode.SetThreadPolicy(policy);
@@ -54,8 +61,8 @@ namespace Bit.Android
typeof(Color).GetProperty("Accent", BindingFlags.Public | BindingFlags.Static)
.SetValue(null, Color.FromHex("d2d6de"));
LoadApplication(new App.App(
uri,
Resolver.Resolve<IAuthService>(),
Resolver.Resolve<IConnectivity>(),
Resolver.Resolve<IUserDialogs>(),
@@ -65,12 +72,56 @@ namespace Bit.Android
Resolver.Resolve<ISettings>(),
Resolver.Resolve<ILockService>(),
Resolver.Resolve<IGoogleAnalyticsService>(),
Resolver.Resolve<ILocalizeService>()));
Resolver.Resolve<ILocalizeService>(),
Resolver.Resolve<IAppInfoService>(),
Resolver.Resolve<IAppSettingsService>()));
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, "RateApp", (sender) =>
{
RateApp();
});
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, "Accessibility", (sender) =>
{
OpenAccessibilitySettings();
});
MessagingCenter.Subscribe<Xamarin.Forms.Application, VaultListPageModel.Login>(
Xamarin.Forms.Application.Current, "Autofill", (sender, args) =>
{
ReturnCredentials(args);
});
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, "BackgroundApp", (sender) =>
{
MoveTaskToBack(true);
});
}
private void ReturnCredentials(VaultListPageModel.Login login)
{
Intent data = new Intent();
if(login == null)
{
data.PutExtra("canceled", "true");
}
else
{
data.PutExtra("uri", login.Uri.Value);
data.PutExtra("username", login.Username);
data.PutExtra("password", login.Password.Value);
}
if(Parent == null)
{
SetResult(Result.Ok, data);
}
else
{
Parent.SetResult(Result.Ok, data);
}
Finish();
}
protected override void OnPause()
@@ -105,8 +156,12 @@ namespace Bit.Android
protected override void OnResume()
{
Console.WriteLine("A 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();
}
public void RateApp()
@@ -140,5 +195,11 @@ namespace Bit.Android
intent.AddFlags(flags);
return intent;
}
private void OpenAccessibilitySettings()
{
var intent = new Intent(global::Android.Provider.Settings.ActionAccessibilitySettings);
StartActivity(intent);
}
}
}

View File

@@ -20,6 +20,7 @@ using XLabs.Ioc.Unity;
using System.Threading.Tasks;
using Plugin.Settings.Abstractions;
using Xamarin.Android.Net;
using FFImageLoading.Forms.Droid;
namespace Bit.Android
{
@@ -38,12 +39,9 @@ namespace Bit.Android
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
// NOTE: This is just here to stop the linker from removing AndroidClientHandler references
var handler = new AndroidClientHandler();
if(!Resolver.IsSet)
{
SetIoc();
SetIoc(this);
}
}
@@ -178,16 +176,16 @@ namespace Bit.Android
}
}
private void SetIoc()
public static void SetIoc(Application application)
{
UserDialogs.Init(this);
UserDialogs.Init(application);
var container = new UnityContainer();
container
// Android Stuff
.RegisterInstance(ApplicationContext)
.RegisterInstance<Application>(this)
.RegisterInstance(application.ApplicationContext)
.RegisterInstance<Application>(application)
// Services
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
@@ -196,7 +194,7 @@ namespace Bit.Android
.RegisterType<IKeyDerivationService, BouncyCastleKeyDerivationService>(new ContainerControlledLifetimeManager())
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
.RegisterType<IFolderService, FolderService>(new ContainerControlledLifetimeManager())
.RegisterType<ISiteService, SiteService>(new ContainerControlledLifetimeManager())
.RegisterType<ILoginService, LoginService>(new ContainerControlledLifetimeManager())
.RegisterType<ISyncService, SyncService>(new ContainerControlledLifetimeManager())
.RegisterType<IClipboardService, ClipboardService>(new ContainerControlledLifetimeManager())
.RegisterType<IPushNotificationListener, PushNotificationListener>(new ContainerControlledLifetimeManager())
@@ -209,15 +207,22 @@ namespace Bit.Android
.RegisterType<IDeviceInfoService, DeviceInfoService>(new ContainerControlledLifetimeManager())
.RegisterType<ILocalizeService, LocalizeService>(new ContainerControlledLifetimeManager())
.RegisterType<ILogService, LogService>(new ContainerControlledLifetimeManager())
.RegisterType<IHttpService, HttpService>(new ContainerControlledLifetimeManager())
.RegisterType<ITokenService, TokenService>(new ContainerControlledLifetimeManager())
.RegisterType<ISettingsService, SettingsService>(new ContainerControlledLifetimeManager())
.RegisterType<IMemoryService, MemoryService>(new ContainerControlledLifetimeManager())
.RegisterType<IAppSettingsService, AppSettingsService>(new ContainerControlledLifetimeManager())
// Repositories
.RegisterType<IFolderRepository, FolderRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IFolderApiRepository, FolderApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ISiteRepository, SiteRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ISiteApiRepository, SiteApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IAuthApiRepository, AuthApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ILoginRepository, LoginRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ILoginApiRepository, LoginApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IConnectApiRepository, ConnectApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IDeviceApiRepository, DeviceApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IAccountsApiRepository, AccountsApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ICipherApiRepository, CipherApiRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ISettingsRepository, SettingsRepository>(new ContainerControlledLifetimeManager())
.RegisterType<ISettingsApiRepository, SettingsApiRepository>(new ContainerControlledLifetimeManager())
// Other
.RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager())
.RegisterInstance(CrossConnectivity.Current, new ContainerControlledLifetimeManager())
@@ -226,6 +231,7 @@ namespace Bit.Android
CrossPushNotification.Initialize(container.Resolve<IPushNotificationListener>(), "962181367620");
container.RegisterInstance(CrossPushNotification.Current, new ContainerControlledLifetimeManager());
CachedImageRenderer.Init();
Resolver.SetResolver(new UnityResolver(container));
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);

View File

@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.2.0" android:installLocation="auto" android:versionCode="9">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application android:label="bitwarden" android:theme="@style/BitwardenTheme"></application>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.5.1" android:installLocation="auto" android:versionCode="502">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application android:label="bitwarden" android:theme="@style/BitwardenTheme">
</application>
</manifest>

View File

@@ -2281,487 +2281,511 @@ namespace Bit.Android
public const int abc_textfield_search_material = 2130837578;
// aapt resource value: 0x7f02004b
public const int cloudup = 2130837579;
public const int accessibility_notification = 2130837579;
// aapt resource value: 0x7f02004c
public const int cogs = 2130837580;
public const int accessibility_notification_icon = 2130837580;
// aapt resource value: 0x7f02004d
public const int cogs_selected = 2130837581;
public const int accessibility_step1 = 2130837581;
// aapt resource value: 0x7f02004e
public const int common_full_open_on_phone = 2130837582;
public const int accessibility_step2 = 2130837582;
// aapt resource value: 0x7f02004f
public const int common_google_signin_btn_icon_dark = 2130837583;
public const int cloudup = 2130837583;
// aapt resource value: 0x7f020050
public const int common_google_signin_btn_icon_dark_disabled = 2130837584;
public const int cogs = 2130837584;
// aapt resource value: 0x7f020051
public const int common_google_signin_btn_icon_dark_focused = 2130837585;
public const int cogs_selected = 2130837585;
// aapt resource value: 0x7f020052
public const int common_google_signin_btn_icon_dark_normal = 2130837586;
public const int common_full_open_on_phone = 2130837586;
// aapt resource value: 0x7f020053
public const int common_google_signin_btn_icon_dark_pressed = 2130837587;
public const int common_google_signin_btn_icon_dark = 2130837587;
// aapt resource value: 0x7f020054
public const int common_google_signin_btn_icon_light = 2130837588;
public const int common_google_signin_btn_icon_dark_disabled = 2130837588;
// aapt resource value: 0x7f020055
public const int common_google_signin_btn_icon_light_disabled = 2130837589;
public const int common_google_signin_btn_icon_dark_focused = 2130837589;
// aapt resource value: 0x7f020056
public const int common_google_signin_btn_icon_light_focused = 2130837590;
public const int common_google_signin_btn_icon_dark_normal = 2130837590;
// aapt resource value: 0x7f020057
public const int common_google_signin_btn_icon_light_normal = 2130837591;
public const int common_google_signin_btn_icon_dark_pressed = 2130837591;
// aapt resource value: 0x7f020058
public const int common_google_signin_btn_icon_light_pressed = 2130837592;
public const int common_google_signin_btn_icon_light = 2130837592;
// aapt resource value: 0x7f020059
public const int common_google_signin_btn_text_dark = 2130837593;
public const int common_google_signin_btn_icon_light_disabled = 2130837593;
// aapt resource value: 0x7f02005a
public const int common_google_signin_btn_text_dark_disabled = 2130837594;
public const int common_google_signin_btn_icon_light_focused = 2130837594;
// aapt resource value: 0x7f02005b
public const int common_google_signin_btn_text_dark_focused = 2130837595;
public const int common_google_signin_btn_icon_light_normal = 2130837595;
// aapt resource value: 0x7f02005c
public const int common_google_signin_btn_text_dark_normal = 2130837596;
public const int common_google_signin_btn_icon_light_pressed = 2130837596;
// aapt resource value: 0x7f02005d
public const int common_google_signin_btn_text_dark_pressed = 2130837597;
public const int common_google_signin_btn_text_dark = 2130837597;
// aapt resource value: 0x7f02005e
public const int common_google_signin_btn_text_light = 2130837598;
public const int common_google_signin_btn_text_dark_disabled = 2130837598;
// aapt resource value: 0x7f02005f
public const int common_google_signin_btn_text_light_disabled = 2130837599;
public const int common_google_signin_btn_text_dark_focused = 2130837599;
// aapt resource value: 0x7f020060
public const int common_google_signin_btn_text_light_focused = 2130837600;
public const int common_google_signin_btn_text_dark_normal = 2130837600;
// aapt resource value: 0x7f020061
public const int common_google_signin_btn_text_light_normal = 2130837601;
public const int common_google_signin_btn_text_dark_pressed = 2130837601;
// aapt resource value: 0x7f020062
public const int common_google_signin_btn_text_light_pressed = 2130837602;
public const int common_google_signin_btn_text_light = 2130837602;
// aapt resource value: 0x7f020063
public const int common_ic_googleplayservices = 2130837603;
public const int common_google_signin_btn_text_light_disabled = 2130837603;
// aapt resource value: 0x7f020064
public const int common_plus_signin_btn_icon_dark = 2130837604;
public const int common_google_signin_btn_text_light_focused = 2130837604;
// aapt resource value: 0x7f020065
public const int common_plus_signin_btn_icon_dark_disabled = 2130837605;
public const int common_google_signin_btn_text_light_normal = 2130837605;
// aapt resource value: 0x7f020066
public const int common_plus_signin_btn_icon_dark_focused = 2130837606;
public const int common_google_signin_btn_text_light_pressed = 2130837606;
// aapt resource value: 0x7f020067
public const int common_plus_signin_btn_icon_dark_normal = 2130837607;
public const int common_ic_googleplayservices = 2130837607;
// aapt resource value: 0x7f020068
public const int common_plus_signin_btn_icon_dark_pressed = 2130837608;
public const int common_plus_signin_btn_icon_dark = 2130837608;
// aapt resource value: 0x7f020069
public const int common_plus_signin_btn_icon_light = 2130837609;
public const int common_plus_signin_btn_icon_dark_disabled = 2130837609;
// aapt resource value: 0x7f02006a
public const int common_plus_signin_btn_icon_light_disabled = 2130837610;
public const int common_plus_signin_btn_icon_dark_focused = 2130837610;
// aapt resource value: 0x7f02006b
public const int common_plus_signin_btn_icon_light_focused = 2130837611;
public const int common_plus_signin_btn_icon_dark_normal = 2130837611;
// aapt resource value: 0x7f02006c
public const int common_plus_signin_btn_icon_light_normal = 2130837612;
public const int common_plus_signin_btn_icon_dark_pressed = 2130837612;
// aapt resource value: 0x7f02006d
public const int common_plus_signin_btn_icon_light_pressed = 2130837613;
public const int common_plus_signin_btn_icon_light = 2130837613;
// aapt resource value: 0x7f02006e
public const int common_plus_signin_btn_text_dark = 2130837614;
public const int common_plus_signin_btn_icon_light_disabled = 2130837614;
// aapt resource value: 0x7f02006f
public const int common_plus_signin_btn_text_dark_disabled = 2130837615;
public const int common_plus_signin_btn_icon_light_focused = 2130837615;
// aapt resource value: 0x7f020070
public const int common_plus_signin_btn_text_dark_focused = 2130837616;
public const int common_plus_signin_btn_icon_light_normal = 2130837616;
// aapt resource value: 0x7f020071
public const int common_plus_signin_btn_text_dark_normal = 2130837617;
public const int common_plus_signin_btn_icon_light_pressed = 2130837617;
// aapt resource value: 0x7f020072
public const int common_plus_signin_btn_text_dark_pressed = 2130837618;
public const int common_plus_signin_btn_text_dark = 2130837618;
// aapt resource value: 0x7f020073
public const int common_plus_signin_btn_text_light = 2130837619;
public const int common_plus_signin_btn_text_dark_disabled = 2130837619;
// aapt resource value: 0x7f020074
public const int common_plus_signin_btn_text_light_disabled = 2130837620;
public const int common_plus_signin_btn_text_dark_focused = 2130837620;
// aapt resource value: 0x7f020075
public const int common_plus_signin_btn_text_light_focused = 2130837621;
public const int common_plus_signin_btn_text_dark_normal = 2130837621;
// aapt resource value: 0x7f020076
public const int common_plus_signin_btn_text_light_normal = 2130837622;
public const int common_plus_signin_btn_text_dark_pressed = 2130837622;
// aapt resource value: 0x7f020077
public const int common_plus_signin_btn_text_light_pressed = 2130837623;
public const int common_plus_signin_btn_text_light = 2130837623;
// aapt resource value: 0x7f020078
public const int design_fab_background = 2130837624;
public const int common_plus_signin_btn_text_light_disabled = 2130837624;
// aapt resource value: 0x7f020079
public const int design_snackbar_background = 2130837625;
public const int common_plus_signin_btn_text_light_focused = 2130837625;
// aapt resource value: 0x7f02007a
public const int envelope = 2130837626;
public const int common_plus_signin_btn_text_light_normal = 2130837626;
// aapt resource value: 0x7f02007b
public const int eye = 2130837627;
public const int common_plus_signin_btn_text_light_pressed = 2130837627;
// aapt resource value: 0x7f02007c
public const int eye_slash = 2130837628;
public const int design_fab_background = 2130837628;
// aapt resource value: 0x7f02007d
public const int fa_lock = 2130837629;
public const int design_snackbar_background = 2130837629;
// aapt resource value: 0x7f02007e
public const int fa_lock_selected = 2130837630;
public const int envelope = 2130837630;
// aapt resource value: 0x7f02007f
public const int fingerprint = 2130837631;
public const int eye = 2130837631;
// aapt resource value: 0x7f020080
public const int fingerprint_white = 2130837632;
public const int eye_slash = 2130837632;
// aapt resource value: 0x7f020081
public const int folder = 2130837633;
public const int fa_lock = 2130837633;
// aapt resource value: 0x7f020082
public const int globe = 2130837634;
public const int fa_lock_selected = 2130837634;
// aapt resource value: 0x7f020083
public const int hockeyapp_btn_background = 2130837635;
public const int fingerprint = 2130837635;
// aapt resource value: 0x7f020084
public const int ic_audiotrack = 2130837636;
public const int fingerprint_white = 2130837636;
// aapt resource value: 0x7f020085
public const int ic_audiotrack_light = 2130837637;
public const int folder = 2130837637;
// aapt resource value: 0x7f020086
public const int ic_bluetooth_grey = 2130837638;
public const int globe = 2130837638;
// aapt resource value: 0x7f020087
public const int ic_bluetooth_white = 2130837639;
public const int hockeyapp_btn_background = 2130837639;
// aapt resource value: 0x7f020088
public const int ic_cast_dark = 2130837640;
public const int ic_audiotrack = 2130837640;
// aapt resource value: 0x7f020089
public const int ic_cast_disabled_light = 2130837641;
public const int ic_audiotrack_light = 2130837641;
// aapt resource value: 0x7f02008a
public const int ic_cast_grey = 2130837642;
public const int ic_bluetooth_grey = 2130837642;
// aapt resource value: 0x7f02008b
public const int ic_cast_light = 2130837643;
public const int ic_bluetooth_white = 2130837643;
// aapt resource value: 0x7f02008c
public const int ic_cast_off_light = 2130837644;
public const int ic_cast_dark = 2130837644;
// aapt resource value: 0x7f02008d
public const int ic_cast_on_0_light = 2130837645;
public const int ic_cast_disabled_light = 2130837645;
// aapt resource value: 0x7f02008e
public const int ic_cast_on_1_light = 2130837646;
public const int ic_cast_grey = 2130837646;
// aapt resource value: 0x7f02008f
public const int ic_cast_on_2_light = 2130837647;
public const int ic_cast_light = 2130837647;
// aapt resource value: 0x7f020090
public const int ic_cast_on_light = 2130837648;
public const int ic_cast_off_light = 2130837648;
// aapt resource value: 0x7f020091
public const int ic_cast_white = 2130837649;
public const int ic_cast_on_0_light = 2130837649;
// aapt resource value: 0x7f020092
public const int ic_close_dark = 2130837650;
public const int ic_cast_on_1_light = 2130837650;
// aapt resource value: 0x7f020093
public const int ic_close_light = 2130837651;
public const int ic_cast_on_2_light = 2130837651;
// aapt resource value: 0x7f020094
public const int ic_collapse = 2130837652;
public const int ic_cast_on_light = 2130837652;
// aapt resource value: 0x7f020095
public const int ic_collapse_00000 = 2130837653;
public const int ic_cast_white = 2130837653;
// aapt resource value: 0x7f020096
public const int ic_collapse_00001 = 2130837654;
public const int ic_close_dark = 2130837654;
// aapt resource value: 0x7f020097
public const int ic_collapse_00002 = 2130837655;
public const int ic_close_light = 2130837655;
// aapt resource value: 0x7f020098
public const int ic_collapse_00003 = 2130837656;
public const int ic_collapse = 2130837656;
// aapt resource value: 0x7f020099
public const int ic_collapse_00004 = 2130837657;
public const int ic_collapse_00000 = 2130837657;
// aapt resource value: 0x7f02009a
public const int ic_collapse_00005 = 2130837658;
public const int ic_collapse_00001 = 2130837658;
// aapt resource value: 0x7f02009b
public const int ic_collapse_00006 = 2130837659;
public const int ic_collapse_00002 = 2130837659;
// aapt resource value: 0x7f02009c
public const int ic_collapse_00007 = 2130837660;
public const int ic_collapse_00003 = 2130837660;
// aapt resource value: 0x7f02009d
public const int ic_collapse_00008 = 2130837661;
public const int ic_collapse_00004 = 2130837661;
// aapt resource value: 0x7f02009e
public const int ic_collapse_00009 = 2130837662;
public const int ic_collapse_00005 = 2130837662;
// aapt resource value: 0x7f02009f
public const int ic_collapse_00010 = 2130837663;
public const int ic_collapse_00006 = 2130837663;
// aapt resource value: 0x7f0200a0
public const int ic_collapse_00011 = 2130837664;
public const int ic_collapse_00007 = 2130837664;
// aapt resource value: 0x7f0200a1
public const int ic_collapse_00012 = 2130837665;
public const int ic_collapse_00008 = 2130837665;
// aapt resource value: 0x7f0200a2
public const int ic_collapse_00013 = 2130837666;
public const int ic_collapse_00009 = 2130837666;
// aapt resource value: 0x7f0200a3
public const int ic_collapse_00014 = 2130837667;
public const int ic_collapse_00010 = 2130837667;
// aapt resource value: 0x7f0200a4
public const int ic_collapse_00015 = 2130837668;
public const int ic_collapse_00011 = 2130837668;
// aapt resource value: 0x7f0200a5
public const int ic_errorstatus = 2130837669;
public const int ic_collapse_00012 = 2130837669;
// aapt resource value: 0x7f0200a6
public const int ic_expand = 2130837670;
public const int ic_collapse_00013 = 2130837670;
// aapt resource value: 0x7f0200a7
public const int ic_expand_00000 = 2130837671;
public const int ic_collapse_00014 = 2130837671;
// aapt resource value: 0x7f0200a8
public const int ic_expand_00001 = 2130837672;
public const int ic_collapse_00015 = 2130837672;
// aapt resource value: 0x7f0200a9
public const int ic_expand_00002 = 2130837673;
public const int ic_errorstatus = 2130837673;
// aapt resource value: 0x7f0200aa
public const int ic_expand_00003 = 2130837674;
public const int ic_expand = 2130837674;
// aapt resource value: 0x7f0200ab
public const int ic_expand_00004 = 2130837675;
public const int ic_expand_00000 = 2130837675;
// aapt resource value: 0x7f0200ac
public const int ic_expand_00005 = 2130837676;
public const int ic_expand_00001 = 2130837676;
// aapt resource value: 0x7f0200ad
public const int ic_expand_00006 = 2130837677;
public const int ic_expand_00002 = 2130837677;
// aapt resource value: 0x7f0200ae
public const int ic_expand_00007 = 2130837678;
public const int ic_expand_00003 = 2130837678;
// aapt resource value: 0x7f0200af
public const int ic_expand_00008 = 2130837679;
public const int ic_expand_00004 = 2130837679;
// aapt resource value: 0x7f0200b0
public const int ic_expand_00009 = 2130837680;
public const int ic_expand_00005 = 2130837680;
// aapt resource value: 0x7f0200b1
public const int ic_expand_00010 = 2130837681;
public const int ic_expand_00006 = 2130837681;
// aapt resource value: 0x7f0200b2
public const int ic_expand_00011 = 2130837682;
public const int ic_expand_00007 = 2130837682;
// aapt resource value: 0x7f0200b3
public const int ic_expand_00012 = 2130837683;
public const int ic_expand_00008 = 2130837683;
// aapt resource value: 0x7f0200b4
public const int ic_expand_00013 = 2130837684;
public const int ic_expand_00009 = 2130837684;
// aapt resource value: 0x7f0200b5
public const int ic_expand_00014 = 2130837685;
public const int ic_expand_00010 = 2130837685;
// aapt resource value: 0x7f0200b6
public const int ic_expand_00015 = 2130837686;
public const int ic_expand_00011 = 2130837686;
// aapt resource value: 0x7f0200b7
public const int ic_media_pause = 2130837687;
public const int ic_expand_00012 = 2130837687;
// aapt resource value: 0x7f0200b8
public const int ic_media_play = 2130837688;
public const int ic_expand_00013 = 2130837688;
// aapt resource value: 0x7f0200b9
public const int ic_media_route_disabled_mono_dark = 2130837689;
public const int ic_expand_00014 = 2130837689;
// aapt resource value: 0x7f0200ba
public const int ic_media_route_off_mono_dark = 2130837690;
public const int ic_expand_00015 = 2130837690;
// aapt resource value: 0x7f0200bb
public const int ic_media_route_on_0_mono_dark = 2130837691;
public const int ic_media_pause = 2130837691;
// aapt resource value: 0x7f0200bc
public const int ic_media_route_on_1_mono_dark = 2130837692;
public const int ic_media_play = 2130837692;
// aapt resource value: 0x7f0200bd
public const int ic_media_route_on_2_mono_dark = 2130837693;
public const int ic_media_route_disabled_mono_dark = 2130837693;
// aapt resource value: 0x7f0200be
public const int ic_media_route_on_mono_dark = 2130837694;
public const int ic_media_route_off_mono_dark = 2130837694;
// aapt resource value: 0x7f0200bf
public const int ic_pause_dark = 2130837695;
public const int ic_media_route_on_0_mono_dark = 2130837695;
// aapt resource value: 0x7f0200c0
public const int ic_pause_light = 2130837696;
public const int ic_media_route_on_1_mono_dark = 2130837696;
// aapt resource value: 0x7f0200c1
public const int ic_play_dark = 2130837697;
public const int ic_media_route_on_2_mono_dark = 2130837697;
// aapt resource value: 0x7f0200c2
public const int ic_play_light = 2130837698;
public const int ic_media_route_on_mono_dark = 2130837698;
// aapt resource value: 0x7f0200c3
public const int ic_speaker_dark = 2130837699;
public const int ic_pause_dark = 2130837699;
// aapt resource value: 0x7f0200c4
public const int ic_speaker_group_dark = 2130837700;
public const int ic_pause_light = 2130837700;
// aapt resource value: 0x7f0200c5
public const int ic_speaker_group_light = 2130837701;
public const int ic_play_dark = 2130837701;
// aapt resource value: 0x7f0200c6
public const int ic_speaker_light = 2130837702;
public const int ic_play_light = 2130837702;
// aapt resource value: 0x7f0200c7
public const int ic_successstatus = 2130837703;
public const int ic_speaker_dark = 2130837703;
// aapt resource value: 0x7f0200c8
public const int ic_tv_dark = 2130837704;
public const int ic_speaker_group_dark = 2130837704;
// aapt resource value: 0x7f0200c9
public const int ic_tv_light = 2130837705;
public const int ic_speaker_group_light = 2130837705;
// aapt resource value: 0x7f0200ca
public const int icon = 2130837706;
public const int ic_speaker_light = 2130837706;
// aapt resource value: 0x7f0200cb
public const int ion_chevron_right = 2130837707;
public const int ic_successstatus = 2130837707;
// aapt resource value: 0x7f0200cc
public const int lightbulb = 2130837708;
public const int ic_tv_dark = 2130837708;
// aapt resource value: 0x7f0200cd
public const int list_selector = 2130837709;
public const int ic_tv_light = 2130837709;
// aapt resource value: 0x7f0200ce
public const int @lock = 2130837710;
public const int icon = 2130837710;
// aapt resource value: 0x7f0200cf
public const int logo = 2130837711;
public const int ion_chevron_right = 2130837711;
// aapt resource value: 0x7f0200d0
public const int more = 2130837712;
public const int lightbulb = 2130837712;
// aapt resource value: 0x7f0200d1
public const int mr_dialog_material_background_dark = 2130837713;
public const int list_selector = 2130837713;
// aapt resource value: 0x7f0200d2
public const int mr_dialog_material_background_light = 2130837714;
public const int @lock = 2130837714;
// aapt resource value: 0x7f0200d3
public const int mr_ic_audiotrack_light = 2130837715;
public const int logo = 2130837715;
// aapt resource value: 0x7f0200d4
public const int mr_ic_cast_dark = 2130837716;
public const int more = 2130837716;
// aapt resource value: 0x7f0200d5
public const int mr_ic_cast_light = 2130837717;
public const int mr_dialog_material_background_dark = 2130837717;
// aapt resource value: 0x7f0200d6
public const int mr_ic_close_dark = 2130837718;
public const int mr_dialog_material_background_light = 2130837718;
// aapt resource value: 0x7f0200d7
public const int mr_ic_close_light = 2130837719;
public const int mr_ic_audiotrack_light = 2130837719;
// aapt resource value: 0x7f0200d8
public const int mr_ic_media_route_connecting_mono_dark = 2130837720;
public const int mr_ic_cast_dark = 2130837720;
// aapt resource value: 0x7f0200d9
public const int mr_ic_media_route_connecting_mono_light = 2130837721;
public const int mr_ic_cast_light = 2130837721;
// aapt resource value: 0x7f0200da
public const int mr_ic_media_route_mono_dark = 2130837722;
public const int mr_ic_close_dark = 2130837722;
// aapt resource value: 0x7f0200db
public const int mr_ic_media_route_mono_light = 2130837723;
public const int mr_ic_close_light = 2130837723;
// aapt resource value: 0x7f0200dc
public const int mr_ic_pause_dark = 2130837724;
public const int mr_ic_media_route_connecting_mono_dark = 2130837724;
// aapt resource value: 0x7f0200dd
public const int mr_ic_pause_light = 2130837725;
public const int mr_ic_media_route_connecting_mono_light = 2130837725;
// aapt resource value: 0x7f0200de
public const int mr_ic_play_dark = 2130837726;
public const int mr_ic_media_route_mono_dark = 2130837726;
// aapt resource value: 0x7f0200df
public const int mr_ic_play_light = 2130837727;
// aapt resource value: 0x7f0200eb
public const int notification_template_icon_bg = 2130837739;
public const int mr_ic_media_route_mono_light = 2130837727;
// aapt resource value: 0x7f0200e0
public const int plus = 2130837728;
public const int mr_ic_pause_dark = 2130837728;
// aapt resource value: 0x7f0200e1
public const int refresh = 2130837729;
public const int mr_ic_pause_light = 2130837729;
// aapt resource value: 0x7f0200e2
public const int roundedbg = 2130837730;
public const int mr_ic_play_dark = 2130837730;
// aapt resource value: 0x7f0200e3
public const int roundedbgdark = 2130837731;
public const int mr_ic_play_light = 2130837731;
// aapt resource value: 0x7f0200e4
public const int splash_screen = 2130837732;
public const int notification_sm = 2130837732;
// aapt resource value: 0x7f0200f3
public const int notification_template_icon_bg = 2130837747;
// aapt resource value: 0x7f0200e5
public const int star = 2130837733;
public const int plus = 2130837733;
// aapt resource value: 0x7f0200e6
public const int star_selected = 2130837734;
public const int refresh = 2130837734;
// aapt resource value: 0x7f0200e7
public const int tools = 2130837735;
public const int roundedbg = 2130837735;
// aapt resource value: 0x7f0200e8
public const int tools_selected = 2130837736;
public const int roundedbgdark = 2130837736;
// aapt resource value: 0x7f0200e9
public const int upload = 2130837737;
public const int search = 2130837737;
// aapt resource value: 0x7f0200ea
public const int user = 2130837738;
public const int share = 2130837738;
// aapt resource value: 0x7f0200eb
public const int share_tools = 2130837739;
// aapt resource value: 0x7f0200ec
public const int splash_screen = 2130837740;
// aapt resource value: 0x7f0200ed
public const int star = 2130837741;
// aapt resource value: 0x7f0200ee
public const int star_selected = 2130837742;
// aapt resource value: 0x7f0200ef
public const int tools = 2130837743;
// aapt resource value: 0x7f0200f0
public const int tools_selected = 2130837744;
// aapt resource value: 0x7f0200f1
public const int upload = 2130837745;
// aapt resource value: 0x7f0200f2
public const int user = 2130837746;
static Drawable()
{
@@ -3675,6 +3699,9 @@ namespace Bit.Android
// aapt resource value: 0x7f080047
public const int ApplicationName = 2131230791;
// aapt resource value: 0x7f08008f
public const int AutoFillServiceDescription = 2131230863;
// aapt resource value: 0x7f080046
public const int Hello = 2131230790;

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="AutoFillServiceDescription">
The allow bitwarden to auto-fill into other Android apps and on the web through your browser, enable the bitwarden
accessibility service by tapping the toggle switch above, then press OK on the confirmation pop-up. You can then press
the back button twice to return to the main bitwarden app.
</string>
</resources>

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackSpoken"
android:accessibilityFlags="flagDefault"
android:description="@string/AutoFillServiceDescription"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"/>

View File

@@ -1,4 +1,6 @@
using Bit.App.Abstractions;
using Android.App;
using Bit.App.Abstractions;
using System.Linq;
using AndroidApp = Android.App.Application;
namespace Bit.Android.Services
@@ -10,5 +12,15 @@ namespace Bit.Android.Services
public string Build => AndroidApp.Context.ApplicationContext.PackageManager
.GetPackageInfo(AndroidApp.Context.PackageName, 0).VersionCode.ToString();
public bool AutofillServiceEnabled => AutofillRunning();
private bool AutofillRunning()
{
var manager = ((ActivityManager)Xamarin.Forms.Forms.Context.GetSystemService("activity"));
var services = manager.GetRunningServices(int.MaxValue);
return services.Any(s => s.Process.ToLowerInvariant().Contains("bitwarden") &&
s.Service.ClassName.ToLowerInvariant().Contains("autofill"));
}
}
}

View File

@@ -1,5 +1,7 @@
using System;
using Bit.App;
using Bit.App.Abstractions;
using Plugin.Settings.Abstractions;
using Android.Gms.Analytics;
using Android.Content;
@@ -7,8 +9,6 @@ namespace Bit.Android.Services
{
public class GoogleAnalyticsService : IGoogleAnalyticsService
{
private const string UserId = "&uid";
private readonly GoogleAnalytics _instance;
private readonly IAuthService _authService;
private readonly Tracker _tracker;
@@ -17,7 +17,8 @@ namespace Bit.Android.Services
public GoogleAnalyticsService(
Context appContext,
IAppIdService appIdService,
IAuthService authService)
IAuthService authService,
ISettings settings)
{
_authService = authService;
@@ -25,16 +26,13 @@ namespace Bit.Android.Services
_instance.SetLocalDispatchPeriod(10);
_tracker = _instance.NewTracker("UA-81915606-2");
_tracker.EnableExceptionReporting(true);
_tracker.EnableExceptionReporting(false);
_tracker.EnableAdvertisingIdCollection(true);
_tracker.EnableAutoActivityTracking(true);
_tracker.SetClientId(appIdService.AnonymousAppId);
}
public void RefreshUserId()
{
_tracker.Set(UserId, null);
_setUserId = true;
var gaOptOut = settings.GetValueOrDefault(Constants.SettingGaOptOut, false);
SetAppOptOut(gaOptOut);
}
public void TrackAppEvent(string eventName, string label = null)
@@ -44,7 +42,7 @@ namespace Bit.Android.Services
public void TrackExtensionEvent(string eventName, string label = null)
{
throw new NotSupportedException();
TrackEvent("AutofillService", eventName, label);
}
public void TrackEvent(string category, string eventName, string label = null)
@@ -57,7 +55,6 @@ namespace Bit.Android.Services
builder.SetLabel(label);
}
SetUserId();
_tracker.Send(builder.Build());
}
@@ -67,30 +64,24 @@ namespace Bit.Android.Services
builder.SetDescription(message);
builder.SetFatal(fatal);
SetUserId();
_tracker.Send(builder.Build());
}
public void TrackPage(string pageName)
{
SetUserId();
_tracker.SetScreenName(pageName);
_tracker.Send(new HitBuilders.ScreenViewBuilder().Build());
}
private void SetUserId()
{
if(_setUserId && _authService.IsAuthenticated)
{
_tracker.Set(UserId, _authService.UserId);
_setUserId = false;
}
}
public void Dispatch(Action completionHandler = null)
{
_instance.DispatchLocalHits();
completionHandler?.Invoke();
}
public void SetAppOptOut(bool optOut)
{
_instance.AppOptOut = optOut;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using Xamarin.Android.Net;
using Bit.App;
using Bit.App.Abstractions;
namespace Bit.Android.Services
{
public class HttpService : IHttpService
{
public ApiHttpClient ApiClient => new ApiHttpClient(new AndroidClientHandler());
public IdentityHttpClient IdentityClient => new IdentityHttpClient(new AndroidClientHandler());
}
}

View File

@@ -52,22 +52,30 @@ namespace Bit.Android.Services
Console.WriteLine("Android Language:" + androidLanguage);
var netLanguage = androidLanguage;
// certain languages need to be converted to CultureInfo equivalent
switch(androidLanguage)
if(netLanguage.StartsWith("zh"))
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizert<EFBFBD><EFBFBD>tsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
// simplified chinese used for all for now
netLanguage = "zh-Hans";
}
else
{
// certain languages need to be converted to CultureInfo equivalent
switch(androidLanguage)
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizert<72><74>tsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
}
Console.WriteLine(".NET Language/Locale:" + netLanguage);

View File

@@ -0,0 +1,44 @@
using System;
using Android.Content;
using Bit.App.Abstractions;
using Xamarin.Forms;
namespace Bit.Android.Services
{
public class MemoryService : IMemoryService
{
public MemoryInfo GetInfo()
{
return MemoryHelper.GetMemoryInfo(Forms.Context);
}
public void Check()
{
MemoryHelper.MemoryCheck(Forms.Context);
}
public static class MemoryHelper
{
public static void MemoryCheck(Context context)
{
Console.WriteLine("MemoryHelper.MemoryCheck.{0} - {1}", "Start", context.ToString());
var maxMemory = Java.Lang.Runtime.GetRuntime().MaxMemory();
var freeMemory = Java.Lang.Runtime.GetRuntime().FreeMemory();
var percentUsed = (maxMemory - freeMemory) / (double)maxMemory;
Console.WriteLine("Free memory: {0:N}", freeMemory);
Console.WriteLine("Max memory: {0:N}", maxMemory);
Console.WriteLine("% used: {0:P}", percentUsed);
Console.WriteLine("MemoryHelper.MemoryCheck.{0} {3:P} {1} out of {2}", "End", freeMemory, maxMemory, percentUsed);
}
public static MemoryInfo GetMemoryInfo(Context context)
{
var retVal = new MemoryInfo();
retVal.MaxMemory = Java.Lang.Runtime.GetRuntime().MaxMemory();
retVal.FreeMemory = Java.Lang.Runtime.GetRuntime().FreeMemory();
retVal.TotalMemory = Java.Lang.Runtime.GetRuntime().TotalMemory();
return retVal;
}
}
}
}

View File

@@ -0,0 +1,8 @@
$rootPath = $args[0];
$newVersionCode = $args[1];
$xml=New-Object XML;
$xml.Load($rootPath + "\src\Android\Properties\AndroidManifest.xml");
$node=$xml.SelectNodes("/manifest");
$node.SetAttribute("android:versionCode", $newVersionCode);
$xml.Save($rootPath + "\src\Android\Properties\AndroidManifest.xml");

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Acr.Support" version="2.1.0" targetFramework="monoandroid60" />
<package id="Acr.UserDialogs" version="6.3.2" targetFramework="monoandroid60" />
<package id="Acr.UserDialogs" version="6.3.10" targetFramework="monoandroid71" />
<package id="AndHUD" version="1.2.0" targetFramework="monoandroid60" />
<package id="BouncyCastle" version="1.8.1" targetFramework="monoandroid60" />
<package id="CommonServiceLocator" version="1.3" targetFramework="monoandroid60" />
<package id="HockeySDK.Xamarin" version="4.1.0" targetFramework="monoandroid60" />
<package id="HockeySDK.Xamarin" version="4.1.2" targetFramework="monoandroid71" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="monoandroid60" />
<package id="PCLCrypto" version="2.0.147" targetFramework="monoandroid60" />
<package id="PInvoke.BCrypt" version="0.3.152" targetFramework="monoandroid60" />
@@ -19,15 +19,15 @@
<package id="SQLitePCL.bundle_green" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCL.plugin.sqlite3.android" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCL.raw" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.1" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.lib.e_sqlite3.android" version="1.1.1" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.provider.e_sqlite3.android" version="1.1.1" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.lib.e_sqlite3.android" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.provider.e_sqlite3.android" version="1.1.2" targetFramework="monoandroid60" />
<package id="Unity" version="3.5.1405-prerelease" targetFramework="monoandroid60" />
<package id="Validation" version="2.3.7" targetFramework="monoandroid60" />
<package id="Xam.Plugin.Connectivity" version="2.2.12" targetFramework="monoandroid60" />
<package id="Xam.Plugin.Connectivity" version="2.3.0" targetFramework="monoandroid71" />
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="monoandroid60" developmentDependency="true" />
<package id="Xam.Plugins.Settings" version="2.5.1.0" targetFramework="monoandroid60" />
<package id="Xam.Plugins.Settings" version="2.5.4" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
@@ -36,7 +36,9 @@
<package id="Xamarin.Android.Support.v7.MediaRouter" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v7.RecyclerView" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Forms" version="2.3.3.175" targetFramework="monoandroid60" />
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="monoandroid71" />
<package id="Xamarin.FFImageLoading.Forms" version="2.2.9" targetFramework="monoandroid71" />
<package id="Xamarin.Forms" version="2.3.4.231" targetFramework="monoandroid71" />
<package id="Xamarin.GooglePlayServices.Analytics" version="29.0.0.2" targetFramework="monoandroid60" />
<package id="Xamarin.GooglePlayServices.Base" version="29.0.0.2" targetFramework="monoandroid60" />
<package id="Xamarin.GooglePlayServices.Basement" version="29.0.0.2" targetFramework="monoandroid60" />

View File

@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
using System;
namespace Bit.App.Abstractions
{
@@ -7,5 +8,8 @@ namespace Bit.App.Abstractions
{
Task<ApiResult> PostRegisterAsync(RegisterRequest requestObj);
Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj);
Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync();
Task<ApiResult<ProfileResponse>> GetProfileAsync();
Task<ApiResult<KeysResponse>> GetKeys();
}
}

View File

@@ -8,6 +8,5 @@ namespace Bit.App.Abstractions
{
Task<ApiResult<CipherResponse>> GetByIdAsync(string id);
Task<ApiResult<ListResponse<CipherResponse>>> GetAsync();
Task<ApiResult<CipherHistoryResponse>> GetByRevisionDateWithHistoryAsync(DateTime since);
}
}

View File

@@ -3,9 +3,8 @@ using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface IAuthApiRepository
public interface IConnectApiRepository
{
Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj);
Task<ApiResult<TokenResponse>> PostTokenTwoFactorAsync(TokenTwoFactorRequest requestObj);
}
}

View File

@@ -8,6 +8,6 @@ namespace Bit.App.Abstractions
public interface IFolderRepository : IRepository<FolderData, string>
{
Task<IEnumerable<FolderData>> GetAllByUserIdAsync(string userId);
Task DeleteWithSiteUpdateAsync(string id, DateTime revisionDate);
Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate);
}
}

View File

@@ -5,7 +5,7 @@ using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISiteApiRepository : IApiRepository<SiteRequest, SiteResponse, string>
public interface ILoginApiRepository : IApiRepository<LoginRequest, LoginResponse, string>
{
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Data;
namespace Bit.App.Abstractions
{
public interface ILoginRepository : IRepository<LoginData, string>
{
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View File

@@ -12,6 +12,7 @@ namespace Bit.App.Abstractions
Task<IEnumerable<T>> GetAllAsync();
Task UpdateAsync(T obj);
Task InsertAsync(T obj);
Task UpsertAsync(T obj);
Task DeleteAsync(TId id);
Task DeleteAsync(T obj);
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISettingsApiRepository
{
Task<ApiResult<DomainsResponse>> GetDomains(bool excluded = false);
}
}

View File

@@ -0,0 +1,8 @@
using Bit.App.Models.Data;
namespace Bit.App.Abstractions
{
public interface ISettingsRepository : IRepository<SettingsData, string>
{
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Data;
namespace Bit.App.Abstractions
{
public interface ISiteRepository : IRepository<SiteData, string>
{
Task<IEnumerable<SiteData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<SiteData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View File

@@ -4,5 +4,6 @@
{
string Build { get; }
string Version { get; }
bool AutofillServiceEnabled { get; }
}
}

View File

@@ -0,0 +1,10 @@
using System;
namespace Bit.App.Abstractions
{
public interface IAppSettingsService
{
bool Locked { get; set; }
DateTime LastActivity { get; set; }
}
}

View File

@@ -1,21 +1,20 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
using Bit.App.Models;
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{
public interface IAuthService
{
bool IsAuthenticated { get; }
bool IsAuthenticatedTwoFactor { get; }
string Token { get; set; }
string UserId { get; set; }
string PreviousUserId { get; }
bool UserIdChanged { get; }
string Email { get; set; }
string PIN { get; set; }
bool BelongsToOrganization(string orgId);
void LogOut();
Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request);
Task<ApiResult<TokenResponse>> TokenTwoFactorPostAsync(TokenTwoFactorRequest request);
Task<FullLoginResult> TokenPostAsync(string email, string masterPassword);
Task<LoginResult> TokenPostTwoFactorAsync(string token, string email, string masterPasswordHash, SymmetricCryptoKey key);
}
}

View File

@@ -1,19 +1,30 @@
using Bit.App.Models;
using Bit.App.Models.Api;
using System;
using System.Collections.Generic;
namespace Bit.App.Abstractions
{
public interface ICryptoService
{
string Base64Key { get; }
byte[] Key { get; set; }
byte[] PreviousKey { get; }
SymmetricCryptoKey Key { get; set; }
SymmetricCryptoKey PreviousKey { get; }
bool KeyChanged { get; }
byte[] PrivateKey { get; }
IDictionary<string, SymmetricCryptoKey> OrgKeys { get; }
string Decrypt(CipherString encyptedValue);
CipherString Encrypt(string plaintextValue);
byte[] MakeKeyFromPassword(string password, string salt);
void SetPrivateKey(CipherString privateKeyEnc);
void SetOrgKeys(ProfileResponse profile);
void SetOrgKeys(Dictionary<string, string> orgKeysEncDict);
SymmetricCryptoKey GetOrgKey(string orgId);
void ClearKeys();
string Decrypt(CipherString encyptedValue, SymmetricCryptoKey key = null);
byte[] DecryptToBytes(CipherString encyptedValue, SymmetricCryptoKey key = null);
byte[] RsaDecryptToBytes(CipherString encyptedValue, byte[] privateKey);
CipherString Encrypt(string plaintextValue, SymmetricCryptoKey key = null);
SymmetricCryptoKey MakeKeyFromPassword(string password, string salt);
string MakeKeyFromPasswordBase64(string password, string salt);
byte[] HashPassword(byte[] key, string password);
string HashPasswordBase64(byte[] key, string password);
byte[] HashPassword(SymmetricCryptoKey key, string password);
string HashPasswordBase64(SymmetricCryptoKey key, string password);
}
}

View File

@@ -4,12 +4,12 @@ namespace Bit.App.Abstractions
{
public interface IGoogleAnalyticsService
{
void RefreshUserId();
void TrackPage(string pageName);
void TrackAppEvent(string eventName, string label = null);
void TrackExtensionEvent(string eventName, string label = null);
void TrackEvent(string category, string eventName, string label = null);
void TrackException(string message, bool fatal);
void Dispatch(Action completionHandler = null);
void SetAppOptOut(bool optOut);
}
}

View File

@@ -0,0 +1,8 @@
namespace Bit.App.Abstractions
{
public interface IHttpService
{
ApiHttpClient ApiClient { get; }
IdentityHttpClient IdentityClient { get; }
}
}

View File

@@ -1,9 +1,11 @@
using Bit.App.Enums;
using System;
namespace Bit.App.Abstractions
{
public interface ILockService
{
void UpdateLastActivity(DateTime? activityDate = null);
LockType GetLockType(bool forceLock);
}
}

View File

@@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Models.Api;
using System;
namespace Bit.App.Abstractions
{
public interface ILoginService
{
Task<Login> GetByIdAsync(string id);
Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString);
Task<ApiResult<LoginResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id);
}
}

View File

@@ -0,0 +1,26 @@
namespace Bit.App.Abstractions
{
public interface IMemoryService
{
MemoryInfo GetInfo();
void Check();
}
public class MemoryInfo
{
public long FreeMemory { get; set; }
public long MaxMemory { get; set; }
public long TotalMemory { get; set; }
public long UsedMemory => TotalMemory - FreeMemory;
public double HeapUsage()
{
return UsedMemory / (double)TotalMemory;
}
public double Usage()
{
return UsedMemory / (double)MaxMemory;
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{
public interface ISettingsService
{
Task<IEnumerable<IEnumerable<string>>> GetEquivalentDomainsAsync();
}
}

View File

@@ -1,16 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISiteService
{
Task<Site> GetByIdAsync(string id);
Task<IEnumerable<Site>> GetAllAsync();
Task<IEnumerable<Site>> GetAllAsync(bool favorites);
Task<ApiResult<SiteResponse>> SaveAsync(Site site);
Task<ApiResult> DeleteAsync(string id);
}
}

View File

@@ -6,11 +6,13 @@ namespace Bit.App.Abstractions
public interface ISyncService
{
bool SyncInProgress { get; }
Task<bool> SyncAsync(string id);
Task<bool> SyncCipherAsync(string id);
Task<bool> SyncFolderAsync(string id);
Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate);
Task<bool> SyncDeleteSiteAsync(string id);
Task<bool> FullSyncAsync();
Task<bool> IncrementalSyncAsync(TimeSpan syncThreshold);
Task<bool> IncrementalSyncAsync();
Task<bool> SyncDeleteLoginAsync(string id);
Task<bool> SyncSettingsAsync();
Task<bool> SyncProfileAsync();
Task<bool> FullSyncAsync(bool forceSync = false);
Task<bool> FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false);
}
}

View File

@@ -0,0 +1,20 @@
using System;
namespace Bit.App.Abstractions
{
public interface ITokenService
{
string Token { get; set; }
string RefreshToken { get; set; }
[Obsolete("Old auth scheme")]
string AuthBearer { get; set; }
DateTime TokenExpiration { get; }
string TokenIssuer { get; }
bool TokenExpired { get; }
TimeSpan TokenTimeRemaining { get; }
bool TokenNeedsRefresh { get; }
string TokenUserId { get; }
string TokenEmail { get; }
string TokenName { get; }
}
}

View File

@@ -19,6 +19,9 @@ namespace Bit.App
{
public class App : Application
{
private const string LastBuildKey = "LastBuild";
private string _uri;
private readonly IDatabaseService _databaseService;
private readonly IConnectivity _connectivity;
private readonly IUserDialogs _userDialogs;
@@ -29,8 +32,11 @@ namespace Bit.App
private readonly ILockService _lockService;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly ILocalizeService _localizeService;
private readonly IAppInfoService _appInfoService;
private readonly IAppSettingsService _appSettingsService;
public App(
string uri,
IAuthService authService,
IConnectivity connectivity,
IUserDialogs userDialogs,
@@ -40,8 +46,11 @@ namespace Bit.App
ISettings settings,
ILockService lockService,
IGoogleAnalyticsService googleAnalyticsService,
ILocalizeService localizeService)
ILocalizeService localizeService,
IAppInfoService appInfoService,
IAppSettingsService appSettingsService)
{
_uri = uri;
_databaseService = databaseService;
_connectivity = connectivity;
_userDialogs = userDialogs;
@@ -52,11 +61,17 @@ namespace Bit.App
_lockService = lockService;
_googleAnalyticsService = googleAnalyticsService;
_localizeService = localizeService;
_appInfoService = appInfoService;
_appSettingsService = appSettingsService;
SetCulture();
SetStyles();
if(authService.IsAuthenticated)
if(authService.IsAuthenticated && _uri != null)
{
MainPage = new ExtendedNavigationPage(new VaultAutofillListLoginsPage(_uri));
}
else if(authService.IsAuthenticated)
{
MainPage = new MainPage();
}
@@ -67,8 +82,8 @@ namespace Bit.App
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, args) =>
{
await CheckLockAsync(args);
await Task.Run(() => IncrementalSyncAsync()).ConfigureAwait(false);
Device.BeginInvokeOnMainThread(async () => await CheckLockAsync(args));
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
});
MessagingCenter.Subscribe<Application, bool>(Current, "Lock", (sender, args) =>
@@ -78,7 +93,7 @@ namespace Bit.App
MessagingCenter.Subscribe<Application, string>(Current, "Logout", (sender, args) =>
{
Device.BeginInvokeOnMainThread(() => Logout(args));
Logout(args);
});
}
@@ -86,8 +101,18 @@ namespace Bit.App
{
// Handle when your app starts
await CheckLockAsync(false);
_databaseService.CreateTables();
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
if(string.IsNullOrWhiteSpace(_uri))
{
var lastBuild = _settings.GetValueOrDefault<string>(LastBuildKey);
if(InDebugMode() || lastBuild == null || lastBuild != _appInfoService.Build)
{
_settings.AddOrUpdateValue(LastBuildKey, _appInfoService.Build);
_databaseService.CreateTables();
}
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
}
Debug.WriteLine("OnStart");
}
@@ -97,9 +122,11 @@ namespace Bit.App
// Handle when your app sleeps
Debug.WriteLine("OnSleep");
SetMainPageFromAutofill();
if(Device.OS == TargetPlatform.Android && !TopPageIsLock())
{
_settings.AddOrUpdateValue(Constants.LastActivityDate, DateTime.UtcNow);
_lockService.UpdateLastActivity();
}
}
@@ -124,46 +151,37 @@ namespace Bit.App
{
lockPinPage.PinControl.Entry.FocusWithDelay();
}
if(Device.OS == TargetPlatform.Android)
{
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
}
}
private async Task IncrementalSyncAsync()
private void SetMainPageFromAutofill()
{
if(_connectivity.IsConnected)
if(Device.OS == TargetPlatform.Android && !string.IsNullOrWhiteSpace(_uri))
{
var attempt = 0;
do
Task.Run(() =>
{
try
Device.BeginInvokeOnMainThread(() =>
{
await _syncService.IncrementalSyncAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
break;
}
catch(WebException)
{
Debug.WriteLine("Failed to incremental sync.");
if(attempt >= 1)
{
break;
}
else
{
await Task.Delay(1000);
}
attempt++;
}
catch(Exception e) when(e is TaskCanceledException || e is OperationCanceledException)
{
Debug.WriteLine("Cancellation exception.");
break;
}
} while(attempt <= 1);
}
else
{
Debug.WriteLine("Not connected.");
Current.MainPage = new MainPage();
_uri = null;
});
});
}
}
private bool InDebugMode()
{
#if DEBUG
return true;
#else
return false;
#endif
}
private async Task FullSyncAsync()
{
if(_connectivity.IsConnected)
@@ -173,7 +191,7 @@ namespace Bit.App
{
try
{
await _syncService.FullSyncAsync().ConfigureAwait(false);
await _syncService.FullSyncAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
break;
}
catch(WebException)
@@ -206,19 +224,17 @@ namespace Bit.App
{
_authService.LogOut();
_googleAnalyticsService.TrackAppEvent("LoggedOut");
_googleAnalyticsService.RefreshUserId();
var deviceApiRepository = Resolver.Resolve<IDeviceApiRepository>();
var appIdService = Resolver.Resolve<IAppIdService>();
await Task.Run(() => deviceApiRepository.PutClearTokenAsync(appIdService.AppId)).ConfigureAwait(false);
Current.MainPage = new ExtendedNavigationPage(new HomePage());
_googleAnalyticsService.TrackAppEvent("LoggedOut");
Device.BeginInvokeOnMainThread(() => Current.MainPage = new ExtendedNavigationPage(new HomePage()));
if(!string.IsNullOrWhiteSpace(logoutMessage))
{
_userDialogs.Toast(logoutMessage);
}
var deviceApiRepository = Resolver.Resolve<IDeviceApiRepository>();
var appIdService = Resolver.Resolve<IAppIdService>();
_settings.Remove(Constants.PushLastRegistrationDate);
await Task.Run(() => deviceApiRepository.PutClearTokenAsync(appIdService.AppId)).ConfigureAwait(false);
}
private async Task CheckLockAsync(bool forceLock)
@@ -230,7 +246,12 @@ namespace Bit.App
}
var lockType = _lockService.GetLockType(forceLock);
var currentPage = Current.MainPage.Navigation.ModalStack.LastOrDefault() as ExtendedNavigationPage;
if(lockType == Enums.LockType.None)
{
return;
}
_appSettingsService.Locked = true;
switch(lockType)
{
case Enums.LockType.Fingerprint:

View File

@@ -35,8 +35,15 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IDeviceApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ISettingsRepository.cs" />
<Compile Include="Abstractions\Services\IAppSettingsService.cs" />
<Compile Include="Abstractions\Services\IMemoryService.cs" />
<Compile Include="Abstractions\Services\ISettingsService.cs" />
<Compile Include="Abstractions\Services\ITokenService.cs" />
<Compile Include="Abstractions\Services\IHttpService.cs" />
<Compile Include="Abstractions\Services\IDeviceInfoService.cs" />
<Compile Include="Abstractions\Services\IGoogleAnalyticsService.cs" />
<Compile Include="Abstractions\Services\IAppInfoService.cs" />
@@ -46,17 +53,19 @@
<Compile Include="Abstractions\Services\IKeyDerivationService.cs" />
<Compile Include="Abstractions\Services\ILogService.cs" />
<Compile Include="Abstractions\Services\IReflectionService.cs" />
<Compile Include="Abstractions\Services\ISiteService.cs" />
<Compile Include="Abstractions\Services\ILoginService.cs" />
<Compile Include="Abstractions\Services\IFolderService.cs" />
<Compile Include="App.cs" />
<Compile Include="Abstractions\Services\ISecureStorageService.cs" />
<Compile Include="Abstractions\Services\ISqlService.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Controls\ExtendedToolbarItem.cs" />
<Compile Include="Controls\DismissModalToolBarItem.cs" />
<Compile Include="Controls\ExtendedEditor.cs" />
<Compile Include="Controls\ExtendedButton.cs" />
<Compile Include="Controls\ExtendedNavigationPage.cs" />
<Compile Include="Controls\ExtendedContentPage.cs" />
<Compile Include="Controls\MemoryContentView.cs" />
<Compile Include="Controls\StepperCell.cs" />
<Compile Include="Controls\ExtendedTableView.cs" />
<Compile Include="Controls\ExtendedPicker.cs" />
@@ -71,8 +80,12 @@
<Compile Include="Controls\FormPickerCell.cs" />
<Compile Include="Controls\FormEntryCell.cs" />
<Compile Include="Controls\PinControl.cs" />
<Compile Include="Controls\VaultListViewCell.cs" />
<Compile Include="Enums\EncryptionType.cs" />
<Compile Include="Enums\OrganizationUserType.cs" />
<Compile Include="Enums\LockType.cs" />
<Compile Include="Enums\CipherType.cs" />
<Compile Include="Enums\OrganizationUserStatusType.cs" />
<Compile Include="Enums\PushType.cs" />
<Compile Include="Enums\ReturnType.cs" />
<Compile Include="Abstractions\Services\ILocalizeService.cs" />
@@ -83,36 +96,42 @@
<Compile Include="Models\Api\Request\FolderRequest.cs" />
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
<Compile Include="Models\Api\Request\RegisterRequest.cs" />
<Compile Include="Models\Api\Request\SiteRequest.cs" />
<Compile Include="Models\Api\Request\LoginRequest.cs" />
<Compile Include="Models\Api\Request\PasswordHintRequest.cs" />
<Compile Include="Models\Api\Request\TokenRequest.cs" />
<Compile Include="Models\Api\Request\TokenTwoFactorRequest.cs" />
<Compile Include="Models\Api\Response\CipherHistoryResponse.cs" />
<Compile Include="Models\Api\Response\CipherResponse.cs" />
<Compile Include="Models\Api\Response\DomainsResponse.cs" />
<Compile Include="Models\Api\Response\ErrorResponse.cs" />
<Compile Include="Models\Api\Response\FolderResponse.cs" />
<Compile Include="Models\Api\Response\ListResponse.cs" />
<Compile Include="Models\Api\Response\DeviceResponse.cs" />
<Compile Include="Models\Api\Response\SiteResponse.cs" />
<Compile Include="Models\Api\Response\LoginResponse.cs" />
<Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" />
<Compile Include="Models\Api\Response\KeysResponse.cs" />
<Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\SiteDataModel.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" />
<Compile Include="Models\Cipher.cs" />
<Compile Include="Models\CipherString.cs" />
<Compile Include="Models\SymmetricCryptoKey.cs" />
<Compile Include="Models\Data\SettingsData.cs" />
<Compile Include="Models\Data\FolderData.cs" />
<Compile Include="Abstractions\IDataObject.cs" />
<Compile Include="Models\Data\SiteData.cs" />
<Compile Include="Models\Data\LoginData.cs" />
<Compile Include="Models\DomainName.cs" />
<Compile Include="Models\Folder.cs" />
<Compile Include="Models\LoginResult.cs" />
<Compile Include="Models\Page\AppExtensionPageModel.cs" />
<Compile Include="Models\Page\SettingsFolderPageModel.cs" />
<Compile Include="Models\Page\PinPageModel.cs" />
<Compile Include="Models\Page\PasswordGeneratorPageModel.cs" />
<Compile Include="Models\PlatformCulture.cs" />
<Compile Include="Models\PushNotification.cs" />
<Compile Include="Models\Site.cs" />
<Compile Include="Models\Page\VaultViewSitePageModel.cs" />
<Compile Include="Models\Login.cs" />
<Compile Include="Models\Page\VaultViewLoginPageModel.cs" />
<Compile Include="Pages\HomePage.cs" />
<Compile Include="Pages\Lock\BaseLockPage.cs" />
<Compile Include="Pages\Lock\LockPasswordPage.cs" />
<Compile Include="Pages\LoginTwoFactorPage.cs" />
<Compile Include="Pages\PasswordHintPage.cs" />
@@ -133,22 +152,25 @@
<Compile Include="Pages\Settings\SettingsSyncPage.cs" />
<Compile Include="Pages\Settings\SettingsPage.cs" />
<Compile Include="Pages\Settings\SettingsListFoldersPage.cs" />
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ISiteRepository.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Repositories\SettingsApiRepository.cs" />
<Compile Include="Repositories\ApiRepository.cs" />
<Compile Include="Repositories\AccountsApiRepository.cs" />
<Compile Include="Repositories\ConnectApiRepository.cs" />
<Compile Include="Repositories\BaseApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ISiteApiRepository.cs" />
<Compile Include="Repositories\AuthApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IAuthApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ILoginApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IConnectApiRepository.cs" />
<Compile Include="Repositories\DeviceApiRepository.cs" />
<Compile Include="Repositories\CipherApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" />
<Compile Include="Repositories\SiteApiRepository.cs" />
<Compile Include="Repositories\SettingsRepository.cs" />
<Compile Include="Repositories\LoginApiRepository.cs" />
<Compile Include="Repositories\FolderApiRepository.cs" />
<Compile Include="Repositories\SiteRepository.cs" />
<Compile Include="Repositories\LoginRepository.cs" />
<Compile Include="Repositories\FolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IRepository.cs" />
@@ -162,11 +184,29 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.es.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.zh.Designer.cs">
<Compile Include="Resources\AppResources.fi.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.zh.resx</DependentUpon>
<DependentUpon>AppResources.fi.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.fr.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.fr.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.sv.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.sv.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.zh-Hans.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.zh-Hans.resx</DependentUpon>
</Compile>
<Compile Include="Services\AppSettingsService.cs" />
<Compile Include="Services\SettingsService.cs" />
<Compile Include="Services\TokenService.cs" />
<Compile Include="Services\AppIdService.cs" />
<Compile Include="Abstractions\Services\ILockService.cs" />
<Compile Include="Services\LockService.cs" />
@@ -178,17 +218,18 @@
<Compile Include="Abstractions\Services\ISyncService.cs" />
<Compile Include="Abstractions\Services\IPasswordGenerationService.cs" />
<Compile Include="Services\SyncService.cs" />
<Compile Include="Services\SiteService.cs" />
<Compile Include="Services\LoginService.cs" />
<Compile Include="Services\AuthService.cs" />
<Compile Include="Services\CryptoService.cs" />
<Compile Include="Models\Page\VaultListPageModel.cs" />
<Compile Include="Pages\LoginPage.cs" />
<Compile Include="Pages\Settings\SettingsAddFolderPage.cs" />
<Compile Include="Pages\Vault\VaultAddSitePage.cs" />
<Compile Include="Pages\Vault\VaultViewSitePage.cs" />
<Compile Include="Pages\Vault\VaultEditSitePage.cs" />
<Compile Include="Pages\Vault\VaultListSitesPage.cs" />
<Compile Include="Pages\Vault\VaultAddLoginPage.cs" />
<Compile Include="Pages\Vault\VaultViewLoginPage.cs" />
<Compile Include="Pages\Vault\VaultEditLoginPage.cs" />
<Compile Include="Pages\Vault\VaultListLoginsPage.cs" />
<Compile Include="Services\PasswordGenerationService.cs" />
<Compile Include="Utilities\IdentityHttpClient.cs" />
<Compile Include="Utilities\Extentions.cs" />
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
<Compile Include="Utilities\ApiHttpClient.cs" />
@@ -203,24 +244,42 @@
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.zh.resx">
<EmbeddedResource Include="Resources\AppResources.fi.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.zh.Designer.cs</LastGenOutput>
<LastGenOutput>AppResources.fi.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.fr.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.fr.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.sv.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.sv.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.zh-Hans.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\public_suffix_list.dat" />
</ItemGroup>
<ItemGroup>
<Reference Include="Acr.UserDialogs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Acr.UserDialogs.6.3.2\lib\portable-win+net45+wp8+win8+wpa81\Acr.UserDialogs.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Acr.UserDialogs.6.3.10\lib\portable-win+net45+wp8+win8+wpa81\Acr.UserDialogs.dll</HintPath>
</Reference>
<Reference Include="Acr.UserDialogs.Interface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Acr.UserDialogs.6.3.2\lib\portable-win+net45+wp8+win8+wpa81\Acr.UserDialogs.Interface.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Acr.UserDialogs.6.3.10\lib\portable-win+net45+wp8+win8+wpa81\Acr.UserDialogs.Interface.dll</HintPath>
</Reference>
<Reference Include="HockeySDK, Version=1.0.6103.22141, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\HockeySDK.dll</HintPath>
<Private>True</Private>
<Reference Include="FFImageLoading, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\portable-net45+win8+wpa81+wp8\FFImageLoading.dll</HintPath>
</Reference>
<Reference Include="FFImageLoading.Forms, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.Forms.2.2.9\lib\portable-net45+win8+wpa81+wp8\FFImageLoading.Forms.dll</HintPath>
</Reference>
<Reference Include="FFImageLoading.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\portable-net45+win8+wpa81+wp8\FFImageLoading.Platform.dll</HintPath>
</Reference>
<Reference Include="HockeySDK, Version=1.0.6288.33979, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\HockeySDK.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
@@ -257,13 +316,11 @@
<HintPath>..\..\packages\PInvoke.Windows.Core.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Connectivity, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\portable-net45+wp80+wp81+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+Xamarin.Mac20+UAP10\Plugin.Connectivity.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Connectivity, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Connectivity.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\portable-net45+wp80+wp81+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+Xamarin.Mac20+UAP10\Plugin.Connectivity.Abstractions.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Connectivity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Fingerprint, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.2.0\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.dll</HintPath>
@@ -273,13 +330,11 @@
<HintPath>..\..\packages\Plugin.Fingerprint.1.2.0\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Settings, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Settings, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.Abstractions.dll</HintPath>
<Private>True</Private>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.dll</HintPath>
@@ -306,15 +361,15 @@
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.1\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_green.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_green.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.1\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_v2.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_v2.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.1\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Validation, Version=2.3.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
@@ -322,16 +377,13 @@
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.3.175\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1+Xamarin.iOS10\XLabs.Ioc.dll</HintPath>
@@ -348,12 +400,12 @@
<Compile Include="Services\PushNotificationListener.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -2,9 +2,12 @@
{
public static class Constants
{
public const string AndroidAppProtocol = "androidapp://";
public const string SettingFingerprintUnlockOn = "setting:fingerprintUnlockOn";
public const string SettingPinUnlockOn = "setting:pinUnlockOn";
public const string SettingLockSeconds = "setting:lockSeconds";
public const string SettingGaOptOut = "setting:googleAnalyticsOptOut";
public const string PasswordGeneratorLength = "pwGenerator:length";
public const string PasswordGeneratorUppercase = "pwGenerator:uppercase";

View File

@@ -4,23 +4,23 @@ using Xamarin.Forms;
namespace Bit.App.Controls
{
public class DismissModalToolBarItem : ToolbarItem
public class DismissModalToolBarItem : ExtendedToolbarItem, IDisposable
{
private readonly ContentPage _page;
private readonly Action _cancelClickedAction;
public DismissModalToolBarItem(ContentPage page, string text = null, Action cancelClickedAction = null)
: base(cancelClickedAction)
{
_cancelClickedAction = cancelClickedAction;
_page = page;
// TODO: init and dispose events from pages
InitEvents();
Text = text ?? AppResources.Close;
Clicked += ClickedItem;
Priority = -1;
}
private async void ClickedItem(object sender, EventArgs e)
protected async override void ClickedItem(object sender, EventArgs e)
{
_cancelClickedAction?.Invoke();
base.ClickedItem(sender, e);
await _page.Navigation.PopModalAsync();
}
}

View File

@@ -10,7 +10,7 @@ namespace Bit.App.Controls
{
private ISyncService _syncService;
private IGoogleAnalyticsService _googleAnalyticsService;
private ISettings _settings;
private ILockService _lockService;
private bool _syncIndicator;
private bool _updateActivity;
@@ -20,7 +20,7 @@ namespace Bit.App.Controls
_updateActivity = updateActivity;
_syncService = Resolver.Resolve<ISyncService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_settings = Resolver.Resolve<ISettings>();
_lockService = Resolver.Resolve<ILockService>();
BackgroundColor = Color.FromHex("efeff4");
@@ -45,11 +45,6 @@ namespace Bit.App.Controls
IsBusy = _syncService.SyncInProgress;
}
if(_updateActivity)
{
_settings.AddOrUpdateValue(Constants.LastActivityDate, DateTime.UtcNow);
}
_googleAnalyticsService.TrackPage(GetType().Name);
base.OnAppearing();
}
@@ -61,6 +56,11 @@ namespace Bit.App.Controls
IsBusy = false;
}
if(_updateActivity)
{
_lockService.UpdateLastActivity();
}
base.OnDisappearing();
}
}

View File

@@ -0,0 +1,30 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedToolbarItem : ToolbarItem, IDisposable
{
public ExtendedToolbarItem(Action clickAction = null)
{
ClickAction = clickAction;
}
public Action ClickAction { get; set; }
protected virtual void ClickedItem(object sender, EventArgs e)
{
ClickAction?.Invoke();
}
public void InitEvents()
{
Clicked += ClickedItem;
}
public void Dispose()
{
Clicked -= ClickedItem;
}
}
}

View File

@@ -3,7 +3,7 @@ using Xamarin.Forms;
namespace Bit.App.Controls
{
public class FormEditorCell : ExtendedViewCell
public class FormEditorCell : ExtendedViewCell, IDisposable
{
public FormEditorCell(Keyboard entryKeyboard = null, double? height = null)
{
@@ -26,7 +26,6 @@ namespace Bit.App.Controls
stackLayout.Children.Add(Editor);
Tapped += FormEditorCell_Tapped;
Editor.AdjustMarginsForDevice();
stackLayout.AdjustPaddingForDevice();
@@ -39,5 +38,15 @@ namespace Bit.App.Controls
{
Editor.Focus();
}
public void InitEvents()
{
Tapped += FormEditorCell_Tapped;
}
public void Dispose()
{
Tapped -= FormEditorCell_Tapped;
}
}
}

View File

@@ -1,12 +1,16 @@
using Bit.App.Abstractions;
using FFImageLoading.Forms;
using System;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Controls
{
public class FormEntryCell : ExtendedViewCell
public class FormEntryCell : ExtendedViewCell, IDisposable
{
private VisualElement _nextElement;
private TapGestureRecognizer _tgr;
public FormEntryCell(
string labelText,
Keyboard entryKeyboard = null,
@@ -17,6 +21,8 @@ namespace Bit.App.Controls
Thickness? containerPadding = null,
bool useButton = false)
{
_nextElement = nextElement;
if(!useLabelAsPlaceholder)
{
Label = new Label
@@ -47,7 +53,6 @@ namespace Bit.App.Controls
if(nextElement != null)
{
Entry.ReturnType = Enums.ReturnType.Next;
Entry.Completed += (object sender, EventArgs e) => { nextElement.Focus(); };
}
var imageStackLayout = new StackLayout
@@ -61,16 +66,17 @@ namespace Bit.App.Controls
if(imageSource != null)
{
var tgr = new TapGestureRecognizer();
tgr.Tapped += Tgr_Tapped;
_tgr = new TapGestureRecognizer();
var theImage = new Image
var theImage = new CachedImage
{
Source = imageSource,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.Center
VerticalOptions = LayoutOptions.Center,
WidthRequest = 18,
HeightRequest = 18
};
theImage.GestureRecognizers.Add(tgr);
theImage.GestureRecognizers.Add(_tgr);
imageStackLayout.Children.Add(theImage);
}
@@ -126,8 +132,6 @@ namespace Bit.App.Controls
}
}
Tapped += FormEntryCell_Tapped;
View = imageStackLayout;
}
@@ -135,6 +139,21 @@ namespace Bit.App.Controls
public ExtendedEntry Entry { get; private set; }
public ExtendedButton Button { get; private set; }
public void InitEvents()
{
if(_nextElement != null)
{
Entry.Completed += Entry_Completed;
}
if(_tgr != null)
{
_tgr.Tapped += Tgr_Tapped;
}
Tapped += FormEntryCell_Tapped;
}
private void Tgr_Tapped(object sender, EventArgs e)
{
Entry.Focus();
@@ -144,5 +163,21 @@ namespace Bit.App.Controls
{
Entry.Focus();
}
private void Entry_Completed(object sender, EventArgs e)
{
_nextElement?.Focus();
}
public void Dispose()
{
if(_tgr != null)
{
_tgr.Tapped -= Tgr_Tapped;
}
Tapped -= FormEntryCell_Tapped;
Entry.Completed -= Entry_Completed;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using Bit.App.Resources;
using Xamarin.Forms;
namespace Bit.App.Controls
@@ -42,8 +41,6 @@ namespace Bit.App.Controls
Picker.AdjustMarginsForDevice();
stackLayout.AdjustPaddingForDevice();
Tapped += FormPickerCell_Tapped;
View = stackLayout;
}
@@ -54,5 +51,15 @@ namespace Bit.App.Controls
{
Picker.Focus();
}
public void InitEvents()
{
Tapped += FormPickerCell_Tapped;
}
public void Dispose()
{
Tapped -= FormPickerCell_Tapped;
}
}
}

View File

@@ -1,4 +1,5 @@
using Xamarin.Forms;
using FFImageLoading.Forms;
using Xamarin.Forms;
namespace Bit.App.Controls
{
@@ -19,6 +20,14 @@ namespace Bit.App.Controls
Style = (Style)Application.Current.Resources["text-muted"]
};
LabelIcon = new CachedImage
{
WidthRequest = 16,
HeightRequest = 16,
HorizontalOptions = LayoutOptions.Start,
Margin = new Thickness(5, 0, 0, 0)
};
Button = new ExtendedButton
{
WidthRequest = 60
@@ -32,11 +41,14 @@ namespace Bit.App.Controls
};
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(60, GridUnitType.Absolute) });
grid.Children.Add(Label, 0, 0);
grid.Children.Add(Detail, 0, 1);
grid.Children.Add(Button, 1, 0);
grid.Children.Add(LabelIcon, 1, 0);
grid.Children.Add(Button, 2, 0);
Grid.SetColumnSpan(Detail, 2);
Grid.SetRowSpan(Button, 2);
if(Device.OS == TargetPlatform.Android)
@@ -49,6 +61,7 @@ namespace Bit.App.Controls
public Label Label { get; private set; }
public Label Detail { get; private set; }
public CachedImage LabelIcon { get; private set; }
public Button Button { get; private set; }
}
}

View File

@@ -0,0 +1,108 @@
using Bit.App.Abstractions;
using System;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Controls
{
public class MemoryContentView : ContentView
{
private readonly IMemoryService _memoryService;
public MemoryContentView()
{
_memoryService = Resolver.Resolve<IMemoryService>();
var grid = new Grid
{
Padding = 5,
BackgroundColor = Color.White,
RowDefinitions = new RowDefinitionCollection
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto }
},
ColumnDefinitions = new ColumnDefinitionCollection
{
new ColumnDefinition { Width = GridLength.Star },
new ColumnDefinition { Width = GridLength.Star }
}
};
grid.Children.Add(new Label { Text = "Used Memory:" }, 0, 0);
grid.Children.Add(new Label { Text = "Free Memory:" }, 0, 1);
grid.Children.Add(new Label { Text = "Heap Memory:" }, 0, 2);
grid.Children.Add(new Label { Text = "Max Memory:" }, 0, 3);
grid.Children.Add(new Label { Text = "% Used Heap:" }, 0, 4);
grid.Children.Add(new Label { Text = "% Used Max:" }, 0, 5);
UsedMemory = new Label { Text = "Used Memory:", HorizontalTextAlignment = TextAlignment.End };
FreeMemory = new Label { Text = "Free Memory:", HorizontalTextAlignment = TextAlignment.End };
HeapMemory = new Label { Text = "Heap Memory:", HorizontalTextAlignment = TextAlignment.End };
MaxMemory = new Label { Text = "Max Memory:", HorizontalTextAlignment = TextAlignment.End };
HeapUsage = new Label { Text = "% Used Heap:", HorizontalTextAlignment = TextAlignment.End };
TotalUsage = new Label { Text = "% Used Max:", HorizontalTextAlignment = TextAlignment.End };
grid.Children.Add(UsedMemory, 1, 0);
grid.Children.Add(FreeMemory, 1, 1);
grid.Children.Add(HeapMemory, 1, 2);
grid.Children.Add(MaxMemory, 1, 3);
grid.Children.Add(HeapUsage, 1, 4);
grid.Children.Add(TotalUsage, 1, 5);
var button = new ExtendedButton { Text = "Refresh", BackgroundColor = Color.Transparent };
button.Clicked += Button_Clicked;
grid.Children.Add(button, 0, 6);
Grid.SetColumnSpan(button, 2);
Content = grid;
RefreshScreen();
}
private void Button_Clicked(object sender, EventArgs e)
{
RefreshScreen();
}
public Label UsedMemory { get; set; }
public Label FreeMemory { get; set; }
public Label HeapMemory { get; set; }
public Label MaxMemory { get; set; }
public Label HeapUsage { get; set; }
public Label TotalUsage { get; set; }
void RefreshScreen()
{
UsedMemory.Text = FreeMemory.Text = HeapMemory.Text = MaxMemory.Text =
HeapUsage.Text = TotalUsage.Text = string.Empty;
UsedMemory.TextColor = FreeMemory.TextColor = HeapMemory.TextColor =
MaxMemory.TextColor = HeapUsage.TextColor = TotalUsage.TextColor = Color.Black;
if(_memoryService != null)
{
var info = _memoryService.GetInfo();
if(info != null)
{
UsedMemory.Text = string.Format("{0:N} mb", Math.Round(info.UsedMemory / 1024 / 1024D, 2));
FreeMemory.Text = string.Format("{0:N} mb", Math.Round(info.FreeMemory / 1024 / 1024D, 2));
HeapMemory.Text = string.Format("{0:N} mb", Math.Round(info.TotalMemory / 1024 / 1024D, 2));
MaxMemory.Text = string.Format("{0:N} mb", Math.Round(info.MaxMemory / 1024 / 1024D, 2));
HeapUsage.Text = string.Format("{0:P}", info.HeapUsage());
TotalUsage.Text = string.Format("{0:P}", info.Usage());
if(info.Usage() > 0.8)
{
FreeMemory.TextColor = UsedMemory.TextColor = TotalUsage.TextColor = Color.Red;
}
}
}
}
}
}

View File

@@ -22,7 +22,6 @@ namespace Bit.App.Controls
MaxLength = 4,
Margin = new Thickness(0, int.MaxValue, 0, 0)
};
Entry.TextChanged += Entry_TextChanged;
if(Device.OS == TargetPlatform.Android)
{
@@ -30,6 +29,9 @@ namespace Bit.App.Controls
}
}
public Label Label { get; set; }
public ExtendedEntry Entry { get; set; }
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if(e.NewTextValue.Length >= 4)
@@ -38,7 +40,14 @@ namespace Bit.App.Controls
}
}
public Label Label { get; set; }
public ExtendedEntry Entry { get; set; }
public void InitEvents()
{
Entry.TextChanged += Entry_TextChanged;
}
public void Dispose()
{
Entry.TextChanged -= Entry_TextChanged;
}
}
}

View File

@@ -34,8 +34,6 @@ namespace Bit.App.Controls
Value = value
};
Stepper.ValueChanged += Stepper_ValueChanged;
var stackLayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
@@ -56,13 +54,23 @@ namespace Bit.App.Controls
View = stackLayout;
}
public Label Label { get; private set; }
public Label StepperValueLabel { get; private set; }
public Stepper Stepper { get; private set; }
private void Stepper_ValueChanged(object sender, ValueChangedEventArgs e)
{
StepperValueLabel.Text = e.NewValue.ToString();
}
public Label Label { get; private set; }
public Label StepperValueLabel { get; private set; }
public Stepper Stepper { get; private set; }
public void InitEvents()
{
Stepper.ValueChanged += Stepper_ValueChanged;
}
public void Dispose()
{
Stepper.ValueChanged -= Stepper_ValueChanged;
}
}
}

View File

@@ -0,0 +1,34 @@
using Bit.App.Models.Page;
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class VaultListViewCell : LabeledDetailCell
{
public static readonly BindableProperty LoginParameterProperty = BindableProperty.Create(nameof(LoginParameter),
typeof(VaultListPageModel.Login), typeof(VaultListViewCell), null);
public VaultListViewCell(Action<VaultListPageModel.Login> moreClickedAction)
{
SetBinding(LoginParameterProperty, new Binding("."));
Label.SetBinding<VaultListPageModel.Login>(Label.TextProperty, l => l.Name);
Detail.SetBinding<VaultListPageModel.Login>(Label.TextProperty, l => l.Username);
LabelIcon.SetBinding<VaultListPageModel.Login>(VisualElement.IsVisibleProperty, l => l.Shared);
Button.Image = "more";
Button.Command = new Command(() => moreClickedAction?.Invoke(LoginParameter));
Button.BackgroundColor = Color.Transparent;
LabelIcon.Source = "share";
BackgroundColor = Color.White;
}
public VaultListPageModel.Login LoginParameter
{
get { return GetValue(LoginParameterProperty) as VaultListPageModel.Login; }
set { SetValue(LoginParameterProperty, value); }
}
}
}

View File

@@ -2,7 +2,8 @@
{
public enum CipherType : short
{
Folder = 0,
Site = 1
// Folder deprecated
//Folder = 0,
Login = 1
}
}

View File

@@ -0,0 +1,11 @@
namespace Bit.App.Enums
{
public enum EncryptionType : byte
{
AesCbc256_B64 = 0,
AesCbc128_HmacSha256_B64 = 1,
AesCbc256_HmacSha256_B64 = 2,
Rsa2048_OaepSha256_B64 = 3,
Rsa2048_OaepSha1_B64 = 4
}
}

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