[
  {
    "path": ".gitattributes",
    "content": "CHANGELOG merge=union\n"
  },
  {
    "path": ".gitignore",
    "content": "# built application files\n*.apk\n*.ap_\n\n# files for the dex VM\n*.dex\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\ndev/\n*.pyc\n.DS_Store\n*.orig\n\n# Local Eclipse files\n.classpath\n.project\n\n# Android studio\n.gradle\nbuild/\n*.iws\n*.ipr\n*.swp\nout/\n.idea/libraries\n.idea/workspace.xml\n.idea/misc.xml\n.idea/vcs.xml\n.idea/*\n*.iml\n.idea\n\n\n#Project specific\napp/src/main/java/com/liato/bankdroid/db/Crypto.*\napp/src/main/java/com/liato/bankdroid/db/Crypto.java.dev\ndev/\napp/release.keystore\napp/crashlytics.properties\napp/keystore.properties\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\njdk: oraclejdk8\n\nbefore_cache:\n  - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock\ncache:\n  directories:\n    - $HOME/.gradle/caches/\n    - $HOME/.gradle/wrapper/\n\nenv:\n  matrix:\n    - ANDROID_TARGET=android-25  ANDROID_ABI=armeabi-v7a\n\nandroid:\n  components:\n    - tools\n    - platform-tools\n    - build-tools-25.0.1\n    - android-25\n    - extra-android-m2repository\n\nscript: ./gradlew assembleDebug check\n\nnotifications:\n  email: false\n  slack:\n    secure: asrV7/94tGqJbhotBAkPFi80PWJY3lcu7uYo855kpujXQHP61b0gC5gHnAairdD+MtrwICOmsJE9KIK/HOIpFrzwE+IwxJ+p6cGL9kX9blX+ZThcz1HkZgEK/EgaMSUxLKZFGrz0LUdktoZ9h+VixeRg05S4VijA7A814iA78fI=\n\nbranches:\n  except:\n    - gh-pages\n    - transaction-uid\n"
  },
  {
    "path": "CHANGELOG",
    "content": "Please view this file on the master branch, on stable branches it's out of date.\n\n(Unreleased)\n* Update certificates\n* Remove support for Avanza and Avanza Mini\n\nv1.9.14 (2017-01-06)\n* Updated certificates for First Card, Osuuspankki and Östgötatrafiken\n\nv1.9.13 (2016-11-03)\n* Fixes Crashlytics logging issue\n\nv1.9.12 (2016-11-02)\n* Bioklubben: Use https. It's secure and http page no longer exists.\n* Östgötatrafiken: Adapt to new login page (Facebook login not supported)\n* Removes broken encryption\n\nv1.9.11 (2016-10-26)\n* Warn about disabled banks in the transactions list\n* Show warning text about disabled banks in the main activity\n* Removes support for TrustBuddy since they're no longer in business\n* Removes support for Audi since they require MobiltBankId\n* Removes support for VolvoFinans since they require MobiltBankId\n* Removes support for EasyCard since they require MobiltBankId\n* Removes support for Preem since they require MobiltBankId\n* Removes support for ResursBank since they require MobiltBankId\n* Removes support for Seat since they require MobiltBankId\n* Removes support for Shell since they require MobiltBankId\n* Removes support for Skoda since they require MobiltBankId\n* Removes support for SupremeCard since they require MobiltBankId\n* Removes support for Villabanken since they require MobiltBankId\n* Removes support for Volkswagen since they require MobiltBankId\n* Merged NordnetDirekt with Nordnet.\n* Merged AvanzaMini with Avanza.\n\nv1.9.10.10 (2016-10-17)\n* Fixes crash for Amex\n* Strikethrough balance in widget indicates update problems.\n\nv1.9.10.9 (2016-10-12)\n* Länsförsäkringar: Remove broken web links\n* Improve Javadocs in the Bank class\n* Make successfully refreshing a disabled bank re-enable it\n* Östgötatrafiken: Update certificate\n* Östgötatrafiken: Adapt to changed web page\n* Skip Server Name Indication (SNI) when refreshing bank certificates to avoid certificate mismatches (bankdroid doesn't use SNI)\n* Ticket Rikskortet: Adapt to changed web page\n* Removes IcaBanken since they now require BankID\n* SveaDirekt: Adapt to changed web page\n* Rikslunchen: Adapt to new web service\n* AmericanExpress: Use their mobile API\n\nv1.9.10.8 (2016-09-29)\n* Add a Volatile account to the Test Bank that always changes its balance.\n* Fix widget not updating when the balance change was lower than the notification threshold.\n\nv1.9.10.7 (2016-08-18)\n* Update certificates for AmericanExpress and Coop\n\nv1.9.10.6 (2016-08-01)\n* Update outdated certificates\n* Upgrade to android-build-tools v.24\n* Upgrade to gradle 2.14\n\nv1.9.10.5 (2016-04-03)\n* Fix for OKQ8\n* Update certificates for AmericanExpress, DankeBank, FirstCard, Rikslunchen and SveaDirekt.\n\nv1.9.10.4 (2016-02-25)\n* Removes support for EspressoHouse\n* Adds support Högskolerestaurangers kund-/studentkort\n* Update certificates for American Express, Marginalen, PayPal, Ticket Rikskortet, Zidisha, Östgötatrafiken\n\nv1.9.10.3 (2015-12-24)\n* Fix for Länsförsäkringar\n\nv1.9.10.2 (2015-12-22)\n* Fixes for Coop login.\n* Removes support for Forex Bank due to BankId requirement.\n* Fixes for MinPension login.\n* Update certificates for Coop, ICA, Osuuspankki, PlusGirot, SevenDay, Meniga & Steam.\n* Fixes for Bredband2.\n* Added support for Android 6.0 Marshmallow.\n\nv1.9.10.1 (2015-11-22)\n* Update certificate for ICA.\n* Fixes bug where banks without password could not be added.\n\nv1.9.10.0 (2015-11-06)\n* Removes support for PayPal due to complex web-login.\n* Removes support for Swedbank, Sparbankerna, Marginalen and NordeaDK due to BankId requirement.\n* Updates certificates for Bredband2, EasyCard, Nordea DK, Nordnet, Östgötatrafiken, Osuuspankki, PayPal, Villabanken\n* Adds support for custom properties for bank implementations.\n\nv1.9.9.5 (2015-07-18)\n* Updates certificates for Akelius Spar, Akelius Invest, Hemköp and Resurs Bank\n\nv1.9.9.4 (2015-06-12)\n* Fixes parsing of incoming payments for American Express (thanks to mhagander)\n* Updates certificates for Nordnet, Avanza, Länsförsäkringar, Forex Bank, OKQ8 and Volvo Finans\n\nv1.9.9.3 (2015-05-24)\n* Updates certificates for Paypal, AmericanExpress, Svenska spel\n\nv1.9.9.2 (2015-04-16)\n* Updates certificates for AmericanExpress, MinPension, Swedbank and Sparbankerna\n* Adapt to new URLs used by Ticket Rikskortet\n* Fixes application crash for Samsung devices running Android 4.2\n\nv1.9.9.1 (2015-04-09)\n* Fixes application crash for Jojo accounts.\n* Removes support for DinersClub due to BankId requirement.\n* Fixes login issues with some PayPal accounts.\n\nv1.9.9.0 (2015-04-02)\n* Adds support for minpension.se.\n* Adds option to disable auto updates while roaming.\n* Removes Skandiabanken due to their new BankId requirement.\n* Fixes issue with Nordnet (thanks to jonasgroth).\n* Fixes crash when account is not available from widget.\n* Fixes transactions for Forex Bank (thanks to jonasgroth).\n* Fixes transaction issues for EspressoHouse.\n* Fixes Payson balance. NOTE: Transactions not supported yet (thanks to robho).\n* Fixes LockPattern crashes for Samsung Galaxy devices.\n* Fixes issue with PayPal (now even supporting WWW login and transactions).\n* Updates certificates for IkanoPartners\n* Removes support for Sparbanken Öresund due to BankId requirement.\n\nv1.9.8.0 (2015-02-27)\n* Adds support for Bredband2's VoIP service (thanks to fredrike)\n* Adds support for EspressoHouse (thanks to fredrike)\n* Adds support for multiple travel cards for JoJo Reskassa\n* Sets subaccounts for Avanza to hidden by default (thanks to fredrike)\n* Order transactions by descending date\n* Fixes www login for Blekingetrafiken (thanks to fredrike)\n* Fixes www login for Avanza (thanks to fredrike)\n* Fixes date formatting for VolvoFinans\n* Fixes application crash for Coop.\n* Fixes application crash when setting LockPattern on some devices\n* Fixes support for Nordea accounts with number in the account name\n* Fixes Swedbank and Sparbankerna if you have corporate credit card\n* Fixes www login for Coop\n* Fixes application crash if SonyEricsson's LiveView integration is enabled\n* Fixes application crash if screen is rotated during a bank update\n* Improved error handling\n* Disabled www-button for Swedbank and Sparbankerna\n* Updated certificate for Östgötatrafiken, AmericanExpress, Brummer KF\n* Removes support for Handelsbanken, SEB, Chevrolet, Djurgarden, EurobonusMastercard, EurobonusMastercardDk, EurobonusMastercardNo, Eurocard, Opel, Quintessentially, SJPrio, Saab, Statoil, Wallet because they now requires BankId.\n\nv1.9.7.4: (2015-02-21)\n* Updated certificates for ICA Banken, Västtrafik, Brummer KF, Diners Club, Ikano Bank, Marginalen, Trustbuddy, Zidisha, AmericanExpress, TicketRikskortet\n* Adds support for Coop's MedMera-Före and MedMera-Efter (thanks to fredrike)\n* Adds support for Blekingetrafiken (thanks to fredrike)\n* Adds support for Östgötatrafiken (thanks to robho)\n* Adds support for point account and transactions for Coop (thanks to fredrike)\n* Adds support for Coop's MedMera Efter credit card (thanks to fredrike)\n* Adds possibility to go back to the account view from the transaction view by clicking on the logotype (thanks to fredrike)\n* Use SvenskaSpel's API (thanks to mikaeler)\n* Fix for null currency for credit cards for Swedbank and Sparbankerna. Defaults to SEK.\n* Fix Handshake failed errors for FirstCard and PostGirot\n* Fix for credit card currency error for Nordea (thanks to Ree)\n* Fix for Västtrafik (thanks to jonasgroth)\n* Fix balance for Avanza (thanks to fredrike)\n\nv1.9.7.3: (2014-11-21)\n* Fix for Nordea balance (thanks to sed)\n* Fix for widget sizes\n\n\nv1.9.7.2: (2014-11-20)\n* Quickfix for widgets, still work to be done\n* Improved account order for Swedbank (thanks to goober)\n\n\nv1.9.7.1: (2014-11-19)\n* Swedbank and Sparbankerna: Show transactions, fix for widget, credit card transactions, various fixes (thanks to goober, cortex, mikaeler)\n* Updated certificate for American Express, Brummer KF, CSN, EasyCard, FirstCard, ICA, Jojo, Meniga, Nordea DK, PlusGirot, Svenskaspel and Västtrafik (thanks to goober, Niclasl, auno)\n* Account balance for Nordea credit cards (thanks to sed03)\n* Fix for Jojo (thanks to sed03)\n* Toggle account visibility by long pressing an account (thanks to fredrike)\n* Show all account types for Avanza (thanks to fredrike)\n\n\nv1.9.7.0: (2014-10-31)\n* Fix for Nordea (thanks to rhoot and wicol)\n* Use Swedbank's API (thanks to goober for the implementation and Swedbank for giving us access to their API)\n* Updated SSL certificate for Skandiabanken\n* Fix for Chalmrest balance (thanks to emilan)\n\n\nv1.9.6.16: (2014-09-18)\n* Updated SSL certificates for American Express, Coop, Eurocard, Forex Bank, Ikano Bank, Marginalen Bank, Meniga, Nordnet, Nordnet Direkt, OKQ8, Payson, Rikslunchen, SevenDay, Trustbuddy and Villabanken\n* Improvements to Villabanken account parsing (thanks to knifhen)\n* Improvements to Coop\n\n\nv1.9.6.15: (2014-06-07)\n* Fix for Coop MedMedmera Visa and Coop Kort\n* Updated SSL certificate for SEB cards (SAS Eurobonus, SJPrio, Statoil and more)\n* Allow all characters when entering username for PlusGirot\n* Updated SevenDay SSL certificate\n* Improvements to ResursBank\n* Login fix for Ikano Partner cards (Ikea, Preem, Shell, Skoda and more)\n\n\nv1.9.6.14: (2014-05-13)\n* Fix for ICA Banken\n* Fix for Payson\n* Partial fix for Coop\n+ Support for Sveadirekt (thanks to goober)\n+ Support for Supreme Card\n\n\nv1.9.6.13: (2014-04-30)\n* Prevent recent apps thumbnail for pattern lock and settings\n* Updated SSL certificate for American Express, Coop, CSN, Handelsbanken, Osuuspankki, PayPal, Resurs Bank, Sevenday and Zidisha.\n\n\nv1.9.6.12: (2014-04-14)\n* Updated SSL certificate for Nordea\n\n\nv1.9.6.11: (2014-04-10)\n* Updated SSL certificate for Swedbank\n* Transactions working for ICA accounts\n* Fix for ICA Banken\n\n\nv1.9.6.10: (2014-03-26)\n* Updated SSL certificate for Akelius Invest\n* Fix ICA for accounts with transactions\n\n\nv1.9.6.9: (2014-03-24)\n* Updated SSL certificate for Avanza\n* Use Avanza implementation for Avanza Mini\n* Update ICA implementation to use internal ICA API\n\n\nv1.9.6.8: (2014-03-20)\n* Updated SSL certificate for American Express\n* Fix for PayPal\n* Fix for ICA Banken (new api-key)\n\n\nv1.9.6.7: (2014-02-21)\n* Fix login fields parsing for Nordnet\n* Fix for regular Jojo cards\n* Use FLAG_SECURE for ICS and newer to prevent thumbnail in recent tasks list\n* Updated SSL certificates for American Express and Swedbank\n\n\nv1.9.6.6: (2014-01-24)\n* Fix for Lunchkortet\n* Fix for Jojo\n* Updated SSL certificates for Ticket Rikskortet, Paypal, Avanza, Avanza Mini and Payson\n\n\nv1.9.6.5: (2013-12-19)\n* Correct currency for SAS Eurobonus Mastercard Norway and Denmark\n* Fix for ICA Banken (new api-key)\n\n\nv1.9.6.4: (2013-12-13)\n* Fix for SAS Eurobonus Mastercard Norway﻿\n* Fix for SEB Cards (Eurocard, SAS Eurobonus, Statoil, SJ Prio...) with multiple accounts﻿\n* Fix for Bitcoin where transfers had notes\n* Fix for ICA Banken\n\n\nv1.9.6.3: (2013-12-05)\n* Fix for American Express\n* Fix for Eurocard\n* Fix for SAS Eurobonus Mastercard\n* Fix for Statoil Mastercard\n* Fix for Bioklubben\n* Fix for SJPrio\n* Various bugfixes\n\n\nv1.9.6.2: (2013-11-03)\n* Fix for Avanza (thanks to NanoRage)\n* Fix for Ikano Bank\n* Improved security of secure connection with certificate pinning\n+ Support for Eurobonus Mastercard Denmark\n+ Support for Bitcoin\n\n\nv1.9.6.1: (2013-09-30)\n* Fix for PayPal\n* Fix for Diners Club (thanks to ScuttleSE)\n* ICA Banken uses their API (thanks to goober)\n* Fix for multiple accounts in Forex Bank (thanks to rickythefox)\n* Fix for Villabanken (thanks to knifhen)\n+ Support for SAS EuroBonus MasterCard Norway\n- Removed Danske Bank\n- Removed Sparbanken Öresund\n\n\nv1.9.6.0: (2013-06-22)\n* Fix for PayPal\n* Fix for Hemköp\n* Fix for ICA\n* Fix for Volvofinans\n+ Support for Forex Bank (thanks to rickythefox)\n+ Support for BetterGlobe (thanks to Tuxie)\n+ Support for Zidisha (thanks to Tuxie)\n\n\nv1.9.5.4: (2013-04-28)\n* Fix for Rikslunchen (thanks to chrfle)\n* Fix for Audikortet (maybe)\n+ Support for TrustBuddy (thanks to Tuxie)\n+ Support for Brummer Privat KF (thanks to Tuxie)\n\n\nv1.9.5.3: (2013-04-02)\n* Fix for Skodakortet\n* Fix for Volvofinans transactions\n* Fix for reappearing Akelius Spar/Invest accounts\n\n\nv1.9.5.2: (2013-03-27)\n* Fix for Coop\n* Show multiple Nordnet accounts\n\n\nv1.9.5.1: (2013-02-26)\n* Fix for Länsförsäkringar saving accounts\n\n\nv1.9.5: (2013-02-21)\n* Fix for Länsförsäkringar\n+ Support for Svenska Spel (thanks to nixi)\n+ Support for Appeak Poker\n\n\nv1.9.4: (2013-01-04)\n* Fix for ICA Banken transactions (thanks to fruktsallad)\n* Fix for Länsförsäkringar\n* Fix for Skandiabanken accounts without transactions\n* Fix for Amex transactions (thanks to goober)\n* Fixes for Marginalen Bank (thanks to jsiverskog)\n\n\nv1.9.3: (2012-11-29)\n+ Support for Marginalen Bank (thanks to jsiverskog)\n* Fix for password saving in Android 4.2+ (thanks to gfu)\n* Fix for ICA (thanks to oskla129)\n* Fix reappearing accounts on ICA Banken\n\n\nv1.9.2: (2012-10-21)\n* Fix for Länsförsäkringar - Now uses the same API as their official app\n\n\nv1.9.1: (2012-10-11)\n+ Support for Chalmrest (thanks to emilan)\n* Fix for Västtrafik (thanks to erifre)\n* Fix for Nordea captcha - login as many times as you want with the built in captcha breaker\n* Fix for Bioklubben\n* Fix for PayPal\n* Better auto updates with SEB\n* Fix for EverydayCard (thanks  to d95andek)\n* Fix for Volvofinans (thanks to d95andek)\n- Removed support for Steam Wallet\n\n\nv1.9.0: (2012-06-25)\n+ Support for Ticket Rikskortet\n+ Support for Bioklubben\n* Fix for Meniga (thanks to bjooork)\n* Fix for Nordea DK (thanks to goober)\n* Fix for Västtrafik (thanks to erifre)\n* Fix for Statoil Mastercard\n* Fix for SAS Eurobonus Mastercard\n* Fix for Eurocard\n\n\nv1.8.9: (2012-04-16)\n+ New setting: Number of simultaneous notifications\n* Fix for graphical bug on devices running older versions of Android (sorry for the poor testing before release)\n\n\nv1.8.8: (2012-04-13)\n+ Support for Meniga (thanks to bjooork)\n+ New notification setting: Display change only\n+ Disable thumbnail in recent apps list (Honeycomb, ICS)\n* Fix for Skandiabanken, now using their internal JSON-api (thanks to woody)\n* Fix for Jojo (thanks to wanders)\n* Fix for Rikslunchen (thanks to mafa73)\n* Fix for IKEA\n\n\nv1.8.7: (2012-01-29)\n* Fix for SEB\n* Fix for double lock pattern when opening transactions view from widget\n\n\nv1.8.6: (2012-01-29)\n* Fix for SEB\n* Fix for LED color picker on pre ICS devices\n\n\nv1.8.5: (2012-01-27)\n+ Support for LED notifications\n+ Support for Akelius Invest\n* Fix for Coop\n* Fix for Hemköp\n* Fix for SEB\n* Fix for SevenDay\n* Fix for ICA\n\n\nv1.8.4: (2011-12-04)\n* Fix for Coop\n* Fix for Länsförsäkringar (thanks to MatsKarlsson!)\n+ Support for Everydaycard (thanks to d95andek!)\n+ Hardware acceleration is now activated for Honeycomb and ICS\n* Smarter automatic updates\n\n\nv1.8.3: (2011-11-13)\n+ Support for American Express\n+ Support for Västtrafik\n* Fix for SEB\n\n\nv1.8.1: (2011-09-26)\n+ Support for Danske Bank\n+ Support for Nordea (Danmark) (thanks to goober!)\n* Fix for Skandiabanken (thanks to woody!)\n\n\nv1.8.0: (2011-08-24)\n+ Support for AudiKortet\n+ Support for Chevrolet Big Plus Card\n+ Support for Djurgårdskortet\n+ Support for IKEA HANDLA Kort\n+ Support for Nordnetdirekt\n+ Support for PlusGirot\n+ Support for Preem Privatkort\n+ Support for Quintessentially Credit Card\n+ Support for SaabKortet\n+ Support for Seatkortet\n+ Support for Shell MasterCard\n+ Support for Skandiabanken (thanks to woody)\n+ Support for Skodakortet\n+ Support for Volkswagenkortet\n+ Support for wallet MasterCard\n* Fix for ICA\n+ Support for Sony Ericcson LiveView notifications (thanks to firetech)\n+ New setting: Only update between user defined times (thanks to woody)\n* Fix for security bug where a user could circumvent the password protection\n* Calculate the total amount correctly\n+ Donate button added\n\n\nv1.7.3 (2011-05-04)\n* Fix for Jojo\n+ Support for OpelKortet\n+ Support for SJ Prio MasterCard\n+ Support for Sparbanken Syd\n+ Support for Sparbanken Öresund\n+ Show old CSN loans\n+ Multi-bank support for Swedbank\n+ New setting: Display balance without decimals\n+ New setting: Smallest change to trigger notification\n\n\nv1.7.2: (2011-04-14)\n* Fix for Swedbank transactions (update account from app to see transactions)\n* Fix for Länsförsäkringar\n+ New setting: Update transaction history from widget\n\n\nv1.7.1: (2011-04-12)\n* Fix for Swedbank\n* For for Payson when using multiple currencies\n* Support for multiple currencies in DinersClub\n* Improved error handling for CSN\n+ Progress bar in webview\n+ Bank icons when choosing a bank\n+ Setting: Disable visible pattern on pattern lock\n\n\nv1.7.0: (2011-03-25)\n+ Support for SevenDay\n+ Support for Nordnet\n+ Support for Osuuspankki/Andelsbanken\n+ Support for Volvofinans\n+ Support for Resurs Bank\n+ Support for Länsförsäkringar Pension\n+ Support for McDonald's Presentkort\n+ New setting: Open main view or transactions view from widget\n+ Loans information for Swedbank\n+ Support for additional currencies for Nordea\n* Repayments to CSN are shown as transactions\n* Fixed FC-bug in Länsförsäkringar if user had pension account\n* Sort and display all transactions for SEB\n* New logo for Ikano Bank (after complaints from Ikano that the old one did not follow their graphic guidelines)\n* Fix for FirstCard\n* Sorted transactions for Statoil and Eurobonus\n* Show all transactions for Eurocard\n* \"Home\" button clears history stack\n\n\nv1.6.3: (2011-02-06)\n* FC fix when opening settings\n\n\nv1.6.2: (2011-02-05)\n+ Support for SEB (automatic website login doesn't work yet)\n+ Support for SAS EuroBonus Mastercard\n+ Support for Rikslunchen\n+ Support for Hemköp Kundkort\n+ Transactions for Diners Club\n* PayPal business accounts are now supported\n+ Content Provider - Lets other apps use data from Bankdroid after user confirmation\n\n\nv1.6.1: (2010-12-29)\n* Fix for FC when using pattern lock in landscape mode\n* Larger hit box on \"Home\" button\n\n\nv1.6.0: (2010-12-29)\n+ Login to any of your banks website automatically by clicking the WWW-button.\n* Design changes\n* Eurocard widgetbug fixed\n* Fix for Ikano Bank\n\n\nv1.5.3: (2010-12-21)\n+ Support for Ikano Bank\n+ MedMera Faktura for Coop\n* Multiple accounts for Eurocard\n\n\nv1.5.2: (2010-12-18)\n+ Support for Diners Club\n+ Transactions for Länsförsäkringar\n\n\nv1.5.1: (2010-12-15)\n+ Funds and loans for Länsförsäkringar\n* MedMera Visa for Coop fixed\n* Fix for Handelsbanken\n* Password field show numeric keyboard if appropriate\n\n\nv1.5.0: (2010-12-12)\n+ Support for Jojo Reskassa\n+ Support for Steam Wallet\n+ Support for Avanza (again...)\n+ New setting: Round balance on widgets\n+ Clicking a widget shows transactions for that account.\n* Additional account information for OKQ8 and Statoil\n* Fix for ICA Banken\n* Fix for Coop\n\n\nv1.4.4: (2010-11-26)\n+ Support for Payson\n* Länsförsäkringar fixed\n* Coop login problems fixed/improved\n+ New settings: Blur account balance on widgets\n\n\nv1.4.3: (2010-11-19)\n- Support for Avanza removed\n* PayPal is working again\n* Show all transactions for Statoil\n* Fix for EuroCard\n* Fix for First Card\n* Hidden accounts are not counted towards the total sum\n* Replaced password lock with pattern lock\n+ Support for Remote Notifier plugin\n+ Support for OpenWatch plugin\n+ Custom notification sound\n+ New setting: Don't update transactions on automatic updates\n\n\nv1.4.2: (2010-11-03)\n* Fixed username field for Avanza\n\n\nv1.4.1: (2010-11-03)\n* Fix for Nordea\n\n\nv1.4.0: (2010-11-02)\n+ Support for OKQ8 (thanks to cola)\n+ Support for PayPal\n+ Support for Eurocard with transactions\n+ Support for First Card with transactions\n* Avanza was split into Avanza and AvanzaMini\n+ Nordea credit cards (Visa Gold and others)\n+ Transactions for Coop MedMera Visa\n* Statoil Mastercard fixed\n* Transactions for Handelsbanken fixed\n* A bit faster updates by skipping an unnecessary login when fetching transactions (thanks to DEGE)\n* Notifications show changes for accounts, not banks.\n+ Encryption for passwords\n+ Option to hide accounts\n+ Option to disable notifications for accounts\n+ New setting: Choose which notifications to display (funds, loands, credit cards)\n* Every bank has a pre defined keyboard layout (numeric for Nordea, email for PayPal)\n* Loans are not counted towards the total bank sum\n\n\nv1.3.1: (2010-09-20)\n* Fix for Swedbank\n* Fix for Avanza\n+ Support for Avanza mini\n+ Support for Villabanken\n\n\nv1.3.0: (2010-09-19)\n* Widgets with Handelsbanken accounts are working again\n* Transactions for ICA Banken\n* Coop now also works with \"MedMera-kortet\"\n* Transactions for Coop MedMera\n* Transactions for Handelsbanken\n* Hit box for updating from widgets is larger\n* Support for loans in Swedbank\n* Support for funds and loans in Nordea\n* Widget with transparent background\n+ Support for ICA Kortet with transactions\n+ Support for Statoil MasterCard with transactions\n+ Support for Avanza\n\n\nv1.2.1: (2010-07-13)\n* Added missing ICA Banken logo\n* Fix amount formatting\n\n\nv1.2.0: (2010-07-12)\n* Fixed Nordea bug (login failed when user had an \"e-faktura\" waiting)\n* New design\n* Confirm password field\n+ Link to the banks website\n+ Support for Handelsbanken\n+ Support for Coop\n+ Transaction history for Nordea\n+ Transaction history for Swedbank\n* Improved login error detection\n+ Support for QVGA devices\n\n\nv1.1.4: (2010-06-03)\n* Fix for Nordea\n\n\nv1.1.3: (2010-06-02)\n+ New widget size, 2x1\n* Widgets are updated on boot\n\n\nv1.1.2: (2010-05-31)\n* Working fix for ICA Banken\n\n\nv1.1.1: (2010-05-31)\n* Fix for FC bug with widgets\n* Fix for ICA Banken\n\n\nv1.1.0: (2010-05-31)\n+ Widgets\n+ Automatic updates\n+ Notifications on account changes\n+ Support for Länsförsäkringar\n+ Improved application lock\n\n\nv1.0.3: (2010-05-16)\n+ Option to password protect the application\n\n\nv1.0.2: (2010-05-12)\n* Fix for Swedbank\n\n\nv1.0.1: (2010-05-10)\n+ Support for ICA Banken\n\n\nv1.0.0: (2010-05-05)\n+ First public release\n+ Support for Nordea\n+ Support for Swedbank\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribute to Bankdroid\n\nThis guide details how to use issues and pull requests (for new code) to improve Bankdroid.\n\n## Code Style and Template\n\nWe use the [Android Open-Source Project (AOSP) Code Style Guidelines](http://source.android.com/source/code-style.html).\n\nWe strongly suggest that you use the [`AndroidStyle.xml`](/config/ide/androidstudio/AndroidStyle.xml) template file, included in this repository, in Android Studio to format your code:\n\n1. Place `AndroidStyle.xml` in your Android Studio `/codestyles` directory (e.g., `%userprofile%\\.AndroidStudio\\config\\codestyles`, or `~/Library/Preferences/AndroidStudio/codestyles/` on OS X)\n2. Restart Android Studio.\n3. Go to \"File->Settings->Code Style\", and under \"Scheme\" select \"AndroidStyle\" and click \"Ok\".\n4. Right-click on the files that contain your contributions and select \"Reformat Code\", check \"Optimize imports\", and select \"Run\".\n\n## Closing policy for issues and pull requests\n\nBankdroid is a popular project and the capacity to deal with issues and pull requests is limited. Out of respect for our volunteers, issues and pull requests not in line with the guidelines listed in this document may be closed without notice.\n\nPlease treat our volunteers with courtesy and respect, it will go a long way towards getting your issue resolved.\n\nIssues and pull requests should be in English and contain appropriate language for audiences of all ages.\n\n## Issue tracker\n\nThe [issue tracker](https://github.com/liato/android-bankdroid/issues) is only for obvious bugs, misbehavior, & feature requests in the latest stable or development release of Bankdroid. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a pull request which partially or fully addresses the issue.\n\n### Issue tracker guidelines\n\n**[Search](https://github.com/liato/android-bankdroid/search?q=&ref=cmdform&type=Issues)** for similar entries before submitting your own, there's a good chance somebody else had the same issue or feature request. Show your support with `:+1:` and/or join the discussion. Please submit issues in the following format (as the first post) and feature requests in a similar format:\n\n1. **Summary:** Summarize your issue in one sentence (what goes wrong, what did you expect to happen)\n2. **Steps to reproduce:** How can we reproduce the issue?\n3. **Expected behavior:** What did you expect the app to do?\n4. **Observed behavior:** What did you see instead?  Describe your issue in detail here.\n5. **Device and Android version:** What make and model device (e.g., Samsung Galaxy S3) did you encounter this on?  What Android version (e.g., Android 4.0 Ice Cream Sandwich) are you running?  Is it the stock version from the manufacturer or a custom ROM?\n5. **Screenshots:** Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher.\n6. **Possible fixes**: If you can, link to the line of code that might be responsible for the problem.\n\n## Pull requests\n\nWe welcome pull requests with fixes and improvements to Bankdroid code, tests, and/or documentation. The features we would really like a pull request for are open issues with the [feature](https://github.com/liato/android-bankdroid/issues?labels=feature&page=1&state=open), [broken](https://github.com/liato/android-bankdroid/issues?labels=broken&page=1&state=open) or [improvement](https://github.com/liato/android-bankdroid/issues?labels=improvement&page=1&state=open) labels.\n\n### Pull request guidelines\n\nIf you can, please submit a pull request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a pull request is as follows:\n\n1. Fork the project on GitHub\n2. Create a feature branch\n3. Write tests and code\n4. Apply the `AndroidStyle.xml` style template to your code in Android Studio.\n5. Add your changes to the [CHANGELOG](/CHANGELOG)\n6. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)\n7. Push the commit to your fork\n8. Submit a pull request with a motive for your change and the method you used to achieve it\n9. [Search for issues](https://github.com/liato/android-bankdroid/search?q=&ref=cmdform&type=Issues) related to your pull request and mention them in the pull request description or comments\n\nWe will accept pull requests if:\n\n* The code has proper tests and all tests pass (or it is a test exposing a failure in existing code)\n* It can be merged without problems (if not please use: `git rebase master`)\n* It doesn't break any existing functionality\n* It's quality code that conforms to standard style guides and best practices\n* The description includes a motive for your change and the method you used to achieve it\n* It is not a catch all pull request but rather fixes a specific issue or implements a specific feature\n* It keeps the Bankdroid code base clean and well structured\n* We think other users will benefit from the same functionality\n* If it makes changes to the UI the pull request should include screenshots\n* It is a single commit (please use `git rebase -i` to squash commits)\n\n## License\n\nBy contributing code to this project via pull requests, patches, or any other process, you are agreeing to license your contributions under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).\n"
  },
  {
    "path": "CONTRIBUTORS.txt",
    "content": "--------------------------------------------------------------------------------\nDevelopment\n--------------------------------------------------------------------------------\n  liato                             https://github.com/liato\n  DEGE1                             https://github.com/DEGE1\n  Magnus Hagander                   https://github.com/mhagander\n  Pierre Chateau                    https://github.com/PMC\n  Magnus Andersson                  https://github.com/magnusart\n  cork                              https://github.com/cork\n  Emil Hesslow                      https://github.com/WizKid\n  Peter Björkman                    https://github.com/woody2\n  Joakim Andersson                  https://github.com/firetech\n  Mathias Åhsberg                   https://github.com/goober\n  Lars Wiklund                      https://github.com/lawi75\n  Fredrik Lindberg                  https://github.com/fredriklindberg\n  Erik Fredriksen                   https://github.com/erifre\n  Mats Karlsson                     https://github.com/MatsKarlsson\n  Snah                              https://github.com/Snaah\n  Jonas Björk                       https://github.com/bjooork\n  Anders Waldenborg                 https://github.com/wanders\n  Mattias Fagerström                https://github.com/mafa73\n  Jacob Siverskog                   https://github.com/jsiverskog\n  Andreas Gunnerås                  https://github.com/d95andek\n  Emil Andersson                    https://github.com/emilan\n  oskla129                          https://github.com/oskla129\n  Per Wigren                        https://github.com/Tuxie\n  Joakim Lundborg                   https://github.com/cortex\n  Jonathan Hjertström               https://github.com/nixi\n  Tim Jansson                       https://github.com/timtux\n  Christer Fletcher                 https://github.com/chrfle\n  Richard Ginzburg                  https://github.com/rickythefox\n  ScuttleSE                         https://github.com/ScuttleSE\n  Andreas Knifh                     https://github.com/knifhen\n  NanoRage                          https://github.com/NanoRage\n  Adam Nybäck                       https://github.com/nadam\n  MathiasBois                       https://github.com/MathiasBois\n  Johan Sköld                       https://github.com/rhoot\n  Wictor                            https://github.com/wicol\n  sed03                             https://github.com/sed03\n  Fredrik Erlandsson                https://github.com/fredrike\n  Niclasl                           https://github.com/NiclasI\n  Mikael Eriksson                   https://github.com/mikaeler\n  Mikael Auno                       https://github.com/auno\n  robho                             https://github.com/robho\n  Johan Walles                      https://github.com/walles\n\n\n  Stats at:\n  https://github.com/liato/android-bankdroid/graphs/contributors?type=a\n\n--------------------------------------------------------------------------------\nBeta testing\n--------------------------------------------------------------------------------\n  Swedroid users                    http://goo.gl/9tJeH\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2015 liato\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "README.rst",
    "content": ".. image:: https://travis-ci.org/liato/android-bankdroid.svg?branch=master\n    :target: https://travis-ci.org/liato/android-bankdroid\n\n.. image:: https://bankdroid.herokuapp.com/badge.svg\n    :alt: Join the chat at https://bankdroid.herokuapp.com/\n    :target: https://bankdroid.herokuapp.com/\n\nBankdroid\n=========\n\nBankdroid is an Android app for Swedish banks, payment cards and similar services. Key features include:\n\n* Automatic updates of your balance and transactions\n* Notifications whenever your balance changes\n* Widgets to show your balance anywhere on your home screen\n\nMore information can be found at:\n\n* `Bankdroid on Google Play <https://play.google.com/store/apps/details?id=com.liato.bankdroid>`_\n* `Bankdroid thread at the Swedroid Forum <http://goo.gl/9tJeH>`_ (Swedish)\n\nContribute or report broken banks\n------------------------------------\nThe following information is needed for troubleshooting a broken bank or if you want a new bank to be supported \nby Bankdroid.\n\n1. Address to login page.\n2. Address and html code for the landing page after a successful login.\n3. Address and html code for the page with the accounts overview.\n4. Address and html code for the page with an account's transaction history.\n\nNOTE. Do not forget to replace your personal information in the html code with random \ninformation before you send everything to android [at] nullbyte.eu. \nYou can also open an issue here at Github with the required files included as an attachment.\n\nDevelopment environment\n-----------------------\n\nBankdroid is written for Android Studio 0.8.2 and Gradle 1.12. Here's how to get the code up and\nrunning on your computer:\n\n1. Make sure you have `Android Studio 0.8.2 or later <https://developer.android.com/sdk/installing/studio.html>`_\n2. `Clone <https://help.github.com/articles/which-remote-url-should-i-use>`_ the project (if you want to contribute you should `fork <https://help.github.com/articles/fork-a-repo>`_ the project first and then clone your fork)\n3. Open the project's settings.gradle file in Android Studio and select \"Use default gradle wrapper (recommended)\"\n4. Select \"Make project\" from the Build menu\n5. Select Run from the Run menu\n\nLicense\n-------\n\nThe Bankdroid source code is licensed under the\n`Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "buildscript {\n    repositories {\n        maven { url 'https://maven.fabric.io/public' }\n        maven {\n            url \"https://plugins.gradle.org/m2/\"\n        }\n    }\n\n    dependencies {\n        classpath \"org.ajoberstar:gradle-git:1.5.1\"\n\n        // The dynamic version here is explicitly recommended by the Crashlytics docs:\n        // https://docs.fabric.io/android/fabric/integration.html#modify-build-gradle\n        //noinspection GradleDynamicVersion\n        classpath 'io.fabric.tools:gradle:1.+'\n    }\n}\napply plugin: 'com.android.application'\napply from: '../config/quality/quality.gradle'\napply plugin: \"org.ajoberstar.grgit\"\n\nif (new File('app/crashlytics.properties').exists()) {\n    apply plugin: 'io.fabric'\n}\n\nrepositories {\n    maven { url 'https://maven.fabric.io/public' }\n}\n\ndef keystorePropertiesFile = project.file(\"keystore.properties\")\ndef keystoreProperties = new Properties()\nkeystoreProperties.load(new FileInputStream(keystorePropertiesFile))\n\next {\n    git = org.ajoberstar.grgit.Grgit.open()\n    gitVersionCode = git.tag.list().size()\n    gitVersionName = \"${git.describe()}\"\n}\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.1\"\n\n    useLibrary 'org.apache.http.legacy'\n    defaultConfig {\n        applicationId \"com.liato.bankdroid\"\n        minSdkVersion 9\n        targetSdkVersion 25\n        versionCode 224 + gitVersionCode\n        versionName gitVersionName\n    }\n\n    signingConfigs {\n        release {\n            storeFile file(keystoreProperties['storeFile'])\n            storePassword keystoreProperties['storePassword']\n            keyAlias keystoreProperties['keyAlias']\n            keyPassword keystoreProperties['keyPassword']\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_7\n        targetCompatibility JavaVersion.VERSION_1_7\n    }\n\n    packagingOptions {\n        exclude 'META-INF/LICENSE.txt'\n        exclude 'META-INF/NOTICE.txt'\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            signingConfig signingConfigs.release\n        }\n        debug {\n            ext.enableCrashlytics = false\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(':bankdroid-legacy')\n    compile project(':bankdroid-core')\n    compile 'com.jakewharton:butterknife:6.1.0'\n    compile 'com.jakewharton.timber:timber:4.3.1'\n    compile \"com.android.support:appcompat-v7:25.2.0\"\n    compile 'com.google.collections:google-collections:1.0'\n    compile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') {\n        transitive = true;\n    }\n\n    testCompile 'junit:junit:4.12'\n    testCompile 'org.mockito:mockito-core:1.10.19'\n}\n"
  },
  {
    "path": "app/crashlytics.properties.example",
    "content": "apiSecret=YOUR_BUILD_SECRET\napiKey=YOUR_API_KEY\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /home/liato/bin/android-studio/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n-keep class com.crashlytics.** { *; }\n-dontwarn com.crashlytics.**\n\n# Allow obfuscation of android.support.v7.internal.view.menu.**\n# to avoid problem on Samsung 4.2.2 devices with appcompat v21\n# see https://code.google.com/p/android/issues/detail?id=78377\n-keep class !android.support.v7.internal.view.menu.**,android.support.** {*;}\n\n#Butterknife\n-keep class butterknife.** { *; }\n-dontwarn butterknife.internal.**\n-keep class **$$ViewInjector { *; }\n\n-keepclasseswithmembernames class * {\n    @butterknife.* <fields>;\n}\n\n-keepclasseswithmembernames class * {\n    @butterknife.* <methods>;\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tpackage=\"com.liato.bankdroid\">\n\t<application\n        android:name=\"com.liato.bankdroid.BankdroidApplication\"\n\t\tandroid:icon=\"@drawable/ic_launcher\"\n\t\tandroid:label=\"@string/app_name\"\n\t    android:hardwareAccelerated=\"true\"\n        android:allowBackup=\"true\">\n\t\t<activity\n\t\t\tandroid:name=\".MainActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:multiprocess=\"false\"\n\t\t\tandroid:alwaysRetainTaskState=\"false\"\n\t\t\tandroid:configChanges=\"keyboardHidden|orientation|screenSize\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.intent.action.MAIN\" />\n\t\t\t\t<category\n\t\t\t\t\tandroid:name=\"android.intent.category.LAUNCHER\" />\n\t\t\t</intent-filter>\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:name=\".TransactionsActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:name=\".WebViewActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\"\n\t\t\tandroid:configChanges=\"keyboardHidden|orientation|screenSize\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:name=\".BankEditActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:configChanges=\"keyboardHidden|orientation|screenSize\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:name=\".SettingsActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:name=\".AboutActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\"\n\t\t\tandroid:name=\".lockpattern.ChooseLockPattern\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\"\n\t\t\tandroid:name=\".lockpattern.ChooseLockPatternExample\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\"\n\t\t\tandroid:name=\".lockpattern.ChooseLockPatternTutorial\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:theme=\"@style/BankdroidTheme\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:name=\".lockpattern.ConfirmLockPattern\">\n\t\t</activity>\n\t\t<activity\n\t\t\tandroid:theme=\"@style/Theme.AppCompat.Dialog\"\n\t\t\tandroid:name=\".appwidget.WidgetConfigureActivity\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.appwidget.action.APPWIDGET_CONFIGURE\" />\n\t\t\t</intent-filter>\n\t\t</activity>\n\t\t<receiver\n\t\t\tandroid:label=\"@string/widget_name_small\"\n\t\t\tandroid:name=\".appwidget.BankdroidWidgetProvider_2x1\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"com.liato.bankdroid.WIDGET_REFRESH\" />\n\t\t\t</intent-filter>\n\t\t\t<meta-data\n\t\t\t\tandroid:name=\"android.appwidget.provider\"\n\t\t\t\tandroid:resource=\"@xml/appwidget_info\" />\n\t\t</receiver>\n\n\t\t<receiver\n\t\t\tandroid:label=\"@string/widget_name_large\"\n\t\t\tandroid:name=\".appwidget.BankdroidWidgetProvider_4x1\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"com.liato.bankdroid.WIDGET_REFRESH\" />\n\t\t\t</intent-filter>\n\t\t\t<meta-data\n\t\t\t\tandroid:name=\"android.appwidget.provider\"\n\t\t\t\tandroid:resource=\"@xml/appwidget_info_large\" />\n\t\t</receiver>\n\n\t\t<service\n\t\t\tandroid:enabled=\"true\"\n\t\t\tandroid:name=\".appwidget.AutoRefreshService\" />\n\t\t<service\n\t\t\tandroid:enabled=\"true\"\n\t\t\tandroid:name=\".appwidget.BankdroidWidgetProvider$WidgetService\" />\n\t\t<receiver\n\t\t\tandroid:name=\"StartupReceiver\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.intent.action.BOOT_COMPLETED\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.intent.action.PACKAGE_ADDED\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.intent.action.PACKAGE_CHANGED\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.intent.action.PACKAGE_REPLACED\" />\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"android.net.conn.CONNECTIVITY_CHANGE\" />\n\t\t\t\t<!-- <data\n\t\t\t\t\tandroid:scheme=\"package\"\n\t\t\t\t\tandroid:path=\"com.liato.bankdroid\" /> -->\n\t\t\t</intent-filter>\n\t\t</receiver>\n\t\t<service\n\t\t\tandroid:name=\".liveview.LiveViewService\"\n\t\t\tandroid:label=\"LiveView plugin service\">\n\t\t</service>\n\t\t<receiver\n\t\t\tandroid:name=\".liveview.PluginReceiver\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"com.sonyericsson.extras.liveview.LAUNCH_PLUGIN\" />\n\t\t\t</intent-filter>\n\t\t</receiver>\n\n\t\t<provider\n\t\t\tandroid:name=\".provider.BankTransactionsProvider\"\n\t\t\tandroid:syncable=\"false\"\n\t\t\tandroid:multiprocess=\"true\"\n\t\t\tandroid:exported=\"true\"\n\t\t\tandroid:authorities=\"com.liato.bankdroid.provider.BankTransactionsProvider\"\n\t\t\tandroid:permission=\"com.liato.bankdroid.permission.READ_ACCESS_BANK_TRANSACTIONS\" />\n\t\t<activity\n\t\t\tandroid:name=\"PairApplicationsActivity\"\n\t\t\tandroid:label=\"@string/app_name\"\n\t\t\tandroid:multiprocess=\"false\"\n\t\t\tandroid:alwaysRetainTaskState=\"false\"\n\t\t\tandroid:theme=\"@style/BankdroidTheme\">\n\t\t\t<intent-filter>\n\t\t\t\t<action\n\t\t\t\t\tandroid:name=\"com.liato.bankroid.PAIR_APPLICATION_ACTION\" />\n\t\t\t\t<category\n\t\t\t\t\tandroid:name=\"android.intent.category.DEFAULT\" />\n\t\t\t</intent-filter>\n\t\t</activity>\n\t</application>\n\t<uses-permission\n\t\tandroid:name=\"android.permission.INTERNET\" />\n\t<uses-permission\n\t\tandroid:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n\t<uses-permission\n\t\tandroid:name=\"android.permission.VIBRATE\" />\n\t<uses-permission\n\t\tandroid:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n\t<uses-permission\n\t\tandroid:name=\"com.sonyericsson.extras.liveview.permission.LIVEVIEW_API\" />\n\t<supports-screens\n\t\tandroid:largeScreens=\"true\"\n\t\tandroid:normalScreens=\"true\"\n\t\tandroid:smallScreens=\"true\"\n\t\tandroid:anyDensity=\"true\" />\n\t<permission\n\t\tandroid:name=\"com.liato.bankdroid.permission.READ_ACCESS_BANK_TRANSACTIONS\"\n\t\tandroid:label=\"@string/permission_provider_label\"\n\t\tandroid:description=\"@string/permission_provider_desc\"\n\t\tandroid:protectionLevel=\"dangerous\" />\n</manifest> "
  },
  {
    "path": "app/src/main/aidl/com/sonyericsson/extras/liveview/IPluginServiceCallbackV1.aidl",
    "content": "/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * \n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.sonyericsson.extras.liveview;\n\ninterface IPluginServiceCallbackV1 {\n\t// Start the plugin.\n\tvoid startPlugin();\n\t\n\t// Stop the plugin.\n\t// A stopped plugin should stop its polling, but can stay alive\n\tvoid stopPlugin();\n\t\n\t// Should return the name the plugin used to register itself with\n\tString getPluginName();\n\n \t// Give the action needed to open the current announcement on the phone\n\t// such as a view in browser action or something else that your application\n\t// responds to.\n\tvoid openInPhone(in String openInPhoneAction);      \n\n\t// Kicked out by framework. Implement this with stopSelf()\n\tvoid onUnregistered();\n\t\n\t// displayWidthPixels equals 0 and displayheigthPixels equals 0\n\t// means no available device is attached, or has no display\n\tvoid displayCaps(in int displayWidthPixels, in int displayHeigthPixels);\n\t\n\t// Button event - note that doublepress is not implemented for the V1\n\t// interface but still left here for compatibility reasons.\n\tvoid button(in String buttonType, in boolean doublepress, in boolean longpress);\n\n\t// Screen mode changed event - this notifies the current active sandbox plugin that the screen has been \n\t// turned on or off. 0 = Screen OFF, 1 = Screen ON\n\tvoid screenMode(in int screenMode);\n}"
  },
  {
    "path": "app/src/main/aidl/com/sonyericsson/extras/liveview/IPluginServiceV1.aidl",
    "content": "/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * \n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.sonyericsson.extras.liveview;\n\nimport com.sonyericsson.extras.liveview.IPluginServiceCallbackV1;\n\ninterface IPluginServiceV1 {\n\n\t// Register to the Liveview application\n\t// cb - callback instance\n    // imageMenu - path to the menu bitmap\n    // pluginName - name of the plugin - must be unique\n    // selectableMenu - is set to true if controlling display and getting buttons. Set to false to only handle announces\n    // packageName - the package name (use getPackageName()).\n    // returns id of plugin in system, 0 means that the registration failed\n    int register(in IPluginServiceCallbackV1 cb, in String imageMenu, in String pluginName, in boolean selectableMenu, in String packageName);\n    \n    // This method should be called if the application/service is uninstalled using the phone application handler \n    // id - the plugin id received in registerPlugin\n    // cb - the callback\n    void unregister( in int id, in IPluginServiceCallbackV1 cb);\n    \n    // Used to send announcements to the device - can only be used when _not_ registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // imageAnnounce - the path to the announce bitmap\n    // header - header text\n    // body - body text\n    // time - timestamp for this announce in milliseconds\n    // openInPhoneAction - a tag to use for openInPhone callback. Set to null when announce not selectable\n    void sendAnnounce(in int id, in String imageAnnounce, in String header, in String body, in long timestamp, in String openInPhoneAction);\n    \n    // Used to send image data to the device while in sandbox mode - Can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // x - from left side\n    // y - from top side\n    // image - the path to the image on file system\n    void sendImage(in int id, in int x, in int y, in String image);\n\n    // Used to send image data to the device while in sandbox mode - Can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // x - from left side\n    // y - from top side\n    // bitmapData - the bitmap to send\n    void sendImageAsBitmap(in int id, in int x, in int y, in Bitmap bitmapData);\n    \n    // Clears the display, for example if several images are sent while in sandbox mode - Can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    void clearDisplay(in int id);\n    \n    // Provide the Liveview application with means to launch the service \n    // that shoul receive and send data in sandbox mode - Must be called if you registered as \"selectableMenu\"\n    // launcherIntent - the intent to start the plugin service\n    // pluginName - the name of the plugin, must match the name you registered with! \n    // returns -1 for failure, 0 for already registered, anything else for success\n    int notifyInstalled(in String launcherIntent, in String pluginName);\n\n    // Controls LED - can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // rgb565 - the color to use\n    // delayTime - the delay in ms\n    // onTime - the on time in ms\n    void ledControl(in int id, int rgb565, int delayTime, int onTime);\n\n    // Controls Vibration - can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // delayTime - the delay in ms\n    // onTime - the on time in ms\n    void vibrateControl(in int id, int delayTime, int onTime);\n\n    // Used to send image data to the device while in sandbox mode - Can only be used if you registered as \"selectableMenu\"\n    // id - the plugin id received in registerPlugin\n    // x - from left side\n    // y - from top side\n    // bitmapBytes - the byteArray containing the bitmap data\n    void sendImageAsBitmapByteArray(in int id, in int x, in int y, in byte[] bitmapByteArray);\n\n    // Used to put the screen in powersave mode\n    // id - the plugin id received in registerPlugin\n    void screenOff(in int id);\n\n    // Used to put the screen in dimmed mode\n    // id - the plugin id received in registerPlugin\n    void screenDim(in int id);\n\n    // Used to wake the screen from powersave mode\n    // id - the plugin id received in registerPlugin\n    void screenOn(in int id);\n\n    // Used to set the to powersave mode \"AUTO\"\n    // id - the plugin id received in registerPlugin\n    void screenOnAuto(in int id);\n}"
  },
  {
    "path": "app/src/main/java/com/ast/util/CookieParser.java",
    "content": "/*\n * Copyright (C) 2009 hessdroid@gmail.com\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.ast.util;\n\n/**\n * Parses Set-Cookie HTTP response header and returns the corresponding {@link Cookie} which can be\n * used for storing cookie information in java collections.\n * <p/>\n * <a href=\"http://www.ietf.org/rfc/rfc2109\">RFC 2109</a>\n *\n * @author hessdroid@gmail.com\n */\npublic class CookieParser {\n\n    /**\n     * Parses the given <tt>setCookieString</tt> from an HTTP response and creates a {@link Cookie}\n     * from it.\n     * The {@link Cookie} can be used by clients to send cookie on subsequent requests.\n     *\n     * @param host            <code>String</code> cookie host\n     * @param setCookieString <code>String</code> complete cookie string\n     * @return a {@link Cookie} that was created from the given <tt>setCookieString</tt>\n     */\n    public static Cookie parse(String host, String setCookieString) {\n\n        if (host == null) {\n            throw new IllegalArgumentException(\"Parameter \\\"host\\\" must not be null\");\n        }\n        if (setCookieString == null) {\n            throw new IllegalArgumentException(\"Parameter \\\"setCookieString\\\" must not be null\");\n        }\n\n        Cookie result = new Cookie();\n\n        // split the cookie string on any semicolon or space(s)\n        String[] fields = setCookieString.split(\";\\\\s*\");\n        result.host = host;\n\n        // ignore leading cookie intro\n        result.value = fields[0].startsWith(\"Set-Cookie: \") ? fields[0].substring(12) : fields[0];\n        if (result.value.startsWith(\"JSESSIONID=\")) {\n            result.sessionId = result.value.substring(11);\n        }\n\n        // Parse each field\n        for (int j = 1; j < fields.length; j++) {\n            if (\"secure\".equalsIgnoreCase(fields[j])) {\n                result.secure = true;\n            } else if (fields[j].indexOf('=') > 0) {\n                String[] f = fields[j].split(\"=\");\n                if (\"expires\".equalsIgnoreCase(f[0])) {\n                    result.expires = f[1];\n                } else if (\"domain\".equalsIgnoreCase(f[0])) {\n                    result.domain = f[1];\n                } else if (\"path\".equalsIgnoreCase(f[0])) {\n                    result.path = f[1];\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Abstract representation of an HTTP cookie.\n     */\n    public static class Cookie {\n\n        public String host;\n\n        public String value; // cookie string without the leading intro: \"Set-Cookie: \"\n\n        public String expires;\n\n        public String path;\n\n        public String domain;\n\n        public String sessionId;\n\n        public boolean secure;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/AboutActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.widget.TextView;\n\nimport butterknife.ButterKnife;\nimport butterknife.InjectView;\n\npublic class AboutActivity extends LockableActivity {\n\n    @InjectView(R.id.txtVersion)\n    TextView mVersion;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.about);\n        ButterKnife.inject(this);\n        PackageInfo pInfo;\n        String version = BuildConfig.VERSION_NAME;\n        mVersion.setText(\n                getText(R.string.version).toString().replace(\"$version\", version));\n\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(final Menu menu) {\n        super.onCreateOptionsMenu(menu);\n        final MenuInflater inflater = new MenuInflater(this);\n        inflater.inflate(R.menu.about, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.action_web:\n                Intent i = new Intent(Intent.ACTION_VIEW);\n                i.setData(Uri.parse(\"https://github.com/liato/android-bankdroid\"));\n                startActivity(i);\n                return true;\n        }\n\n        return super.onOptionsItemSelected(item);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/ActivityHelper.java",
    "content": "package com.liato.bankdroid;\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.ContextWrapper;\n\npublic class ActivityHelper {\n\n    public static void dismissDialog(Dialog dialog) {\n        if (dialog.isShowing()) { //check if dialog is showing.\n\n            //get the Context object that was used to great the dialog\n            Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();\n\n            //if the Context used here was an activity AND it hasn't been finished\n            //then dismiss it\n            if (context instanceof Activity) {\n                if (!((Activity) context).isFinishing()) {\n                    dialog.dismiss();\n                }\n            } else { //if the Context used wasnt an Activity, then dismiss it too\n                dialog.dismiss();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/BankEditActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.google.common.collect.Iterators;\n\nimport com.crashlytics.android.Crashlytics;\nimport com.liato.bankdroid.api.configuration.Entry;\nimport com.liato.bankdroid.api.configuration.Field;\nimport com.liato.bankdroid.appwidget.AutoRefreshService;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankChoice;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.configuration.DefaultConnectionConfiguration;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.utils.FieldTypeMapper;\nimport com.liato.bankdroid.utils.NetworkUtils;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.SharedPreferences;\nimport android.content.res.Resources;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.text.method.PasswordTransformationMethod;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport butterknife.ButterKnife;\nimport butterknife.InjectView;\nimport butterknife.OnClick;\nimport timber.log.Timber;\n\npublic class BankEditActivity extends LockableActivity implements OnItemSelectedListener {\n\n    @InjectView(R.id.spnBankeditBanklist)\n    Spinner mBankSpinner;\n\n    @InjectView(R.id.layoutBankConfiguration)\n    LinearLayout mFormContainer;\n\n    @InjectView(R.id.txtErrorDesc)\n    TextView mErrorDescription;\n\n    private Bank selectedBank;\n\n    private long bankId = -1;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.bank);\n        ButterKnife.inject(this);\n        this.getWindow()\n                .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);\n\n        List<Bank> items = BankFactory.listBanks(this);\n        Collections.sort(items);\n        BankSpinnerAdapter<Bank> adapter = new BankSpinnerAdapter<>(this, items);\n        mBankSpinner.setAdapter(adapter);\n\n\n        Bundle extras = getIntent().getExtras();\n        if (extras != null) {\n            bankId = extras.getLong(\"id\", -1);\n            if (bankId != -1) {\n                Bank bank = BankFactory.bankFromDb(bankId, this, false);\n                if (bank != null) {\n                    mErrorDescription.setVisibility(\n                            bank.isDisabled() ? View.VISIBLE : View.INVISIBLE);\n                    mBankSpinner.setEnabled(false);\n                    mBankSpinner.setSelection(adapter.getPosition(bank));\n                    selectedBank = bank;\n                    createForm(selectedBank.getConnectionConfiguration(),\n                            DefaultConnectionConfiguration.fields()\n                    );\n                    populateForm(bank);\n                }\n            }\n        }\n        mBankSpinner.setOnItemSelectedListener(this);\n    }\n\n    @OnClick(R.id.btnSettingsOk)\n    public void onSubmit(View v) {\n        if (!validate()) {\n            return;\n        }\n        selectedBank.setProperties(getFormParameters(selectedBank.getConnectionConfiguration()));\n        selectedBank.setCustomName(getFormParameter(DefaultConnectionConfiguration.NAME));\n        selectedBank.setDbid(bankId);\n        new DataRetrieverTask(this, selectedBank).execute();\n    }\n\n    @OnClick(R.id.btnSettingsCancel)\n    public void onCancel(View v) {\n        this.finish();\n    }\n\n    @Override\n    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int pos, long id) {\n        Bank selectedBank = (Bank) parentView.getItemAtPosition(pos);\n        if (this.selectedBank == null || !this.selectedBank.equals(selectedBank)) {\n            this.selectedBank = selectedBank;\n                    mFormContainer.removeAllViewsInLayout();\n            createForm(this.selectedBank.getConnectionConfiguration(),\n                    DefaultConnectionConfiguration.fields()\n            );\n        }\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> arg) {\n    }\n\n\n    private void createForm(List<Field>... configurations) {\n        for (List<Field> fields : configurations) {\n            for (Field field : fields) {\n                createLabel(field);\n                if (field.getValues().isEmpty()) {\n                    createField(field);\n                } else {\n                    createSpinner(field);\n                }\n            }\n        }\n    }\n\n    private void createLabel(Field field) {\n        TextView fieldText = new TextView(this);\n        String label = field.getLabel() + (field.isRequired() ? \"\" : \" \" + getString(R.string.optional_field));\n        fieldText.setText(label);\n        fieldText.setVisibility(field.isHidden() ? View.GONE : View.VISIBLE);\n        mFormContainer.addView(fieldText);\n    }\n\n    private void createField(Field field) {\n        EditText inputField = new EditText(this);\n        inputField.setHint(field.getPlaceholder());\n        if (field.isSecret()) {\n            inputField.setTransformationMethod(\n                    PasswordTransformationMethod.getInstance());\n        } else {\n            inputField\n                    .setInputType(FieldTypeMapper.fromFieldType(field.getFieldType()));\n        }\n        inputField.setVisibility(field.isHidden() ? View.GONE : View.VISIBLE);\n        inputField.setTag(field.getReference());\n\n        mFormContainer.addView(inputField);\n    }\n\n    private void createSpinner(Field field) {\n        Spinner spinner = new Spinner(this);\n        spinner.setAdapter(new ArrayAdapter<Entry>(this, android.R.layout.simple_spinner_item,\n                field.getValues()));\n        spinner.setTag(field.getReference());\n        mFormContainer.addView(spinner);\n    }\n\n    private void populateForm(Bank bank) {\n        EditText customName = (EditText) mFormContainer.findViewWithTag(\n                DefaultConnectionConfiguration.NAME);\n        customName.setText(bank.getCustomName());\n\n        for (Map.Entry<String, String> property : bank.getProperties().entrySet()) {\n            EditText propertyInput = (EditText) mFormContainer.findViewWithTag(property.getKey());\n            propertyInput.setText(property.getValue());\n        }\n    }\n\n    private Map<String, String> getFormParameters(List<Field> fields) {\n        Map<String, String> properties = new HashMap<>();\n        for (Field field : fields) {\n            properties.put(field.getReference(), getFormParameter(field.getReference()));\n        }\n        return properties;\n    }\n\n    private String getFormParameter(String property) {\n        View propertyView = mFormContainer.findViewWithTag(property);\n        if (propertyView instanceof EditText) {\n            EditText propertyInput = (EditText) propertyView;\n            return propertyInput.getText().toString().trim();\n        } else if (propertyView instanceof Spinner) {\n            Spinner spinnerProperty = (Spinner) propertyView;\n            Entry entry = (Entry) spinnerProperty.getSelectedItem();\n            return entry.getKey();\n        } else {\n            return null;\n        }\n    }\n\n    private boolean validate() {\n        boolean valid = true;\n        Iterator<Field> fields = Iterators.concat(selectedBank.getConnectionConfiguration().iterator(),\n                DefaultConnectionConfiguration.fields().iterator());\n        while (fields.hasNext()) {\n            Field field = fields.next();\n            try {\n                field.validate(getFormParameter(field.getReference()));\n            } catch (IllegalArgumentException e) {\n                valid = false;\n                ((EditText) mFormContainer.findViewWithTag(field.getReference())).setError(e.getMessage());\n            }\n        }\n        return valid;\n    }\n\n    private class BankSpinnerAdapter<T> extends ArrayAdapter<T> {\n\n        private LayoutInflater inflater;\n\n        public BankSpinnerAdapter(Context context, List<T> items) {\n            super(context, R.layout.bank_spinner_item, R.id.txtBank, items);\n            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            if (convertView == null) {\n                convertView = inflater.inflate(R.layout.bank_spinner_item, parent, false);\n            }\n            ((TextView) convertView.findViewById(R.id.txtBank))\n                    .setText(((Bank) getItem(position)).getName());\n            ((ImageView) convertView.findViewById(R.id.imgBank))\n                    .setImageResource(((Bank) getItem(position)).getImageResource());\n            return convertView;\n        }\n\n        @Override\n        public View getDropDownView(int position, View convertView,\n                ViewGroup parent) {\n            if (convertView == null) {\n                convertView = inflater.inflate(R.layout.bank_spinner_dropdown_item, parent, false);\n            }\n            ((TextView) convertView.findViewById(R.id.txtBank))\n                    .setText(((Bank) getItem(position)).getName());\n            ((ImageView) convertView.findViewById(R.id.imgBank))\n                    .setImageResource(((Bank) getItem(position)).getImageResource());\n            return convertView;\n        }\n\n\n    }\n\n    private class DataRetrieverTask extends AsyncTask<String, Void, Void> {\n\n        private final ProgressDialog dialog = new ProgressDialog(BankEditActivity.this);\n\n        private Exception exc = null;\n\n        private Bank bank;\n\n        private BankEditActivity context;\n\n        private Resources res;\n\n        public DataRetrieverTask(BankEditActivity context, Bank bank) {\n            this.context = context;\n            this.res = context.getResources();\n            this.bank = bank;\n        }\n\n        protected void onPreExecute() {\n            this.dialog.setMessage(res.getText(R.string.logging_in));\n            this.dialog.show();\n        }\n\n        protected Void doInBackground(final String... args) {\n            try {\n                bank.update();\n                bank.updateAllTransactions();\n                bank.closeConnection();\n                DBAdapter.save(bank, context);\n\n                // Transactions updated.\n                final SharedPreferences prefs = PreferenceManager\n                        .getDefaultSharedPreferences(getBaseContext());\n                if (prefs.getBoolean(\"content_provider_enabled\", false)) {\n                    final ArrayList<Account> accounts = bank.getAccounts();\n                    for (final Account account : accounts) {\n                        AutoRefreshService.broadcastTransactionUpdate(\n                                getBaseContext(), bank.getDbId(),\n                                account.getId());\n                    }\n                }\n            } catch (BankException e) {\n                this.exc = e;\n                Crashlytics.logException(e);\n            } catch (LoginException e) {\n                this.exc = e;\n            } catch (BankChoiceException e) {\n                this.exc = e;\n            } catch (IOException e) {\n                this.exc = e;\n                if (NetworkUtils.isInternetAvailable()) {\n                    Crashlytics.logException(e);\n                }\n            }\n            return null;\n        }\n\n        protected void onPostExecute(final Void unused) {\n            AutoRefreshService.sendWidgetRefresh(context);\n            ActivityHelper.dismissDialog(this.dialog);\n            if (this.exc != null) {\n                AlertDialog.Builder builder = new AlertDialog.Builder(context);\n                if (this.exc instanceof BankChoiceException) {\n                    final BankChoiceException e = (BankChoiceException) exc;\n                    final String[] items = new String[e.getBanks().size()];\n                    int i = 0;\n                    for (BankChoice b : e.getBanks()) {\n                        items[i] = b.getName();\n                        i++;\n                    }\n                    builder.setTitle(R.string.select_a_bank);\n                    builder.setItems(items, new DialogInterface.OnClickListener() {\n                        public void onClick(DialogInterface dialog, int item) {\n                            selectedBank.setExtras(e.getBanks().get(item).getId());\n                            new DataRetrieverTask(context, selectedBank).execute();\n                        }\n                    });\n                } else {\n                    Timber.w(exc, \"Failed getting info from bank\");\n                    builder.setMessage(this.exc.getMessage())\n                            .setTitle(res.getText(R.string.could_not_create_account))\n                            .setIcon(android.R.drawable.ic_dialog_alert)\n                            .setNeutralButton(\"Ok\", new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int id) {\n                                    dialog.cancel();\n                                }\n                            });\n                }\n                AlertDialog alert = builder.create();\n                if (!context.isFinishing()) {\n                    alert.show();\n                }\n            } else {\n                context.finish();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/BankdroidApplication.java",
    "content": "package com.liato.bankdroid;\n\nimport com.liato.bankdroid.utils.LoggingUtils;\n\nimport android.app.Application;\nimport android.widget.Toast;\n\npublic class BankdroidApplication extends Application {\n\n    private String message = \"\";\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        LoggingUtils.createLogger(this);\n    }\n\n    public void setApplicationMessage(String messageText) {\n        message = messageText == null ? \"\" : messageText;\n    }\n\n    public void showAndDeleteApplicationMessage() {\n        if (!message.isEmpty()) {\n            Toast toast = Toast.makeText(this, message, Toast.LENGTH_LONG);\n            message = \"\";\n            toast.show();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/BetterPopupWindow.java",
    "content": "package com.liato.bankdroid;\n\nimport android.content.Context;\nimport android.graphics.Rect;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.View.OnTouchListener;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.WindowManager;\nimport android.widget.PopupWindow;\n\n/**\n * This class does most of the work of wrapping the {@link PopupWindow} so it's simpler to use.\n *\n * @author qberticus\n */\npublic class BetterPopupWindow {\n\n    protected final ViewGroup parentView;\n    protected final View anchor;\n\n    private final PopupWindow window;\n\n    private final WindowManager windowManager;\n\n    private View root;\n\n    private Drawable background = null;\n\n    /**\n     * Create a BetterPopupWindow\n     *\n     * @param anchor the view that the BetterPopupWindow will be displaying 'from'\n     */\n    public BetterPopupWindow(ViewGroup parentView, View anchor) {\n        this.anchor = anchor;\n        this.parentView = parentView;\n        this.window = new PopupWindow(anchor.getContext());\n\n        // when a touch even happens outside of the window\n        // make the window go away\n        this.window.setTouchInterceptor(new OnTouchListener() {\n            @Override\n            public boolean onTouch(View v, MotionEvent event) {\n                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {\n                    BetterPopupWindow.this.window.dismiss();\n                    return true;\n                }\n                return false;\n            }\n        });\n\n        this.windowManager = (WindowManager) this.anchor.getContext()\n                .getSystemService(Context.WINDOW_SERVICE);\n        onCreate();\n    }\n\n    /**\n     * Anything you want to have happen when created. Probably should create a view and setup the\n     * event listeners on\n     * child views.\n     */\n    protected void onCreate() {\n    }\n\n    /**\n     * In case there is stuff to do right before displaying.\n     */\n    protected void onShow() {\n    }\n\n    private void preShow() {\n        if (this.root == null) {\n            throw new IllegalStateException(\n                    \"setContentView was not called with a view to display.\");\n        }\n        onShow();\n\n        if (this.background == null) {\n            this.window.setBackgroundDrawable(new BitmapDrawable());\n        } else {\n            this.window.setBackgroundDrawable(this.background);\n        }\n\n        // if using PopupWindow#setBackgroundDrawable this is the only values of the width and hight that make it work\n        // otherwise you need to set the background of the root viewgroup\n        // and set the popupwindow background to an empty BitmapDrawable\n        this.window.setWidth(WindowManager.LayoutParams.FILL_PARENT);\n        this.window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);\n        this.window.setTouchable(true);\n        this.window.setFocusable(true);\n        this.window.setOutsideTouchable(true);\n\n        this.window.setContentView(this.root);\n    }\n\n    public void setBackgroundDrawable(Drawable background) {\n        this.background = background;\n    }\n\n    /**\n     * Sets the content view. Probably should be called from {@link onCreate}\n     *\n     * @param root the view the popup will display\n     */\n    public void setContentView(View root) {\n        this.root = root;\n        this.window.setContentView(root);\n    }\n\n    /**\n     * Will inflate and set the view from a resource id\n     */\n    public void setContentView(int layoutResID) {\n        LayoutInflater inflator =\n                (LayoutInflater) this.anchor.getContext()\n                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n        this.setContentView(inflator.inflate(layoutResID, null));\n    }\n\n    /**\n     * If you want to do anything when {@link dismiss} is called\n     */\n    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {\n        this.window.setOnDismissListener(listener);\n    }\n\n    /**\n     * Displays like a popdown menu from the anchor view\n     */\n    public void showLikePopDownMenu() {\n        this.showLikePopDownMenu(0, 0);\n    }\n\n    /**\n     * Displays like a popdown menu from the anchor view.\n     *\n     * @param xOffset offset in X direction\n     * @param yOffset offset in Y direction\n     */\n    public void showLikePopDownMenu(int xOffset, int yOffset) {\n        this.preShow();\n\n        this.window.setAnimationStyle(R.style.Animations_PopDownMenu);\n\n        this.window.showAsDropDown(this.anchor, xOffset, yOffset);\n    }\n\n    /**\n     * Displays like a QuickAction from the anchor view.\n     */\n    public void showLikeQuickAction() {\n        this.showLikeQuickAction(0, 0);\n    }\n\n    /**\n     * Displays like a QuickAction from the anchor view.\n     *\n     * @param xOffset offset in the X direction\n     * @param yOffset offset in the Y direction\n     */\n    public void showLikeQuickAction(int xOffset, int yOffset) {\n        this.preShow();\n\n        this.window.setAnimationStyle(R.style.Animations_GrowFromBottom);\n\n        int[] location = new int[2];\n        this.anchor.getLocationOnScreen(location);\n\n        Rect anchorRect =\n                new Rect(location[0], location[1], location[0] + this.anchor.getWidth(), location[1]\n                        + this.anchor.getHeight());\n\n        this.root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n\n        int rootWidth = this.root.getMeasuredWidth();\n        int rootHeight = this.root.getMeasuredHeight();\n\n        int screenWidth = this.windowManager.getDefaultDisplay().getWidth();\n        int screenHeight = this.windowManager.getDefaultDisplay().getHeight();\n\n        int xPos = ((screenWidth - rootWidth) / 2) + xOffset;\n        int yPos = anchorRect.top - rootHeight + yOffset;\n\n        // display on bottom\n        if (rootHeight > anchorRect.top) {\n            yPos = anchorRect.bottom - yOffset;\n            this.window.setAnimationStyle(R.style.Animations_GrowFromTop);\n            this.root.findViewById(R.id.layPopupCont).setBackgroundResource(R.drawable.popup_bg_up);\n        }\n\n        this.window.showAtLocation(this.anchor, Gravity.NO_GRAVITY, xPos, yPos);\n    }\n\n    public void dismiss() {\n        this.window.dismiss();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/DataRetrieverTask.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.appwidget.AutoRefreshService;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.utils.LoggingUtils;\nimport com.liato.bankdroid.utils.NetworkUtils;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.SharedPreferences;\nimport android.content.res.Resources;\nimport android.os.AsyncTask;\nimport android.preference.PreferenceManager;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport timber.log.Timber;\n\npublic class DataRetrieverTask extends AsyncTask<String, String, Void> {\n\n    private final ProgressDialog dialog;\n\n    private final MainActivity parent;\n\n    private final Resources res;\n\n    private ArrayList<String> errors;\n\n    private long bankId = -1;\n\n    public DataRetrieverTask(final MainActivity parent) {\n        this.parent = parent;\n        this.res = parent.getResources();\n        this.dialog = new ProgressDialog(parent);\n    }\n\n    public DataRetrieverTask(final MainActivity parent, final long bankId) {\n        this(parent);\n        this.bankId = bankId;\n    }\n\n    @Override\n    protected void onPreExecute() {\n        getDialog().setMessage(res.getText(R.string.updating_account_balance)\n                + \"\\n \");\n        getDialog().setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);\n        getDialog().setCancelable(false);\n        getDialog().show();\n    }\n\n    @NonNull\n    protected ProgressDialog getDialog() {\n        return this.dialog;\n    }\n\n    @Nullable\n    protected Bank getBankFromDb(long bankId, Context parent) {\n        return BankFactory.bankFromDb(bankId, parent, true);\n    }\n\n    protected List<Bank> getBanksFromDb(Context parent) {\n        return BankFactory.banksFromDb(parent, true);\n    }\n\n    protected void saveBank(Bank bank, Context context) {\n        DBAdapter.save(bank, parent);\n    }\n\n    protected void publishProgress(int zeroBasedBankNumber, @Nullable Bank bank) {\n        String text = \"\";\n        if (bank != null) {\n            text = bank.getName() + \" (\" + bank.getUsername() + \")\";\n        }\n        publishProgress(Integer.toString(zeroBasedBankNumber), text);\n    }\n\n    protected boolean isContentProviderEnabled() {\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(parent);\n        return prefs.getBoolean(\"content_provider_enabled\", false);\n    }\n\n    @Override\n    protected Void doInBackground(final String... args) {\n        errors = new ArrayList<>();\n        List<Bank> banks;\n        if (bankId != -1) {\n            banks = new ArrayList<>();\n            banks.add(getBankFromDb(bankId, parent));\n        } else {\n            banks = getBanksFromDb(parent);\n        }\n        getDialog().setMax(banks.size());\n        int i = 0;\n        for (final Bank bank : banks) {\n            publishProgress(i, bank);\n\n            if (isListingAllBanks() && bank.isDisabled()) {\n                LoggingUtils.logDisabledBank(bank);\n                continue;\n            }\n\n            try {\n                bank.update();\n                bank.updateAllTransactions();\n                bank.closeConnection();\n                saveBank(bank, parent);\n                i++;\n\n                LoggingUtils.logBankUpdate(bank, true);\n            } catch (final BankException e) {\n                this.errors.add(bank.getName() + \" (\" + bank.getUsername()\n                        + \")\");\n\n                Timber.e(e, \"Could not update bank.\");\n            } catch (final LoginException e) {\n                this.errors.add(bank.getName() + \" (\" + bank.getUsername()\n                        + \")\");\n                DBAdapter.disable(bank, parent);\n            } catch (BankChoiceException e) {\n                this.errors.add(bank.getName() + \" (\" + bank.getUsername()\n                        + \")\");\n            } catch (IOException e) {\n                this.errors.add(bank.getName() + \" (\" + bank.getUsername()\n                        + \")\");\n                if (NetworkUtils.isInternetAvailable()) {\n                    Timber.e(e, \"IO error talking to bank\");\n                }\n            }\n\n            if (isContentProviderEnabled()) {\n                final ArrayList<Account> accounts = bank.getAccounts();\n                for (final Account account : accounts) {\n                    AutoRefreshService.broadcastTransactionUpdate(parent,\n                            bank.getDbId(), account.getId());\n                }\n            }\n        }\n        publishProgress(i, null);\n        return null;\n    }\n\n    private boolean isListingAllBanks() {\n        return bankId == -1;\n    }\n\n    @Override\n    protected void onProgressUpdate(final String... args) {\n        getDialog().setProgress(Integer.parseInt(args[0]));\n        getDialog().setMessage(res.getText(R.string.updating_account_balance)\n                + \"\\n\" + args[1]);\n    }\n\n    @Override\n    protected void onPostExecute(final Void unused) {\n        parent.refreshView();\n        AutoRefreshService.sendWidgetRefresh(parent);\n        ActivityHelper.dismissDialog(getDialog());\n\n        if ((this.errors != null) && !this.errors.isEmpty()) {\n            final StringBuilder errormsg = new StringBuilder();\n            errormsg.append(res.getText(R.string.accounts_were_not_updated))\n                    .append(\":\\n\");\n            for (final String err : errors) {\n                errormsg.append(err);\n                errormsg.append(\"\\n\");\n            }\n            final AlertDialog.Builder builder = new AlertDialog.Builder(parent);\n            builder.setMessage(errormsg.toString())\n                    .setTitle(res.getText(R.string.errors_when_updating))\n                    .setIcon(android.R.drawable.ic_dialog_alert)\n                    .setNeutralButton(\"Ok\",\n                            new DialogInterface.OnClickListener() {\n                                @Override\n                                public void onClick(\n                                        final DialogInterface dialog,\n                                        final int id) {\n                                    dialog.cancel();\n                                }\n                            });\n            final AlertDialog alert = builder.create();\n            alert.show();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/LockableActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.lockpattern.ConfirmLockPattern;\nimport com.liato.bankdroid.lockpattern.LockPatternUtils;\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.RectF;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.preference.PreferenceManager;\nimport android.support.v7.app.ActionBarActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.view.View;\nimport android.view.WindowManager;\n\npublic class LockableActivity extends ActionBarActivity {\n\n    private static final int PATTERNLOCK_UNLOCK = 42;\n\n    protected boolean mSkipLockOnce = false;\n\n    private SharedPreferences mPrefs;\n\n    private LockPatternUtils mLockPatternUtils;\n\n    private boolean mHasLoaded = false;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);\n        mLockPatternUtils = new LockPatternUtils(this);\n        mLockPatternUtils\n                .setVisiblePatternEnabled(mPrefs.getBoolean(\"patternlock_visible_pattern\", true));\n        mLockPatternUtils.setTactileFeedbackEnabled(\n                mPrefs.getBoolean(\"patternlock_tactile_feedback\", false));\n//        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);\n        }\n    }\n\n    @Override\n    public void setContentView(int layoutResID) {\n        super.setContentView(layoutResID);\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        if (toolbar != null) {\n            if (shouldShowActionBar()) {\n                setSupportActionBar(toolbar);\n                toolbar.setLogo(R.drawable.ic_launcher);\n            } else {\n                toolbar.setVisibility(View.GONE);\n            }\n\n        }\n//        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title);\n//        View titlebar = findViewById(R.id.layTitle);\n//        mTitlebarButtons = (LinearLayout)titlebar.findViewById(R.id.layTitleButtons);\n//        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n//\n//        mHomeButton = (ImageView)titlebar.findViewById(R.id.imgTitle);\n//        mHomeButtonCont = titlebar.findViewById(R.id.layLogoContainer);\n//        mProgressBar = (ProgressBar)titlebar.findViewById(R.id.progressBar);\n//        OnClickListener listener = new View.OnClickListener() {\n//            public void onClick(View v) {\n//                Intent intent = new Intent(LockableActivity.this, MainActivity.class);\n//                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n//                startActivity(intent);\n//                LockableActivity.this.finish();\n//            }\n//        };\n//        mHomeButton.setOnClickListener(listener);\n//        mHomeButtonCont.setOnClickListener(listener);\n//        setHomeButtonEnabled(true);\n    }\n\n//    protected void addTitleButton(int imageResourceId, String tag, OnClickListener listener) {\n//        View child = mInflater.inflate(R.layout.title_item, mTitlebarButtons, false);\n//        ImageButton button = (ImageButton)child.findViewById(R.id.imgItemIcon);\n//        button.setImageResource(imageResourceId);\n//        button.setTag(tag);\n//        child.setTag(\"item_\"+tag);\n//        button.setOnClickListener(listener);\n//        mTitlebarButtons.addView(child);\n//    }\n//\n//    protected void hideTitleButton(String tag) {\n//        View v = mTitlebarButtons.findViewWithTag(\"item_\"+tag);\n//        if (v != null) {\n//            v.setVisibility(View.GONE);\n//        }\n//    }\n//\n//    protected void showTitleButton(String tag) {\n//        View v = mTitlebarButtons.findViewWithTag(\"item_\"+tag);\n//        if (v != null) {\n//            v.setVisibility(View.VISIBLE);\n//        }\n//    }\n//\n//    protected void setTitleButtonEnabled(String tag, boolean enabled) {\n//        View v = mTitlebarButtons.findViewWithTag(\"item_\"+tag);\n//        if (v != null) {\n//            ImageButton button = (ImageButton)v.findViewById(R.id.imgItemIcon);\n//            if (button != null) {\n//                v.setEnabled(enabled);\n//                v.setFocusable(enabled);\n//                button.setEnabled(enabled);\n//                button.setAlpha(enabled ? 255 : 50);\n//            }\n//        }\n//    }\n//\n//    protected void setHomeButtonEnabled(boolean enabled) {\n//        mHomeButtonCont.setFocusable(enabled);\n//        mHomeButtonCont.setClickable(enabled);\n//        mHomeButton.setFocusable(enabled);\n//        mHomeButton.setClickable(enabled);\n//    }\n//\n//    protected void setProgressBar(int progress) {\n//        mProgressBar.setProgress(progress);\n//    }\n//\n//    protected void showProgressBar() {\n//        mProgressBar.setVisibility(View.VISIBLE);\n//    }\n//\n//    protected void hideProgressBar() {\n//        AlphaAnimation animation = new AlphaAnimation(1, 0);\n//        animation.setDuration(350);\n//        animation.setAnimationListener(new AnimationListener() {\n//            @Override\n//            public void onAnimationEnd(Animation animation) {\n//                mProgressBar.setVisibility(View.GONE);\n//            }\n//\n//            @Override\n//            public void onAnimationRepeat(Animation animation) {}\n//\n//            @Override\n//            public void onAnimationStart(Animation animation) {}\n//        });\n//        mProgressBar.startAnimation(animation);\n//    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        // Don't do anything if no lock pattern is set\n        if (!mLockPatternUtils.isLockPatternEnabled()) {\n            return;\n        }\n        /*\n                Save the current time If a lock pattern has been set\n        If this activity never loaded set the lock time to\n        10 seconds ago.\n        This is to prevent the following scenario:\n            1. Activity Starts\n            2. Lock screen is displayed\n            3. User presses the home button\n            4. \"lock time\" is set in onPause to when the home button was pressed\n            5. Activity is started again within 2 seconds and no lock screen is shown this time.\n        */\n        if (mHasLoaded) {\n            writeLockTime();\n        } else {\n            writeLockTime(SystemClock.elapsedRealtime() - 10000);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        // Don't do anything if no lock pattern is set\n        if (!mLockPatternUtils.isLockPatternEnabled()) {\n            return;\n        }\n        if (mSkipLockOnce) {\n            mSkipLockOnce = false;\n            return;\n        }\n        // If a lock pattern is set we need to check the time for when the last\n        // activity was open. If it's been more than two seconds the user\n        // will have to enter the lock pattern to continue.\n        long currentTime = SystemClock.elapsedRealtime();\n        long lockedAt = mPrefs.getLong(\"locked_at\", currentTime - 10000);\n        long timedif = Math.abs(currentTime - lockedAt);\n        if (timedif > 2000) {\n            mHasLoaded = false;\n            launchPatternLock();\n        } else {\n            mHasLoaded = true;\n        }\n    }\n\n    private void launchPatternLock() {\n        Intent intent = new Intent(this, ConfirmLockPattern.class);\n        intent.putExtra(ConfirmLockPattern.HEADER_TEXT, getText(R.string.patternlock_header));\n        startActivityForResult(intent, PATTERNLOCK_UNLOCK);\n    }\n\n    private void writeLockTime() {\n        writeLockTime(SystemClock.elapsedRealtime());\n    }\n\n    private void writeLockTime(long time) {\n        Editor editor = mPrefs.edit();\n        editor.putLong(\"locked_at\", time);\n        editor.apply();\n    }\n\n    protected void onActivityResult(int requestCode, int resultCode,\n            Intent data) {\n        if (requestCode == PATTERNLOCK_UNLOCK) {\n            if (resultCode == RESULT_OK) {\n                writeLockTime();\n            } else {\n                launchPatternLock();\n            }\n        }\n    }\n\n    protected void skipLockOnce() {\n        mSkipLockOnce = true;\n    }\n\n\n    @Override\n    public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {\n        View decorview = getWindow().getDecorView();\n        if (decorview == null) {\n            return true;\n        }\n\n        final int vw = decorview.getWidth();\n        final int vh = decorview.getHeight();\n        final int dw = outBitmap.getWidth();\n        final int dh = outBitmap.getHeight();\n\n        Bitmap bluredBitmap = Bitmap\n                .createBitmap(outBitmap.getWidth(), outBitmap.getHeight(), outBitmap.getConfig());\n        Canvas c = new Canvas(bluredBitmap);\n\n        c.save();\n        c.scale(((float) dw) / vw, ((float) dh) / vh);\n        decorview.draw(c);\n        c.restore();\n\n        canvas.drawBitmap(pixelate(bluredBitmap, 5), 0, 0, null);\n        Bitmap lockbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lock);\n\n        Paint p = new Paint();\n        p.setAntiAlias(true);\n        p.setDither(true);\n        p.setFilterBitmap(true);\n\n        canvas.drawBitmap(lockbitmap, null,\n                new RectF(dw * 0.25f, dh * 0.25f, dw * 0.75f, dh * 0.75f), p);\n\n        return true;\n    }\n\n    private Bitmap pixelate(Bitmap bitmap, int size) {\n        Bitmap bm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());\n        Canvas c = new Canvas(bm);\n        Paint p = new Paint();\n        p.setStyle(Style.FILL);\n        int w = bm.getWidth();\n        int h = bm.getHeight();\n\n        int[] pixels = new int[w * h];\n        bitmap.getPixels(pixels, 0, w, 0, 0, w, h);\n        for (int i = 0; i < h; i = i + size) {\n            for (int j = 0; j < w; j = j + size) {\n                int a = 0;\n                int r = 0;\n                int g = 0;\n                int b = 0;\n                int pc = 0;\n                for (int k = 0; k < size; k++) {\n                    for (int l = 0; l < size; l++) {\n                        int pxp = (i + k) * w + j + l;\n                        if (pxp < pixels.length) {\n                            int pixel = pixels[pxp];\n                            a += Color.alpha(pixel);\n                            r += Color.red(pixel);\n                            g += Color.green(pixel);\n                            b += Color.blue(pixel);\n                            pc++;\n                        }\n                    }\n                }\n                a /= pc;\n                r /= pc;\n                g /= pc;\n                b /= pc;\n                p.setColor(Color.argb(a, r, g, b));\n                c.drawRect(j, i, j + size, i + size, p);\n            }\n        }\n        return bm;\n    }\n\n    public boolean shouldShowActionBar() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/LockablePreferenceActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.lockpattern.ConfirmLockPattern;\nimport com.liato.bankdroid.lockpattern.LockPatternUtils;\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.preference.PreferenceActivity;\nimport android.preference.PreferenceManager;\nimport android.view.WindowManager;\n\npublic class LockablePreferenceActivity extends PreferenceActivity {\n\n    private static final int PATTERNLOCK_UNLOCK = 42;\n\n    private SharedPreferences mPrefs;\n\n    private LockPatternUtils mLockPatternUtils;\n\n    private boolean mHasLoaded = false;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);\n        mLockPatternUtils = new LockPatternUtils(this);\n        mLockPatternUtils\n                .setVisiblePatternEnabled(mPrefs.getBoolean(\"patternlock_visible_pattern\", true));\n        mLockPatternUtils.setTactileFeedbackEnabled(\n                mPrefs.getBoolean(\"patternlock_tactile_feedback\", false));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        // Don't do anything if no lock pattern is set\n        if (!mLockPatternUtils.isLockPatternEnabled()) {\n            return;\n        }\n        /*\n        Save the current time If a lock pattern has been set\n        If this activity never loaded set the lock time to\n        10 seconds ago.\n        This is to prevent the following scenario:\n            1. Activity Starts\n            2. Lock screen is displayed\n            3. User presses the home button\n            4. \"lock time\" is set in onPause to when the home button was pressed\n            5. Activity is started again within 2 seconds and no lock screen is shown this time.\n        */\n        if (mHasLoaded) {\n            writeLockTime();\n        } else {\n            writeLockTime(SystemClock.elapsedRealtime() - 10000);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        // Don't do anything if lock pattern is not set\n        if (!mLockPatternUtils.isLockPatternEnabled() || !isLockEnabled()) {\n            return;\n        }\n        // If a lock pattern is set we need to check the time for when the last\n        // activity was open. If it's been more than two seconds the user\n        // will have to enter the lock pattern to continue.\n        long currentTime = SystemClock.elapsedRealtime();\n        long lockedAt = mPrefs.getLong(\"locked_at\", currentTime - 10000);\n        long timedif = Math.abs(currentTime - lockedAt);\n        if (timedif > 2000) {\n            launchPatternLock();\n        } else {\n            mHasLoaded = true;\n        }\n    }\n\n    private void launchPatternLock() {\n        Intent intent = new Intent(this, ConfirmLockPattern.class);\n        intent.putExtra(ConfirmLockPattern.HEADER_TEXT, getText(R.string.patternlock_header));\n        startActivityForResult(intent, PATTERNLOCK_UNLOCK);\n    }\n\n    private void writeLockTime() {\n        writeLockTime(SystemClock.elapsedRealtime());\n    }\n\n    private void writeLockTime(long time) {\n        Editor editor = mPrefs.edit();\n        editor.putLong(\"locked_at\", time);\n        editor.apply();\n    }\n\n    protected boolean isLockEnabled() {\n        return mPrefs.getBoolean(\"lock_enabled\", true);\n    }\n\n    protected void setLockEnabled(boolean enabled) {\n        Editor editor = mPrefs.edit();\n        editor.putBoolean(\"lock_enabled\", enabled);\n        editor.apply();\n    }\n\n    protected void onActivityResult(int requestCode, int resultCode,\n            Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == PATTERNLOCK_UNLOCK) {\n            if (resultCode == RESULT_OK) {\n                writeLockTime();\n            } else {\n                launchPatternLock();\n            }\n        }\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        setLockEnabled(true);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/MainActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.adapters.AccountsAdapter;\nimport com.liato.bankdroid.appwidget.AutoRefreshService;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.db.DBAdapter;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.AdapterView.OnItemLongClickListener;\nimport android.widget.Button;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\n\nimport butterknife.ButterKnife;\nimport butterknife.InjectView;\n\npublic class MainActivity extends LockableActivity {\n\n    @InjectView(R.id.txtAccountsDesc)\n    TextView mAccountsDescription;\n\n    protected static boolean showHidden = false;\n\n    private Bank selectedBank = null;\n\n    private static Account selectedAccount = null;\n\n    private final BroadcastReceiver receiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(final Context context, final Intent intent) {\n            refreshView();\n        }\n    };\n\n    protected AccountsAdapter adapter = null;\n\n    @Override\n    public void onCreate(final Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        PairApplicationsActivity.initialSetupApiKey(this);\n\n        setContentView(R.layout.main);\n        ButterKnife.inject(this);\n\n        adapter = new AccountsAdapter(this, showHidden);\n        final ArrayList<Bank> banks = new ArrayList<>();\n        adapter.setGroups(banks);\n        final ListView lv = (ListView) findViewById(R.id.lstAccountsList);\n        lv.setAdapter(adapter);\n        lv.setOnItemLongClickListener(new OnItemLongClickListener() {\n            @Override\n            public boolean onItemLongClick(final AdapterView<?> parent, final View view,\n                    final int position, final long id) {\n                if (adapter.getItem(position) instanceof Account) {\n                    selectedAccount = (Account) adapter.getItem(position);\n                    final PopupMenuAccount pmenu = new PopupMenuAccount(parent, view, MainActivity.this);\n                    pmenu.showLikeQuickAction(0, 12);\n                    return true;\n                } else if (adapter.getItem(position) instanceof Bank) {\n                    selectedBank = (Bank) adapter.getItem(position);\n                    selectedBank.toggleHideAccounts();\n                    DBAdapter.save(selectedBank, MainActivity.this);\n                    refreshView();\n                    return true;\n                }\n                return false;\n            }\n        });\n        lv.setOnItemClickListener(new OnItemClickListener() {\n            @Override\n            public void onItemClick(final AdapterView<?> parent, final View view,\n                    final int position, final long id) {\n                if (adapter.getItem(position) instanceof Bank) {\n                    selectedBank = (Bank) adapter.getItem(position);\n                    final PopupMenuBank pmenu = new PopupMenuBank(parent, view, MainActivity.this);\n                    pmenu.showLikeQuickAction(0, 12);\n                } else {\n                    final Intent intent = new Intent(MainActivity.this, TransactionsActivity.class);\n                    final Account account = (Account) adapter.getItem(position);\n                    intent.putExtra(\"account\", account.getId());\n                    intent.putExtra(\"bank\", account.getBankDbId());\n                    MainActivity.this.startActivity(intent);\n                }\n            }\n        });\n\n        final Bundle extras = getIntent().getExtras();\n        // Clicking on widgets opens the transactions history through MainActivity so that\n        // the user can back out to the main window.\n        if (AutoRefreshService.ACTION_MAIN_SHOW_TRANSACTIONS.equals(getIntent().getAction())) {\n            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\n            if (prefs.getBoolean(\"widget_opens_transactions\", true)) {\n                skipLockOnce();\n                final Intent intent = new Intent(this, TransactionsActivity.class);\n                intent.putExtra(\"account\", extras.getString(\"account\"));\n                intent.putExtra(\"bank\", extras.getLong(\"bank\"));\n                startActivity(intent);\n            }\n        }\n        ((BankdroidApplication) getApplication()).showAndDeleteApplicationMessage();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        // Receive refresh Intent from AutoRefreshService and refresh the main view if changes\n        // have been detected.\n        registerReceiver(receiver, new IntentFilter(AutoRefreshService.BROADCAST_MAIN_REFRESH));\n        refreshView();\n    }\n\n    public void refreshView() {\n        final ArrayList<Bank> banks = BankFactory.banksFromDb(this, true);\n        mAccountsDescription.setVisibility(banks.isEmpty() ? View.VISIBLE : View.GONE);\n\n        adapter.setShowHidden(showHidden);\n        adapter.setGroups(banks);\n        adapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(final Menu menu) {\n        super.onCreateOptionsMenu(menu);\n        final MenuInflater inflater = new MenuInflater(this);\n        inflater.inflate(R.menu.main, menu);\n        return true;\n    }\n\n\n    @Override\n    protected Dialog onCreateDialog(final int id) {\n        super.onCreateDialog(id);\n        final Dialog dialog = new Dialog(this);\n        dialog.setContentView(R.layout.about);\n        dialog.setTitle(getString(R.string.about));\n        String version = BuildConfig.VERSION_NAME;\n        ((TextView) dialog.findViewById(R.id.txtVersion))\n                .setText(getText(R.string.version).toString().replace(\"$version\", version));\n        return dialog;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(final MenuItem item) {\n        Intent intent;\n        switch (item.getItemId()) {\n            case R.id.action_toggle_hidden:\n                showHidden = !showHidden;\n                item.setTitle(showHidden ? R.string.menu_hide_hidden : R.string.menu_show_hidden);\n                refreshView();\n                return true;\n            case R.id.action_settings:\n                intent = new Intent(this, SettingsActivity.class);\n                this.startActivity(intent);\n                //Helpers.setActivityAnimation(this, R.anim.zoom_enter, R.anim.zoom_exit);\n                return true;\n            case R.id.action_about:\n                intent = new Intent(this, AboutActivity.class);\n                startActivity(intent);\n                return true;\n            case R.id.action_refresh:\n                new DataRetrieverTask(MainActivity.this).execute();\n                return true;\n            case R.id.action_add:\n                final Intent intentAccount = new Intent(MainActivity.this, BankEditActivity.class);\n                startActivity(intentAccount);\n                return true;\n\n        }\n        return false;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        unregisterReceiver(receiver);\n    }\n\n    /**\n     * Extends {@link BetterPopupWindow}\n     * <p>\n     * Overrides onCreate to create the view and register the button listeners\n     *\n     * @author qbert\n     */\n    private static class PopupMenuBank extends BetterPopupWindow implements OnClickListener {\n\n        MainActivity parent = null;\n\n        public PopupMenuBank(final ViewGroup parentView, final View anchor, final MainActivity parent) {\n            super(parentView, anchor);\n            this.parent = parent;\n        }\n\n        @Override\n        protected void onCreate() {\n            // inflate layout\n            final LayoutInflater inflater =\n                    (LayoutInflater) this.anchor.getContext()\n                            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n\n            final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.popup_bank, this.parentView, false);\n            final Button btnHide = (Button) root.findViewById(R.id.btnHide);\n            final Button btnUnhide = (Button) root.findViewById(R.id.btnUnhide);\n            final Button btnWWW = (Button) root.findViewById(R.id.btnWWW);\n            if (parent.selectedBank.getHideAccounts()) {\n                btnHide.setVisibility(View.GONE);\n                btnUnhide.setVisibility(View.VISIBLE);\n                btnUnhide.setOnClickListener(this);\n            } else {\n                btnHide.setVisibility(View.VISIBLE);\n                btnUnhide.setVisibility(View.GONE);\n                btnHide.setOnClickListener(this);\n            }\n            if (parent.selectedBank.isWebViewEnabled()) {\n                btnWWW.setOnClickListener(this);\n            } else {\n                btnWWW.setVisibility(View.GONE);\n            }\n            root.findViewById(R.id.btnRefresh).setOnClickListener(this);\n            root.findViewById(R.id.btnEdit).setOnClickListener(this);\n            root.findViewById(R.id.btnRemove).setOnClickListener(this);\n\n            this.setContentView(root);\n        }\n\n        @Override\n        public void onClick(final View v) {\n            final Context context = this.anchor.getContext();\n            final int id = v.getId();\n            switch (id) {\n                case R.id.btnHide:\n                case R.id.btnUnhide:\n                    this.dismiss();\n                    parent.selectedBank.toggleHideAccounts();\n                    DBAdapter.save(parent.selectedBank, context);\n                    parent.refreshView();\n                    return;\n                case R.id.btnWWW:\n                    if (parent.selectedBank != null && parent.selectedBank.isWebViewEnabled()) {\n                        //Uri uri = Uri.parse(selectedBank.getURL());\n                        //Intent intent = new Intent(Intent.ACTION_VIEW, uri);\n                        final Intent intent = new Intent(context, WebViewActivity.class);\n                        intent.putExtra(\"bankid\", parent.selectedBank.getDbId());\n                        context.startActivity(intent);\n                    }\n                    this.dismiss();\n                    return;\n                case R.id.btnEdit:\n                    final Intent intent = new Intent(context, BankEditActivity.class);\n                    intent.putExtra(\"id\", parent.selectedBank.getDbId());\n                    context.startActivity(intent);\n                    this.dismiss();\n                    return;\n                case R.id.btnRefresh:\n                    this.dismiss();\n                    new DataRetrieverTask(parent, parent.selectedBank.getDbId()).execute();\n                    return;\n                case R.id.btnRemove:\n                    this.dismiss();\n                    final AlertDialog.Builder builder = new AlertDialog.Builder(context);\n                    //builder.setMessage(getText(R.string.passwords_mismatch)).setTitle(getText(R.string.passwords_mismatch_title))\n                    builder.setMessage(context.getText(R.string.remove_bank_msg))\n                            .setTitle(context.getText(R.string.remove_bank_title))\n                            .setIcon(android.R.drawable.ic_dialog_alert)\n                            .setPositiveButton(context.getText(R.string.yes),\n                                    new DialogInterface.OnClickListener() {\n                                        @Override\n                                        public void onClick(final DialogInterface dialog,\n                                                final int id) {\n                                            final DBAdapter db = new DBAdapter(context);\n                                            db.deleteBank(parent.selectedBank.getDbId());\n                                            dialog.cancel();\n                                            parent.refreshView();\n                                        }\n                                    })\n                            .setNegativeButton(context.getText(R.string.no),\n                                    new DialogInterface.OnClickListener() {\n                                        @Override\n                                        public void onClick(final DialogInterface dialog,\n                                                final int id) {\n                                            dialog.cancel();\n                                        }\n                                    });\n                    final AlertDialog alert = builder.create();\n                    alert.show();\n                    return;\n            }\n\n        }\n    }\n\n\n    /**\n     * Extends {@link BetterPopupWindow}\n     * <p>\n     * Overrides onCreate to create the view and register the button listeners\n     *\n     * @author qbert\n     */\n    private static class PopupMenuAccount extends BetterPopupWindow implements OnClickListener {\n\n        MainActivity parent = null;\n\n        public PopupMenuAccount(final ViewGroup parentView, final View anchor, final MainActivity parent) {\n            super(parentView, anchor);\n            this.parent = parent;\n        }\n\n        @Override\n        protected void onCreate() {\n            final LayoutInflater inflater =\n                    (LayoutInflater) this.anchor.getContext()\n                            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n\n            final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.popup_account, this.parentView, false);\n            final Button btnHide = (Button) root.findViewById(R.id.btnHide);\n            final Button btnUnhide = (Button) root.findViewById(R.id.btnUnhide);\n            final Button btnDisableNotifications = (Button) root\n                    .findViewById(R.id.btnDisableNotifications);\n            final Button btnEnableNotifications = (Button) root\n                    .findViewById(R.id.btnEnableNotifications);\n            if (selectedAccount.isHidden()) {\n                btnHide.setVisibility(View.GONE);\n                btnUnhide.setVisibility(View.VISIBLE);\n                btnUnhide.setOnClickListener(this);\n            } else {\n                btnHide.setVisibility(View.VISIBLE);\n                btnUnhide.setVisibility(View.GONE);\n                btnHide.setOnClickListener(this);\n            }\n            if (selectedAccount.isNotify()) {\n                btnDisableNotifications.setVisibility(View.VISIBLE);\n                btnDisableNotifications.setOnClickListener(this);\n                btnEnableNotifications.setVisibility(View.GONE);\n            } else {\n                btnDisableNotifications.setVisibility(View.GONE);\n                btnEnableNotifications.setOnClickListener(this);\n                btnEnableNotifications.setVisibility(View.VISIBLE);\n            }\n            this.setContentView(root);\n        }\n\n        @Override\n        public void onClick(final View v) {\n            final int id = v.getId();\n            switch (id) {\n                case R.id.btnHide:\n                    this.dismiss();\n                    selectedAccount.setHidden(true);\n                    DBAdapter.save(selectedAccount.getBank(), parent);\n                    parent.refreshView();\n                    return;\n                case R.id.btnUnhide:\n                    this.dismiss();\n                    selectedAccount.setHidden(false);\n                    DBAdapter.save(selectedAccount.getBank(), parent);\n                    parent.refreshView();\n                    return;\n                case R.id.btnEnableNotifications:\n                    this.dismiss();\n                    selectedAccount.setNotify(true);\n                    DBAdapter.save(selectedAccount.getBank(), parent);\n                    parent.refreshView();\n                    return;\n                case R.id.btnDisableNotifications:\n                    this.dismiss();\n                    selectedAccount.setNotify(false);\n                    DBAdapter.save(selectedAccount.getBank(), parent);\n                    parent.refreshView();\n                    return;\n\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/PairApplicationsActivity.java",
    "content": "/**\n * Copyright 2011 Magnus Andersson\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.provider.BankTransactionsProvider;\nimport com.liato.bankdroid.provider.IBankTransactionsProvider;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.preference.PreferenceManager;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport timber.log.Timber;\n\n/**\n * @author Magnus Andersson\n * @since 8 jun 2011\n */\npublic class PairApplicationsActivity extends LockableActivity {\n\n    private static final String PAIR_APP_NAME = \"com.liato.bankdroid.PAIR_APP_NAME\";\n\n    public static void initialSetupApiKey(Context ctx) {\n        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);\n        final String apiKey = prefs.getString(\"content_provider_api_key\", \"\");\n        if (apiKey.equals(\"\")) {\n            final SharedPreferences.Editor editor = prefs.edit();\n\n            // Create a random HEX String\n            final String genKey = Long.toHexString(Double.doubleToLongBits(Math.random()));\n\n            // Commit to preferences\n            editor.putString(\"content_provider_api_key\", genKey.toUpperCase());\n            editor.apply();\n        }\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    protected void onCreate(final Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.pair_applications_layout);\n//        setHomeButtonEnabled(false);\n\n        Bundle bundle = getIntent().getExtras();\n\n        if (bundle.containsKey(PAIR_APP_NAME)) {\n            String appName = bundle.getString(PAIR_APP_NAME);\n\n            ImageView img = (ImageView) findViewById(R.id.imageView1);\n\n            // Note that we used to load this dynamically, but Ekonomipuls was the\n            // only user ever. Doing it statically like this helps Android Lint\n            // know that the logo in question is still in use.\n            Drawable d = getResources().getDrawable(R.drawable.applogo_ekonomipuls);\n            img.setImageDrawable(d);\n            img.requestLayout();\n\n            // Change application name\n            TextView appNameView = (TextView) findViewById(R.id.app_name);\n            appNameView.setText(appName);\n        } else {\n            Timber.w(\"Unknown application\");\n        }\n\n\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        //Handle the back button\n        if (keyCode == KeyEvent.KEYCODE_BACK) {\n            setResult(RESULT_CANCELED);\n            finish();\n            return true;\n        }\n\n        return super.onKeyDown(keyCode, event);\n    }\n\n    public void cancelPairing(final View v) {\n        setResult(RESULT_CANCELED);\n        finish();\n    }\n\n    public void confirmPairing(final View v) {\n        Intent intent = this.getIntent();\n\n        Context ctx = getBaseContext();\n\n        // Make sure sharing is enabled\n        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ctx);\n        Editor editor = pref.edit();\n        editor.putBoolean(\"content_provider_enabled\", true);\n        editor.apply();\n        String apiKey;\n\n        try {\n            apiKey = BankTransactionsProvider.getApiKey(ctx);\n        } catch (IllegalArgumentException e) {\n            //Initialize API key if it is not set\n            initialSetupApiKey(ctx);\n            apiKey = BankTransactionsProvider.getApiKey(ctx);\n        }\n\n        intent.putExtra(IBankTransactionsProvider.API_KEY, apiKey);\n        setResult(RESULT_OK, intent);\n\n        finish();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/SettingsActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.appwidget.AutoRefreshService;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.banks.TestBank;\nimport com.liato.bankdroid.banking.banks.nordea.Nordea;\nimport com.liato.bankdroid.lockpattern.ChooseLockPattern;\nimport com.liato.bankdroid.lockpattern.ConfirmLockPattern;\nimport com.liato.bankdroid.lockpattern.LockPatternUtils;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.CheckBoxPreference;\nimport android.preference.Preference;\nimport android.preference.Preference.OnPreferenceChangeListener;\nimport android.preference.Preference.OnPreferenceClickListener;\nimport android.preference.PreferenceScreen;\nimport android.widget.Toast;\n\nimport java.math.BigDecimal;\n\nimport timber.log.Timber;\n\npublic class SettingsActivity extends LockablePreferenceActivity\n        implements OnPreferenceClickListener, OnPreferenceChangeListener {\n\n    private final static int DISABLE_LOCKPATTERN = 1;\n\n    private final static int ENABLE_LOCKPATTERN = 2;\n\n    private final static int CHANGE_LOCKPATTERN = 3;\n\n    private LockPatternUtils mLockPatternUtils;\n\n    /** Called when the activity is first created. */\n    @Override\n    public void onCreate(final Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mLockPatternUtils = new LockPatternUtils(this);\n        addPreferencesFromResource(R.xml.settings);\n        getWindow().setBackgroundDrawableResource(R.drawable.background_repeat);\n        (findPreference(\"patternlock_change\")).setOnPreferenceClickListener(this);\n        (findPreference(\"remotenotifier_help\")).setOnPreferenceClickListener(this);\n        (findPreference(\"openwatch_help\")).setOnPreferenceClickListener(this);\n        (findPreference(\"liveview_help\")).setOnPreferenceClickListener(this);\n        (findPreference(\"account_types_screen\")).setOnPreferenceClickListener(this);\n        (findPreference(\"remotenotifier_screen\")).setOnPreferenceClickListener(this);\n        (findPreference(\"openwatch_screen\")).setOnPreferenceClickListener(this);\n        (findPreference(\"liveview_screen\")).setOnPreferenceClickListener(this);\n        (findPreference(\"notification_sound\")).setOnPreferenceClickListener(this);\n        (findPreference(\"test_notification\")).setOnPreferenceClickListener(this);\n        (findPreference(\"notify_min_delta\")).setOnPreferenceChangeListener(this);\n        final CheckBoxPreference patternLock = ((CheckBoxPreference) findPreference(\n                \"patternlock_enabled\"));\n        patternLock.setOnPreferenceClickListener(this);\n        // Check the pattern lock check box if the lock pattern is enabled\n        patternLock.setChecked(mLockPatternUtils.isLockPatternEnabled());\n    }\n\n    @Override\n    public boolean onPreferenceClick(final Preference pref) {\n        final String prefKey = pref.getKey();\n        if (\"account_types_screen\".equals(prefKey) ||\n                \"remotenotifier_screen\".equals(prefKey) ||\n                \"openwatch_screen\".equals(prefKey) ||\n                \"liveview_screen\".equals(prefKey)) {\n            ((PreferenceScreen) pref).getDialog().getWindow()\n                    .setBackgroundDrawableResource(R.drawable.background_repeat);\n            return false;\n        }\n\n        if (\"notification_sound\".equals(prefKey)) {\n            return false;\n        }\n\n        if (\"patternlock_enabled\".equals(prefKey)) {\n            this.setLockEnabled(false);\n            if (mLockPatternUtils.isLockPatternEnabled()) {\n                // The user is trying to disable the lock pattern,\n                // only disable if the user knows the pattern.\n                startActivityForResult(new Intent(this, ConfirmLockPattern.class),\n                        DISABLE_LOCKPATTERN);\n                return true;\n            } else {\n                // No lock pattern has been set yet, let the user choose a new one.\n                startActivityForResult(new Intent(this, ChooseLockPattern.class),\n                        ENABLE_LOCKPATTERN);\n                return true;\n            }\n        } else if (\"patternlock_change\".equals(prefKey)) {\n            this.setLockEnabled(false);\n            startActivityForResult(new Intent(this, ChooseLockPattern.class), CHANGE_LOCKPATTERN);\n            return true;\n        } else if (\"remotenotifier_help\".equals(prefKey)) {\n            startActivity(new Intent(Intent.ACTION_VIEW,\n                    Uri.parse(\"http://code.google.com/p/android-notifier/\")));\n            return true;\n        } else if (\"openwatch_help\".equals(prefKey)) {\n            startActivity(new Intent(Intent.ACTION_VIEW,\n                    Uri.parse(\"http://forum.xda-developers.com/showthread.php?t=554551\")));\n            return true;\n        } else if (\"liveview_help\".equals(prefKey)) {\n            startActivity(new Intent(Intent.ACTION_VIEW,\n                    Uri.parse(\n                            \"http://www.sonyericsson.com/cws/products/accessories/overview/liveviewmicrodisplay\")));\n            return true;\n        } else if (\"test_notification\".equals(prefKey)) {\n            Timber.d(\"Sending test notification.\");\n            Account account1 = new Account(\"Personkonto\", new BigDecimal(8351.00), \"22\");\n            Bank bank1 = new TestBank(this);\n            bank1.setDbid(21);\n            bank1.setCustomName(\"800416-0001\");\n\n            Account account2 = new Account(\"Personkonto\", new BigDecimal(8341.00), \"23\");\n            Bank bank2 = new Nordea(this);\n            bank2.setDbid(22);\n            bank2.setCustomName(\"800416-0002\");\n\n            AutoRefreshService.showNotification(bank1, account1, new BigDecimal(-143.50), this);\n            AutoRefreshService.showNotification(bank2, account2, new BigDecimal(-123.50), this);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    protected void onActivityResult(final int requestCode, final int resultCode,\n            final Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == DISABLE_LOCKPATTERN) {\n            if (resultCode == RESULT_OK) {\n                mLockPatternUtils.setLockPatternEnabled(false);\n                mLockPatternUtils.saveLockPattern(null);\n                ((CheckBoxPreference) findPreference(\"patternlock_enabled\")).setChecked(false);\n            } else {\n                Timber.d(\"User was unable to disable pattern lock.\");\n            }\n        } else if (requestCode == ENABLE_LOCKPATTERN) {\n            // User attempted to enable the pattern lock, toggle the checkbox.\n            ((CheckBoxPreference) findPreference(\"patternlock_enabled\"))\n                    .setChecked(mLockPatternUtils.isLockPatternEnabled());\n        } else if (requestCode == CHANGE_LOCKPATTERN) {\n            // Don't do anything special\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        this.setLockEnabled(true);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        StartupReceiver.setAlarm(this);\n        // Blur/unblur the widget balance\n        AutoRefreshService.sendWidgetRefresh(this);\n    }\n\n    @Override\n    public boolean onPreferenceChange(Preference pref, Object newValue) {\n        final String prefKey = pref.getKey();\n        if (\"notify_min_delta\".equals(prefKey)) {\n            Integer val;\n            try {\n                val = Integer.valueOf((String) newValue);\n            } catch (NumberFormatException e) {\n                val = null;\n            }\n\n            if (val != null && val >= 0) {\n                return true;\n            } else {\n                Toast.makeText(pref.getContext(),\n                        String.format(pref.getContext().getString(R.string.invalid_integer),\n                                newValue), Toast.LENGTH_LONG).show();\n            }\n            return false;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/StartupReceiver.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.appwidget.AutoRefreshService;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.net.ConnectivityManager;\nimport android.os.SystemClock;\nimport android.preference.PreferenceManager;\n\npublic class StartupReceiver extends BroadcastReceiver {\n\n    public static void setAlarm(Context context) {\n        PendingIntent alarmSender;\n        alarmSender = PendingIntent\n                .getService(context, 0, new Intent(context, AutoRefreshService.class),\n                        PendingIntent.FLAG_UPDATE_CURRENT);\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        boolean autoUpdatesEnabled = prefs.getBoolean(\"autoupdates_enabled\", true);\n        Integer refreshRate = Integer.parseInt(prefs.getString(\"refresh_rate\", \"0\"));\n        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        if (!autoUpdatesEnabled) {\n            am.cancel(alarmSender);\n        } else {\n            long firstTime = SystemClock.elapsedRealtime();\n            int secondsInMinute = 60;\n            if (prefs.getBoolean(\"debug_mode\", false) && prefs\n                    .getBoolean(\"debug_refreshrate_in_seconds\", false)) {\n                secondsInMinute = 1;\n            }\n            am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,\n                    firstTime + refreshRate * secondsInMinute * 1000,\n                    refreshRate * secondsInMinute * 1000, alarmSender);\n        }\n\n    }\n\n    public static void updateNow(Context context) {\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        boolean autoUpdatesEnabled = prefs.getBoolean(\"autoupdates_enabled\", true);\n        long lastUpdate = prefs.getLong(\"autoupdates_last_update\", 0);\n        Integer refreshRate = Integer.parseInt(prefs.getString(\"refresh_rate\", \"0\"));\n        if (autoUpdatesEnabled\n                && System.currentTimeMillis() - lastUpdate > refreshRate * 60 * 1000) {\n            context.startService(new Intent(context, AutoRefreshService.class));\n        }\n    }\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        //Set alarms for auto updates on boot, package update, package replace and package new\n        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {\n            updateNow(context);\n        } else {\n            setAlarm(context);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/TimePreference.java",
    "content": "//This class  based on tutorial found here https://github.com/commonsguy/cw-lunchlist/blob/master/19-Alarm/LunchList/src/apt/tutorial/TimePreference.java\npackage com.liato.bankdroid;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.preference.DialogPreference;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.TimePicker;\n\nimport timber.log.Timber;\n\npublic class TimePreference extends DialogPreference {\n\n    private int lastValue = 0;\n\n    private TimePicker picker = null;\n\n    public TimePreference(Context ctxt, AttributeSet attrs) {\n        super(ctxt, attrs);\n\n        setPositiveButtonText(\"Set\");\n        setNegativeButtonText(\"Cancel\");\n    }\n\n    @Override\n    protected View onCreateDialogView() {\n        picker = new TimePicker(getContext());\n        picker.setIs24HourView(true);\n        return picker;\n    }\n\n    @Override\n    protected void onBindDialogView(View v) {\n        super.onBindDialogView(v);\n\n        picker.setCurrentHour(lastValue / 60);\n        picker.setCurrentMinute(lastValue % 60);\n    }\n\n    @Override\n    protected void onDialogClosed(boolean positiveResult) {\n        super.onDialogClosed(positiveResult);\n\n        if (positiveResult) {\n            lastValue = picker.getCurrentHour() * 60 + picker.getCurrentMinute();\n\n            if (callChangeListener(lastValue)) {\n                persistInt(lastValue);\n            }\n        }\n    }\n\n    @Override\n    protected Object onGetDefaultValue(TypedArray a, int index) {\n        return (a.getInt(index, 0));\n    }\n\n    @Override\n    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {\n        int val = 0;\n\n        if (restoreValue) {\n            val = getPersistedInt(val);\n        } else {\n            try {\n                val = Integer.parseInt(defaultValue.toString());\n            } catch (NumberFormatException e) {\n                Timber.e(e, \"TimePreference's defaultValue is not a number\");\n            }\n        }\n\n        lastValue = val;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/TransactionsActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.banking.Transaction;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class TransactionsActivity extends LockableActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.transactions);\n        Bundle extras = getIntent().getExtras();\n        Bank bank = BankFactory.bankFromDb(extras.getLong(\"bank\"), this, false);\n        if (bank == null) {\n            redirectToMain(getString(R.string.error_bank_not_found));\n            return;\n        }\n        Account account = BankFactory\n                .accountFromDb(this, extras.getLong(\"bank\") + \"_\" + extras.getString(\"account\"),\n                        true);\n        if (account == null) {\n            redirectToMain(getString(R.string.error_account_not_found));\n            return;\n        }\n        TextView viewBankName = (TextView) findViewById(R.id.txtListitemAccountsGroupAccountname);\n        TextView viewAccountName = (TextView) findViewById(R.id.txtListitemAccountsGroupBankname);\n        TextView viewAccountBalance = (TextView) findViewById(R.id.txtListitemAccountsGroupTotal);\n\n        ImageView icon = (ImageView) findViewById(R.id.imgListitemAccountsGroup);\n        viewBankName.setText(bank.getDisplayName());\n        viewAccountName.setText(account.getName());\n        viewAccountBalance\n                .setText(Helpers.formatBalance(account.getBalance(), account.getCurrency()));\n        icon.setImageResource(bank.getImageResource());\n        List<Transaction> transactions = account.getTransactions();\n\n        if (bank.isDisabled()) {\n            findViewById(R.id.txtDisabledWarning).setVisibility(View.VISIBLE);\n        }\n\n        if (!transactions.isEmpty()) {\n            Collections.sort(transactions);\n            findViewById(R.id.txtTranDesc).setVisibility(View.GONE);\n            TransactionsAdapter adapter = new TransactionsAdapter(transactions);\n            ListView viewTransactionsList = (ListView) findViewById(R.id.lstTransactionsList);\n            viewTransactionsList.setAdapter(adapter);\n        }\n        findViewById(R.id.layBankHeader).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                finish();\n            }\n        });\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n    }\n\n    private void redirectToMain(String errorMessage) {\n        final Intent intent = new Intent(this, MainActivity.class);\n        ((BankdroidApplication) getApplicationContext())\n                .setApplicationMessage(errorMessage);\n        startActivity(intent);\n    }\n\n    private class TransactionsAdapter extends BaseAdapter {\n\n        private LayoutInflater inflater;\n\n        private ArrayList<Object> items = new ArrayList<>();\n\n        public TransactionsAdapter(List<Transaction> transactions) {\n            inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n            if (!transactions.isEmpty()) {\n                String date = transactions.get(0).getDate();\n                items.add(date);\n                for (Transaction transaction : transactions) {\n                    if (!date.equals(transaction.getDate())) {\n                        date = transaction.getDate();\n                        items.add(date);\n                    }\n                    items.add(transaction);\n                }\n\n            }\n        }\n\n        public View newTransactionView(Transaction transaction, ViewGroup parent,\n                View convertView) {\n            if (convertView == null) {\n                convertView = inflater.inflate(R.layout.transaction_item, parent, false);\n            }\n            ((TextView) convertView.findViewById(R.id.txtTransaction))\n                    .setText(transaction.getTransaction());\n            ((TextView) convertView.findViewById(R.id.txtAmount)).setText(\n                    Helpers.formatBalance(transaction.getAmount(), transaction.getCurrency()));\n            if (transaction.getAmount().signum() == 1) {\n                convertView.findViewById(R.id.imgColor)\n                        .setBackgroundResource(R.drawable.transaction_positive);\n            } else {\n                convertView.findViewById(R.id.imgColor)\n                        .setBackgroundResource(R.drawable.transaction_negative);\n            }\n            return convertView;\n        }\n\n        public View newDateView(String date, ViewGroup parent, View convertView) {\n            if (convertView == null) {\n                convertView = inflater.inflate(R.layout.transaction_date, parent, false);\n            }\n            ((TextView) convertView.findViewById(R.id.txtDate)).setText(date);\n            return convertView;\n        }\n\n        @Override\n        public int getCount() {\n            return items.size();\n        }\n\n        @Override\n        public Object getItem(int position) {\n            return items.get(position);\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        @Nullable\n        public View getView(int position, View convertView, ViewGroup parent) {\n            Object item = getItem(position);\n            if (item == null) {\n                return null;\n            }\n            if (item instanceof Transaction) {\n                return newTransactionView((Transaction) item, parent, convertView);\n            } else if (item instanceof String) {\n                return newDateView((String) item, parent, convertView);\n            }\n            return null;\n        }\n\n        @Override\n        public boolean areAllItemsEnabled() {\n            return true;\n        }\n\n        @Override\n        public boolean isEnabled(int position) {\n            return true;\n        }\n\n        @Override\n        public int getViewTypeCount() {\n            return 2;\n        }\n\n        @Override\n        public int getItemViewType(int position) {\n            Object item = getItem(position);\n            if (item instanceof Transaction) {\n                return 0;\n            }\n            return 1;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/WebViewActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Bank.SessionPackage;\nimport com.liato.bankdroid.banking.BankFactory;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.cookie.Cookie;\n\nimport android.content.res.Resources.NotFoundException;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.webkit.CookieManager;\nimport android.webkit.CookieSyncManager;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport java.io.IOException;\n\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\nimport static android.graphics.Color.WHITE;\n\npublic class WebViewActivity extends LockableActivity implements OnClickListener {\n\n    private WebView mWebView;\n\n    private boolean mFirstPageLoaded = false;\n\n    private Handler mMainThreadhandler = new Handler(Looper.getMainLooper());\n\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.webview);\n        //TODO\n//        this.addTitleButton(R.drawable.title_icon_back, \"back\", this);\n//        this.addTitleButton(R.drawable.title_icon_forward, \"forward\", this);\n//        this.addTitleButton(R.drawable.title_icon_refresh, \"refresh\", this);\n//        this.setTitleButtonEnabled(\"forward\", false);\n//        this.setTitleButtonEnabled(\"back\", false);\n//        this.setTitleButtonEnabled(\"refresh\", false);\n\n        final CookieSyncManager csm = CookieSyncManager.createInstance(this);\n        mWebView = (WebView) findViewById(R.id.wvBank);\n        mWebView.setBackgroundColor(0);\n        mWebView.getSettings().setJavaScriptEnabled(true);\n        mWebView.getSettings().setBuiltInZoomControls(true);\n        mWebView.getSettings().setUserAgentString(Urllib.DEFAULT_USER_AGENT);\n        mWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);\n\n        mWebView.setWebChromeClient(new WebChromeClient() {\n            public void onProgressChanged(WebView view, int progress) {\n//                activity.setProgressBar(progress);\n                if (progress == 100) {\n                    Handler handler = new Handler();\n                    Runnable runnable = new Runnable() {\n                        public void run() {\n//                            activity.hideProgressBar();\n                            if (mFirstPageLoaded) {\n                                mWebView.setBackgroundColor(WHITE);\n                            }\n                        }\n                    };\n                    // Let the progress bar hit 100% before we hide it.\n                    handler.postDelayed(runnable, 100);\n\n                } else if (mFirstPageLoaded) {\n//                    activity.showProgressBar();\n                }\n            }\n        });\n        mWebView.setWebViewClient(new BankWebViewClient());\n        String preloader = \"Error...\";\n        try {\n            preloader = IOUtils.toString(getResources().openRawResource(R.raw.loading));\n            preloader = String.format(preloader,\n                    \"\", // Javascript function\n                    \"\" // HTML\n            );\n        } catch (NotFoundException | IOException e) {\n            Timber.w(e, \"Error loading loading.html\");\n        }\n        mWebView.loadDataWithBaseURL(\"what://is/this/i/dont/even\", preloader, \"text/html\", \"utf-8\",\n                null);\n        Bundle extras = getIntent().getExtras();\n        final long bankId = extras.getLong(\"bankid\", -1);\n        //final long bankId = -1;\n        if (bankId >= 0) {\n            Runnable generateLoginPage = new Runnable() {\n                public void run() {\n                    Bank bank = BankFactory.bankFromDb(bankId, WebViewActivity.this, false);\n                    final SessionPackage loginPackage = bank\n                            .getSessionPackage(WebViewActivity.this);\n                    final CookieStore cookieStore = loginPackage.getCookiestore();\n                    mMainThreadhandler.post(new Runnable() {\n                        @Override\n                        public void run() {\n                            if ((cookieStore != null) && !cookieStore.getCookies().isEmpty()) {\n                                CookieManager cookieManager = CookieManager.getInstance();\n                                CookieManager.getInstance().removeSessionCookie();\n                                String cookieString;\n                                for (Cookie cookie : cookieStore.getCookies()) {\n                                    cookieString = String.format(\"%s=%s;%spath=%s; domain=%s;\",\n                                            cookie.getName(), cookie.getValue(),\n                                            cookie.getExpiryDate() == null ? \"\"\n                                                    : \"expires=\" + cookie.getExpiryDate() + \"; \",\n                                            cookie.getPath() == null ? \"/\" : cookie.getPath(),\n                                            cookie.getDomain());\n                                    cookieManager.setCookie(cookie.getDomain(), cookieString);\n                                }\n                                csm.sync();\n                            }\n                            mWebView.loadDataWithBaseURL(\"what://is/this/i/dont/even\",\n                                    loginPackage.getHtml(), \"text/html\", \"utf-8\", null);\n                        }\n                    });\n                }\n            };\n            new Thread(generateLoginPage).start();\n        }\n    }\n\n    public void onResume() {\n        super.onResume();\n    }\n\n    //Handle the back key\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (mWebView != null) {\n            if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {\n                mWebView.goBack();\n                return true;\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public void onClick(View v) {\n        String tag = (String) v.getTag();\n        if (\"refresh\".equals(tag)) {\n            mWebView.reload();\n        } else if (\"back\".equals(tag)) {\n            mWebView.goBack();\n        } else if (\"forward\".equals(tag)) {\n            mWebView.goForward();\n        }\n    }\n\n    // Make sure clicked links are loaded in our webview.\n    private class BankWebViewClient extends WebViewClient {\n\n        @Override\n        public void onLoadResource(WebView view, String url) {\n            super.onLoadResource(view, url);\n            if (mFirstPageLoaded) {\n                handleHistoryChange();\n            }\n        }\n\n\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            super.onPageFinished(view, url);\n            if (!mFirstPageLoaded) {\n                //This is the generated POST page.\n                if (url.startsWith(\"what:\")) {\n                    return;\n                }\n\n                //This is the first real page.\n                //Remove the generated page from history.\n                mWebView.clearHistory();\n                mFirstPageLoaded = true;\n//                activity.setTitleButtonEnabled(\"refresh\", true);\n                return;\n            }\n        }\n\n\n        @Override\n        public void onFormResubmission(WebView view, Message dontResend,\n                Message resend) {\n            // TODO Auto-generated method stub\n            //super.onFormResubmission(view, dontResend, resend);\n            resend.sendToTarget();\n        }\n\n        @Override\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            view.loadUrl(url);\n            return true;\n        }\n\n        public void handleHistoryChange() {\n//            activity.setTitleButtonEnabled(\"back\", mWebView.canGoBack());\n//            activity.setTitleButtonEnabled(\"forward\", mWebView.canGoForward());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/adapters/AccountsAdapter.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.adapters;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.graphics.Color;\nimport android.preference.PreferenceManager;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\n\npublic class AccountsAdapter extends BaseAdapter {\n\n    public final static int VIEWTYPE_BANK = 0;\n\n    public final static int VIEWTYPE_ACCOUNT = 1;\n\n    public final static int VIEWTYPE_EMPTY = 2;\n\n    private final SharedPreferences prefs;\n\n    private ArrayList<Bank> banks;\n\n    private final LayoutInflater inflater;\n\n    private boolean showHidden;\n\n    public AccountsAdapter(Context context, boolean showHidden) {\n        this.banks = new ArrayList<>();\n        inflater = LayoutInflater.from(context);\n        this.showHidden = showHidden;\n        prefs = PreferenceManager.getDefaultSharedPreferences(context);\n    }\n\n    public void setGroups(ArrayList<Bank> banks) {\n        this.banks = banks;\n    }\n\n    public void setShowHidden(boolean showHidden) {\n        this.showHidden = showHidden;\n    }\n\n    private View newBankView(Bank bank, ViewGroup parent, View convertView) {\n        if (convertView == null) {\n            convertView = inflater.inflate(R.layout.listitem_accounts_group, parent, false);\n        }\n\n        ImageView icon = (ImageView) convertView.findViewById(R.id.imgListitemAccountsGroup);\n        ((TextView) convertView.findViewById(R.id.txtListitemAccountsGroupAccountname))\n                .setText(bank.getDisplayName());\n        ((TextView) convertView.findViewById(R.id.txtListitemAccountsGroupBankname))\n                .setText(bank.getName());\n        ((TextView) convertView\n                .findViewById(R.id.txtListitemAccountsGroupTotal))\n                .setText(Helpers.formatBalance(bank.getBalance(),\n                        bank.getCurrency(),\n                        prefs.getBoolean(\"round_balance\", false) || !bank.getDisplayDecimals(),\n                        bank.getDecimalFormatter(),\n                        false));\n        icon.setImageResource(bank.getImageResource());\n        View warning = convertView.findViewById(R.id.txtDisabledWarningX);\n        if (bank.isDisabled()) {\n            warning.setVisibility(View.VISIBLE);\n        } else {\n            warning.setVisibility(View.GONE);\n        }\n        return convertView;\n    }\n\n    private View newAccountView(Account account, ViewGroup parent, View convertView) {\n        if ((account.isHidden() && !showHidden) || account.getBank().getHideAccounts()) {\n            return convertView == null ? inflater.inflate(R.layout.empty, parent, false)\n                    : convertView;\n        }\n        if (convertView == null) {\n            convertView = inflater.inflate(R.layout.listitem_accounts_item, parent, false);\n        }\n        convertView.findViewById(R.id.divider).setBackgroundColor(Color.argb(30, 255, 255, 255));\n        TextView txtAccountName = ((TextView) convertView\n                .findViewById(R.id.txtListitemAccountsItemAccountname));\n        TextView txtBalance = ((TextView) convertView\n                .findViewById(R.id.txtListitemAccountsItemBalance));\n        txtAccountName.setText(account.getName());\n        txtBalance.setText(Helpers.formatBalance(account.getBalance(), account.getCurrency()));\n        txtBalance\n                .setText(Helpers.formatBalance(account.getBalance(),\n                        account.getCurrency(),\n                        prefs.getBoolean(\"round_balance\", false) || !account.getBank()\n                                .getDisplayDecimals(),\n                        account.getBank().getDecimalFormatter(),\n                        false));\n        if (account.isHidden()) {\n            txtAccountName.setTextColor(Color.argb(255, 191, 191, 191));\n            txtBalance.setTextColor(Color.argb(255, 191, 191, 191));\n        } else {\n            txtAccountName.setTextColor(Color.WHITE);\n            txtBalance.setTextColor(Color.WHITE);\n        }\n        return convertView;\n    }\n\n    @Override\n    public int getCount() {\n        int c = 0;\n        for (Bank g : banks) {\n            if (g.getHideAccounts()) {\n                c++;\n            } else {\n                c += g.getAccounts().size() + 1;\n            }\n        }\n        return c;\n    }\n\n    @Override\n    @Nullable\n    public Object getItem(int position) {\n        if (banks.size() == 0) {\n            return null;\n        }\n        if (position == 0) {\n            return banks.get(0);\n        }\n\n        int i = 0;\n        for (Bank g : banks) {\n            if (position == i) {\n                return g;\n            } else if (g.getHideAccounts()) {\n                i++;\n                continue;\n            } else if (position <= (g.getAccounts().size() + i)) {\n                return g.getAccounts().get(position - i - 1);\n            }\n            i += g.getAccounts().size() + 1;\n        }\n\n        return (null);\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return position;\n    }\n\n    @Override\n    @Nullable\n    public View getView(int position, View convertView, ViewGroup parent) {\n        Object item = getItem(position);\n        if (item == null) {\n            return null;\n        }\n        if (item instanceof Bank) {\n            return newBankView((Bank)item, parent, convertView);\n        } else if (item instanceof Account) {\n            return newAccountView((Account)item, parent, convertView);\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isEnabled(int position) {\n        if (getItemViewType(position) == VIEWTYPE_EMPTY) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int getViewTypeCount() {\n        return 3;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        Object item = getItem(position);\n        if (item instanceof Bank) {\n            return VIEWTYPE_BANK;\n        } else {\n            final Account account = (Account)item;\n            if ((account.isHidden() && !showHidden) ||\n                    account.getBank().getHideAccounts()) {\n                return VIEWTYPE_EMPTY;\n            }\n        }\n        return VIEWTYPE_ACCOUNT;\n    }\n}\n\n\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/appwidget/AutoRefreshService.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.appwidget;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.MainActivity;\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.liveview.LiveViewService;\nimport com.liato.bankdroid.utils.LoggingUtils;\n\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.PendingIntent.CanceledException;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.content.res.Resources;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.IBinder;\nimport android.os.SystemClock;\nimport android.preference.PreferenceManager;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.NotificationCompat;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport timber.log.Timber;\n\npublic class AutoRefreshService extends Service {\n\n    public final static String BROADCAST_WIDGET_REFRESH = \"com.liato.bankdroid.WIDGET_REFRESH\";\n\n    public final static String BROADCAST_MAIN_REFRESH = \"com.liato.bankdroid.MAIN_REFRESH\";\n\n    public final static String BROADCAST_REMOTE_NOTIFIER\n            = \"org.damazio.notifier.service.UserReceiver.USER_MESSAGE\";\n\n    public final static String BROADCAST_OPENWATCH_TEXT = \"com.smartmadsoft.openwatch.action.TEXT\";\n\n    public final static String BROADCAST_OPENWATCH_VIBRATE\n            = \"com.smartmadsoft.openwatch.action.VIBRATE\";\n\n    public final static String ACTION_MAIN_SHOW_TRANSACTIONS\n            = \"com.liato.bankdroid.action.MAIN_SHOW_TRANSACTIONS\";\n\n    public final static String BROADCAST_TRANSACTIONS_UPDATED\n            = \"com.liato.bankdroid.action.TRANSACTIONS\";\n\n    public static void showNotification(final Bank bank, final Account account,\n            final BigDecimal diff, Context context) {\n\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(context);\n        if (!prefs.getBoolean(\"notify_on_change\", true)) {\n            return;\n        }\n\n        String text = String.format(\"%s: %s%s\", account.getName(),\n                ((diff.compareTo(new BigDecimal(0)) == 1) ? \"+\" : \"\"),\n                Helpers.formatBalance(diff, account.getCurrency()));\n        if (!prefs.getBoolean(\"notify_delta_only\", false)) {\n            text = String.format(\"%s (%s)\", text,\n                    Helpers.formatBalance(account.getBalance(), account.getCurrency()));\n        }\n\n        final NotificationManager notificationManager = (NotificationManager) context\n                .getSystemService(NOTIFICATION_SERVICE);\n        final NotificationCompat.Builder notification = new NotificationCompat.Builder(context)\n                .setSmallIcon(bank.getImageResource())\n                .setContentTitle(bank.getDisplayName())\n                .setContentText(text);\n\n        // Remove notification from statusbar when clicked\n        notification.setAutoCancel(true);\n\n        // http://www.freesound.org/samplesViewSingle.php?id=75235\n        // http://www.freesound.org/samplesViewSingle.php?id=91924\n        if (prefs.getString(\"notification_sound\", null) != null) {\n            notification.setSound(Uri.parse(prefs.getString(\n                    \"notification_sound\", null)));\n        }\n        if (prefs.getBoolean(\"notify_with_vibration\", true)) {\n            final long[] vib = {0, 90, 130, 80, 350, 190, 20, 380};\n            notification.setVibrate(vib);\n        }\n\n        if (prefs.getBoolean(\"notify_with_led\", true)) {\n            notification.setLights(prefs.getInt(\"notify_with_led_color\",\n                    context.getResources().getColor(R.color.default_led_color)), 700, 200);\n        }\n\n        final PendingIntent contentIntent = PendingIntent.getActivity(context, 0,\n                new Intent(context, MainActivity.class), 0);\n        notification.setContentIntent(contentIntent);\n\n        String numNotifications = prefs.getString(\"num_notifications\", \"total\");\n        int notificationId = (int) (numNotifications.equals(\"total\") ? 0\n                : numNotifications.equals(\"bank\") ? bank.getDbId()\n                        : numNotifications.equals(\"account\") ? account.getId().hashCode()\n                                : SystemClock.elapsedRealtime());\n        notificationManager.notify(notificationId, notification.build());\n\n        // Broadcast to Remote Notifier if enabled\n        // http://code.google.com/p/android-notifier/\n        if (prefs.getBoolean(\"notify_remotenotifier\", false)) {\n            final Intent i = new Intent(BROADCAST_REMOTE_NOTIFIER);\n            i.putExtra(\"title\", String.format(\"%s (%s)\", bank.getName(), bank.getDisplayName()));\n            i.putExtra(\"description\", text);\n            context.sendBroadcast(i);\n        }\n\n        // Broadcast to OpenWatch if enabled\n        // http://forum.xda-developers.com/showthread.php?t=554551\n        if (prefs.getBoolean(\"notify_openwatch\", false)) {\n            Intent i;\n            if (prefs.getBoolean(\"notify_openwatch_vibrate\", false)) {\n                i = new Intent(BROADCAST_OPENWATCH_VIBRATE);\n            } else {\n                i = new Intent(BROADCAST_OPENWATCH_TEXT);\n            }\n            i.putExtra(\"line1\", String.format(\"%s (%s)\", bank.getName(), bank.getDisplayName()));\n            i.putExtra(\"line2\", text);\n            context.sendBroadcast(i);\n        }\n\n        // Broadcast to LiveView if enabled\n        // http://www.sonyericsson.com/cws/products/accessories/overview/liveviewmicrodisplay\n        if (prefs.getBoolean(\"notify_liveview\", false)) {\n            final Intent i = new Intent(context, LiveViewService.class);\n            i.putExtra(LiveViewService.INTENT_EXTRA_ANNOUNCE, true);\n            i.putExtra(LiveViewService.INTENT_EXTRA_TITLE,\n                    String.format(\"%s (%s)\", bank.getName(), bank.getDisplayName()));\n            i.putExtra(LiveViewService.INTENT_EXTRA_TEXT, text);\n            context.startService(i);\n        }\n\n    }\n\n    public static void broadcastTransactionUpdate(final Context context,\n            final long bankId, final String accountId) {\n        final Intent i = new Intent(BROADCAST_TRANSACTIONS_UPDATED);\n        i.putExtra(\"accountId\", Long.toString(bankId) + \"_\" + accountId);\n        context.sendBroadcast(i);\n    }\n\n    public static void sendWidgetRefresh(final Context context) {\n        // Send intent to BankdroidWidgetProvider\n        final Intent updateIntent = new Intent(BROADCAST_WIDGET_REFRESH);\n        final PendingIntent pendingIntent = PendingIntent.getBroadcast(context,\n                0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n        try {\n            pendingIntent.send();\n        } catch (final CanceledException e) {\n            Timber.w(e, \"Problem occurred while updating widget\");\n        }\n    }\n\n    @Override\n    public void onStart(Intent intent, int startId) {\n        super.onStart(intent, startId);\n        handleStart();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        handleStart();\n        return START_NOT_STICKY;\n    }\n\n    private void handleStart() {\n        ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);\n        NetworkInfo ni = cm.getActiveNetworkInfo();\n        if (ni != null &&\n                ni.isConnected() &&\n                shouldUpdateOnRoaming(ni)) {\n            if (InsideUpdatePeriod()) {\n                new DataRetrieverTask(this).execute();\n            } else {\n                Timber.v(\"Skipping update due to not in update period.\");\n                stopSelf();\n            }\n        }\n    }\n\n    private boolean shouldUpdateOnRoaming(NetworkInfo ni) {\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(this);\n        if (prefs.getBoolean(\"disable_during_roaming\", false) && ni.isRoaming()) {\n            return false;\n        }\n        return true;\n    }\n\n    private boolean InsideUpdatePeriod() {\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(this);\n\n        int start = prefs.getInt(\"refresh_start_minutes\", 0);\n        int stop = prefs.getInt(\"refresh_stop_minutes\", 0);\n\n        // If start is bigger than stop we always update. It should perhaps\n        // be possible to set start to 17:00 and stop to 07:00 and have to\n        // updates working from 17 to 07 around midnight\n        if (start >= stop) {\n            return true;\n        }\n\n        Date now = new Date();\n        int minutesSinceMidnight = now.getHours() * 60 + now.getMinutes();\n        return minutesSinceMidnight > start && minutesSinceMidnight < stop;\n    }\n\n    @Override\n    public void onDestroy() {\n    }\n\n    @Override\n    public IBinder onBind(final Intent intent) {\n        return null;\n    }\n\n    static class DataRetrieverTask extends AsyncTask<String, String, Void> {\n\n        private final SharedPreferences prefs;\n\n        private ArrayList<String> errors;\n        protected final AutoRefreshService autoRefreshService;\n\n        private Resources res;\n\n        // This constructor is for unit testing only\n        protected DataRetrieverTask(AutoRefreshService autoRefreshService, SharedPreferences prefs) {\n            this.autoRefreshService = autoRefreshService;\n            this.prefs = prefs;\n        }\n\n        public DataRetrieverTask(AutoRefreshService autoRefreshService) {\n            this(autoRefreshService,\n                    PreferenceManager.getDefaultSharedPreferences(autoRefreshService));\n        }\n\n        @Override\n        protected void onPreExecute() {\n        }\n\n        protected List<Bank> getBanks() {\n            return BankFactory.banksFromDb(autoRefreshService, true);\n        }\n\n        @NonNull\n        protected DBAdapter getDBAdapter() {\n            return new DBAdapter(autoRefreshService);\n        }\n\n        protected void sendWidgetRefresh() {\n            final Intent updateIntent = new Intent(BROADCAST_MAIN_REFRESH);\n            autoRefreshService.sendBroadcast(updateIntent);\n            AutoRefreshService.sendWidgetRefresh(autoRefreshService);\n        }\n\n        @Override\n        protected Void doInBackground(final String... args) {\n            errors = new ArrayList<>();\n            Boolean refreshWidgets = false;\n            final List<Bank> banks = getBanks();\n            if (banks.isEmpty()) {\n                return null;\n            }\n            final DBAdapter db = getDBAdapter();\n            BigDecimal currentBalance;\n            BigDecimal diff;\n            BigDecimal minDelta = new BigDecimal(prefs.getString(\"notify_min_delta\", \"0\"));\n\n            final HashMap<String, Account> accounts = new HashMap<>();\n\n            for (final Bank bank : banks) {\n                if (prefs.getBoolean(\"debug_mode\", false)\n                        && prefs.getBoolean(\"debug_only_testbank\", false)) {\n                    Timber.d(\n                            \"Only_Testbank is ON. Skipping update for %s\",\n                            bank.getName());\n                    continue;\n                }\n                if (bank.isDisabled()) {\n                    LoggingUtils.logDisabledBank(bank);\n                    continue;\n                }\n                try {\n                    currentBalance = bank.getBalance();\n                    accounts.clear();\n                    for (final Account account : bank.getAccounts()) {\n                        accounts.put(account.getId(), account);\n                    }\n                    bank.update();\n\n                    diff = currentBalance.subtract(bank.getBalance());\n\n                    if (diff.compareTo(BigDecimal.ZERO) != 0) {\n                        refreshWidgets = true;\n                    }\n\n                    if (diff.compareTo(new BigDecimal(0)) != 0\n                            && diff.abs().compareTo(minDelta) != -1) {\n                        Account oldAccount;\n                        for (final Account account : bank.getAccounts()) {\n                            oldAccount = accounts.get(account.getId());\n                            if (oldAccount != null) {\n                                if (account.getBalance().compareTo(\n                                        oldAccount.getBalance()) != 0) {\n                                    boolean notify = false;\n                                    switch (account.getType()) {\n                                        case Account.REGULAR:\n                                            notify = prefs.getBoolean(\n                                                    \"notify_for_deposit\", true);\n                                            break;\n                                        case Account.FUNDS:\n                                            notify = prefs.getBoolean(\n                                                    \"notify_for_funds\", false);\n                                            break;\n                                        case Account.LOANS:\n                                            notify = prefs.getBoolean(\n                                                    \"notify_for_loans\", false);\n                                            break;\n                                        case Account.CCARD:\n                                            notify = prefs.getBoolean(\n                                                    \"notify_for_ccards\", true);\n                                            break;\n                                        case Account.OTHER:\n                                            notify = prefs.getBoolean(\n                                                    \"notify_for_other\", false);\n                                            break;\n                                    }\n                                    if (account.isHidden()\n                                            || !account.isNotify()) {\n                                        notify = false;\n                                    }\n                                    if (notify) {\n                                        diff = account.getBalance().subtract(\n                                                oldAccount.getBalance());\n                                        showNotification(bank, account, diff,\n                                                autoRefreshService);\n                                    }\n                                }\n                            }\n                        }\n                        if (prefs.getBoolean(\n                                \"autoupdates_transactions_enabled\", true)) {\n                            bank.updateAllTransactions();\n                            LoggingUtils.logBankUpdate(bank, true);\n                        } else {\n                            LoggingUtils.logBankUpdate(bank, false);\n                        }\n                    }\n                    bank.closeConnection();\n                    db.updateBank(bank);\n\n                    // Send update for all accounts since we're overwriting the\n                    // database transaction history\n                    if (prefs.getBoolean(\"content_provider_enabled\", false)) {\n                        for (final Account account : bank.getAccounts()) {\n                            broadcastTransactionUpdate(autoRefreshService.getBaseContext(),\n                                    bank.getDbId(), account.getId());\n                        }\n                    }\n                } catch (final BankException e) {\n                    // Refresh widgets if an update fails\n                    Timber.e(e, \"Could not update bank %s\", bank.getName());\n                } catch (final LoginException e) {\n                    Timber.d(e, \"Invalid credentials for bank %s\", bank.getName());\n                    refreshWidgets = true;\n                    db.disableBank(bank.getDbId());\n                } catch (BankChoiceException e) {\n                    Timber.w(e, \"BankChoiceException\");\n                } catch (Exception e) {\n                    Timber.e(e, \"An unexpected error occurred while updating bank %s\", bank.getName());\n                }\n            }\n\n            if (refreshWidgets) {\n                sendWidgetRefresh();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onProgressUpdate(final String... args) {\n        }\n\n        @Override\n        protected void onPostExecute(final Void unused) {\n            if ((this.errors != null) && !this.errors.isEmpty()) {\n                final StringBuilder errormsg = new StringBuilder();\n                errormsg.append(res.getText(R.string.accounts_were_not_updated)\n                        + \":\\n\");\n                for (final String err : errors) {\n                    errormsg.append(err);\n                    errormsg.append(\"\\n\");\n                }\n            }\n            Editor edit = prefs.edit();\n            edit.putLong(\"autoupdates_last_update\", System.currentTimeMillis());\n            edit.apply();\n            autoRefreshService.stopSelf();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/appwidget/BankdroidWidgetProvider.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.appwidget;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.MainActivity;\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.utils.NetworkUtils;\n\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.appwidget.AppWidgetProviderInfo;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.preference.PreferenceManager;\nimport android.view.View;\nimport android.widget.RemoteViews;\n\nimport java.io.IOException;\n\nimport timber.log.Timber;\n\npublic abstract class BankdroidWidgetProvider extends AppWidgetProvider {\n\n    private final static String TAG = \"BankdroidWidgetProvider\";\n\n    private final static String ACTION_WIDGET_BLUR = \"com.liato.bankdroid.action.WIDGET_BLUR\";\n\n    private final static String ACTION_WIDGET_UNBLUR = \"com.liato.bankdroid.action.WIDGET_UNBLUR\";\n\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId, Account account) {\n        RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId, account);\n        if (views != null) {\n            appWidgetManager.updateAppWidget(appWidgetId, views);\n        }\n    }\n\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId) {\n        RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId);\n        if (views != null) {\n            appWidgetManager.updateAppWidget(appWidgetId, views);\n        }\n    }\n\n    static void unblurAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId) {\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        Editor e = prefs.edit();\n        e.putBoolean(\"widget_unblurred_\" + appWidgetId, true);\n        e.apply();\n\n        RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId);\n        if (views != null) {\n            views.setViewVisibility(R.id.imgBalanceblur, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountnameBlur, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountbalance, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountname, View.VISIBLE);\n            appWidgetManager.updateAppWidget(appWidgetId, views);\n        }\n    }\n\n    static void blurAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId) {\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        Editor e = prefs.edit();\n        e.remove(\"widget_unblurred_\" + appWidgetId);\n        e.apply();\n        RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId);\n        if (views != null) {\n            views.setViewVisibility(R.id.imgBalanceblur, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountnameBlur, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountbalance, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountname, View.GONE);\n            appWidgetManager.updateAppWidget(appWidgetId, views);\n        }\n    }\n\n\n    static RemoteViews buildAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId) {\n        String accountId = WidgetConfigureActivity.getAccountId(context, appWidgetId);\n        long bankId = WidgetConfigureActivity.getBankId(context, appWidgetId);\n        if (accountId == null) {\n            Timber.w(\"Widget not found. ID: %s\", appWidgetId);\n            return disableAppWidget(context, appWidgetManager,\n                    appWidgetId);\n        }\n        Account account = BankFactory.accountFromDb(context, bankId + \"_\" + accountId, false);\n        if (account == null) {\n            Timber.w(\"Account not found in database\");\n            return disableAppWidget(context, appWidgetManager,\n                    appWidgetId);\n\n        }\n\n        Bank bank = BankFactory.bankFromDb(account.getBankDbId(), context, false);\n        if (bank == null) {\n            Timber.w(\"Bank not found in database\");\n            return disableAppWidget(context, appWidgetManager,\n                    appWidgetId);\n        }\n\n        account.setBank(bank);\n        return buildAppWidget(context, appWidgetManager,\n                appWidgetId, account);\n    }\n\n\n    static RemoteViews buildAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId, Account account) {\n        AppWidgetProviderInfo providerInfo = appWidgetManager.getAppWidgetInfo(appWidgetId);\n        int layoutId = (providerInfo == null) ? R.layout.widget : providerInfo.initialLayout;\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        SharedPreferences defprefs = PreferenceManager.getDefaultSharedPreferences(context);\n        if (prefs.getBoolean(\"transperant_background\" + appWidgetId, false) && (providerInfo\n                != null)) {\n            if (providerInfo.initialLayout == R.layout.widget_large) {\n                layoutId = R.layout.widget_large_transparent;\n            } else {\n                layoutId = R.layout.widget_transparent;\n            }\n        }\n        Bank bank = account.getBank();\n        RemoteViews views = new RemoteViews(context.getPackageName(), layoutId);\n        views.setTextViewText(R.id.txtWidgetAccountname, account.getName().toUpperCase());\n        views.setTextViewText(R.id.txtWidgetAccountnameBlur, account.getName().toUpperCase());\n        views.setTextViewText(R.id.txtWidgetAccountbalance,\n                Helpers.formatBalance(account.getBalance(), account.getCurrency(),\n                        defprefs.getBoolean(\"round_widget_balance\", false),\n                        bank.getDecimalFormatter(),\n                        bank.isDisabled()));\n        views.setImageViewResource(R.id.imgWidgetIcon, bank.getImageResource());\n        Intent intent = new Intent(context, MainActivity.class);\n        PendingIntent pendingIntent;\n\n        //intent = new Intent(context, AccountsActivity.class);\n        pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);\n        views.setOnClickPendingIntent(R.id.layWidgetContainer, pendingIntent);\n\n        intent = new Intent(context, WidgetService.class);\n        intent.setAction(AutoRefreshService.BROADCAST_WIDGET_REFRESH);\n        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);\n        intent.setData(\n                Uri.parse(\"rofl://copter/\" + appWidgetId + \"/\" + System.currentTimeMillis()));\n        pendingIntent = PendingIntent\n                .getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);\n        views.setOnClickPendingIntent(R.id.imgWidgetIcon, pendingIntent);\n        views.setOnClickPendingIntent(R.id.hitBox, pendingIntent);\n\n        intent = new Intent(context, WidgetService.class);\n        intent.setAction(BankdroidWidgetProvider.ACTION_WIDGET_UNBLUR);\n        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);\n        intent.setData(Uri.parse(\n                \"rofl://copter/widgetunblur/\" + appWidgetId + \"/\" + System.currentTimeMillis()));\n        pendingIntent = PendingIntent\n                .getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);\n        views.setOnClickPendingIntent(R.id.imgBalanceblur, pendingIntent);\n\n        if (defprefs.getBoolean(\"widget_blur_balance\", false) && !prefs\n                .getBoolean(\"widget_unblurred_\" + appWidgetId, false)) {\n            views.setViewVisibility(R.id.imgBalanceblur, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountnameBlur, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountbalance, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountname, View.GONE);\n            views.setOnClickPendingIntent(R.id.layWidgetContainer, pendingIntent);\n        } else {\n            views.setViewVisibility(R.id.imgBalanceblur, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountnameBlur, View.GONE);\n            views.setViewVisibility(R.id.txtWidgetAccountbalance, View.VISIBLE);\n            views.setViewVisibility(R.id.txtWidgetAccountname, View.VISIBLE);\n\n            intent = new Intent(context, MainActivity.class);\n            intent.setAction(AutoRefreshService.ACTION_MAIN_SHOW_TRANSACTIONS);\n            intent.setData(Uri.parse(\"rofl://copter/showtransactions/\" + appWidgetId + \"/\" + System\n                    .currentTimeMillis()));\n            intent.putExtra(\"bank\", bank.getDbId());\n            intent.putExtra(\"account\", account.getId());\n            pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);\n            views.setOnClickPendingIntent(R.id.txtWidgetAccountbalance, pendingIntent);\n            views.setOnClickPendingIntent(R.id.layWidgetContainer, pendingIntent);\n        }\n\n        return views;\n    }\n\n\n    static RemoteViews disableAppWidget(Context context, AppWidgetManager appWidgetManager,\n            int appWidgetId) {\n        AppWidgetProviderInfo providerInfo = appWidgetManager.getAppWidgetInfo(appWidgetId);\n        int layoutId = (providerInfo == null) ? R.layout.widget : providerInfo.initialLayout;\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        if (prefs.getBoolean(\"transperant_background\" + appWidgetId, false) && (providerInfo\n                != null)) {\n            if (providerInfo.initialLayout == R.layout.widget_large) {\n                layoutId = R.layout.widget_large_transparent;\n            } else {\n                layoutId = R.layout.widget_transparent;\n            }\n        }\n        RemoteViews views = new RemoteViews(context.getPackageName(), layoutId);\n        views.setTextViewText(R.id.txtWidgetAccountname, \"\");\n        views.setTextViewText(R.id.txtWidgetAccountbalance, \"ERROR\");\n        views.setImageViewResource(R.id.imgWidgetIcon, R.drawable.icon_large);\n\n        Intent intent = new Intent(context, MainActivity.class);\n        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);\n        views.setOnClickPendingIntent(R.id.txtWidgetAccountbalance, pendingIntent);\n        views.setOnClickPendingIntent(R.id.layWidgetContainer, pendingIntent);\n\n        return views;\n    }\n\n\n    public void onReceive(Context context, Intent intent) {\n        // v1.5 fix that doesn't call onDelete Action\n        final String action = intent.getAction();\n        if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {\n            final int appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,\n                    AppWidgetManager.INVALID_APPWIDGET_ID);\n            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {\n                this.onDeleted(context, new int[]{appWidgetId});\n            }\n        } else {\n            super.onReceive(context, intent);\n        }\n\n        if (action.equals(AutoRefreshService.BROADCAST_WIDGET_REFRESH) || action\n                .equals(android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {\n            AppWidgetManager appWM = AppWidgetManager.getInstance(context);\n            int[] appWidgetIds = appWM.getAppWidgetIds(intent.getComponent());\n            final int N = appWidgetIds.length;\n            for (int i = 0; i < N; i++) {\n                int appWidgetId = appWidgetIds[i];\n                updateAppWidget(context, appWM, appWidgetId);\n            }\n        }\n    }\n\n    @Override\n    public void onDeleted(Context context, int[] appWidgetIds) {\n        super.onDeleted(context, appWidgetIds);\n        final int N = appWidgetIds.length;\n        for (int i = 0; i < N; i++) {\n            WidgetConfigureActivity.delAccountId(context, appWidgetIds[i]);\n        }\n    }\n\n    public static class WidgetService extends Service {\n\n        @Override\n        public void onStart(Intent intent, int startId) {\n            super.onStart(intent, startId);\n            handleStart(intent, startId);\n        }\n\n        @Override\n        public int onStartCommand(Intent intent, int flags, int startId) {\n            handleStart(intent, startId);\n            return START_NOT_STICKY;\n        }\n\n        public void handleStart(Intent intent, int startId) {\n            if (intent == null) {\n                return;\n            }\n            int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);\n            Context context = getApplicationContext();\n            String action = intent.getAction();\n            if (action == null) {\n                return;\n            }\n            if (action.equals(AutoRefreshService.BROADCAST_WIDGET_REFRESH)) {\n                new WidgetUpdateTask(context, AppWidgetManager.getInstance(context), appWidgetId)\n                        .execute();\n            } else if (action.equals(BankdroidWidgetProvider.ACTION_WIDGET_UNBLUR)) {\n                unblurAppWidget(context, AppWidgetManager.getInstance(context), appWidgetId);\n\n                Handler blurHandler = new Handler();\n                class BlurRunnable implements Runnable {\n\n                    private int mAppWidgetId;\n\n                    public BlurRunnable(int appWidgetId) {\n                        this.mAppWidgetId = appWidgetId;\n                    }\n\n                    @Override\n                    public void run() {\n                        Context context = getApplicationContext();\n                        blurAppWidget(context, AppWidgetManager.getInstance(context), mAppWidgetId);\n                    }\n\n                }\n\n                SharedPreferences defprefs = PreferenceManager.getDefaultSharedPreferences(context);\n                Integer unblurTimeout = 1000 * Integer\n                        .parseInt(defprefs.getString(\"widget_blur_balance_timeout\", \"5\"));\n                blurHandler.postDelayed(new BlurRunnable(appWidgetId), unblurTimeout);\n            } else if (action.equals(BankdroidWidgetProvider.ACTION_WIDGET_BLUR)) {\n                blurAppWidget(context, AppWidgetManager.getInstance(context), appWidgetId);\n            }\n        }\n\n        @Override\n        public IBinder onBind(Intent arg0) {\n            // TODO Auto-generated method stub\n            return null;\n        }\n\n        protected class WidgetUpdateTask extends AsyncTask<Void, Void, Void> {\n\n            private Context context;\n\n            private AppWidgetManager appWidgetManager;\n\n            private int appWidgetId;\n\n            private SharedPreferences prefs;\n\n            public WidgetUpdateTask(Context context, AppWidgetManager appWidgetManager,\n                    int appWidgetId) {\n                this.context = context;\n                this.appWidgetManager = appWidgetManager;\n                this.appWidgetId = appWidgetId;\n                this.prefs = PreferenceManager.getDefaultSharedPreferences(context);\n            }\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId);\n                if (views != null) {\n                    views.setViewVisibility(R.id.frmProgress, View.VISIBLE);\n                    appWidgetManager.updateAppWidget(appWidgetId, views);\n                }\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                String accountId = WidgetConfigureActivity.getAccountId(context, appWidgetId);\n                if (accountId == null) {\n                    Timber.w(\"Widget not found %d\", appWidgetId);\n                    return null;\n                }\n                long bankId = WidgetConfigureActivity.getBankId(context, appWidgetId);\n                Bank bank = BankFactory.bankFromDb(bankId, context, true);\n                if (bank == null) {\n                    return null;\n                }\n\n                try {\n                    if (!bank.isDisabled()) {\n                        bank.update();\n                        if (prefs.getBoolean(\"widget_updates_transactions\", false)) {\n                            bank.updateAllTransactions();\n                        }\n                        bank.closeConnection();\n                        DBAdapter.save(bank, context);\n                    }\n\n                } catch (BankException e) {\n                    Timber.e(e, \"Could not update bank %s\", bank.getName());\n                } catch (LoginException e) {\n                    Timber.w(e, \"Invalid credentials for bank %s\", bank.getName());\n                    DBAdapter.disable(bank, context);\n                } catch (BankChoiceException e) {\n                    Timber.w(e, \"BankChoiceException\");\n                } catch (IOException e) {\n                    if (NetworkUtils.isInternetAvailable()) {\n                        Timber.e(e, \"Could not update bank %s\", bank.getName());\n                    }\n                }\n                BankdroidWidgetProvider.updateAppWidget(context, appWidgetManager, appWidgetId);\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void result) {\n                super.onPostExecute(result);\n                RemoteViews views = buildAppWidget(context, appWidgetManager, appWidgetId);\n                if (views != null) {\n                    views.setViewVisibility(R.id.frmProgress, View.INVISIBLE);\n                    appWidgetManager.updateAppWidget(appWidgetId, views);\n                }\n                WidgetService.this.stopSelf();\n            }\n\n\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/appwidget/BankdroidWidgetProvider_2x1.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.appwidget;\n\n\npublic class BankdroidWidgetProvider_2x1 extends BankdroidWidgetProvider {\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/appwidget/BankdroidWidgetProvider_4x1.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.appwidget;\n\n\npublic class BankdroidWidgetProvider_4x1 extends BankdroidWidgetProvider {\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/appwidget/WidgetConfigureActivity.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.appwidget;\n\nimport com.liato.bankdroid.LockableActivity;\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.adapters.AccountsAdapter;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.BankFactory;\n\nimport android.appwidget.AppWidgetManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.CheckBox;\nimport android.widget.ListView;\n\nimport java.util.ArrayList;\n\npublic class WidgetConfigureActivity extends LockableActivity {\n\n    private static final String WIDGET_PREFIX = \"widget_\";\n\n    int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;\n\n    private AccountsAdapter adapter;\n\n    public WidgetConfigureActivity() {\n        super();\n\n    }\n\n    public static void setAccountBankId(Context context, int appWidgetId, String accountId,\n            long bankId) {\n        SharedPreferences.Editor prefs = context.getSharedPreferences(\"widget_prefs\", 0).edit();\n        prefs.putString(WIDGET_PREFIX + appWidgetId, accountId);\n        prefs.putLong(WIDGET_PREFIX + appWidgetId + \"_bankid\", bankId);\n        prefs.apply();\n    }\n\n    public static String getAccountId(Context context, int appWidgetId) {\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        return prefs.getString(WIDGET_PREFIX + appWidgetId, null);\n    }\n\n    public static long getBankId(Context context, int appWidgetId) {\n        SharedPreferences prefs = context.getSharedPreferences(\"widget_prefs\", 0);\n        return prefs.getLong(WIDGET_PREFIX + appWidgetId + \"_bankid\", -1);\n    }\n\n    public static void delAccountId(Context context, int appWidgetId) {\n        SharedPreferences.Editor prefs = context.getSharedPreferences(\"widget_prefs\", 0).edit();\n        prefs.remove(WIDGET_PREFIX + appWidgetId);\n        prefs.remove(WIDGET_PREFIX + appWidgetId + \"_bankid\");\n        prefs.apply();\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    public void onResume() {\n        super.onResume();\n\n        setContentView(R.layout.main);\n        this.setTitle(this.getString(R.string.choose_an_account));\n        setResult(RESULT_CANCELED);\n        ((View) findViewById(R.id.layMainMenu)).setVisibility(View.GONE);\n\n        Intent intent = getIntent();\n        Bundle extras = intent.getExtras();\n        if (extras != null) {\n            mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,\n                    AppWidgetManager.INVALID_APPWIDGET_ID);\n        }\n        if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {\n            finish();\n        }\n\n        ListView lv = (ListView) findViewById(R.id.lstAccountsList);\n        lv.setOnItemClickListener(new OnItemClickListener() {\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                if (adapter.getItemViewType(position) != AccountsAdapter.VIEWTYPE_ACCOUNT) {\n                    return;\n                }\n                final Context context = WidgetConfigureActivity.this;\n                Account account = (Account) parent.getItemAtPosition(position);\n                Bank bank = account.getBank();\n                WidgetConfigureActivity\n                        .setAccountBankId(context, mAppWidgetId, account.getId(), bank.getDbId());\n                SharedPreferences.Editor prefs = context.getSharedPreferences(\"widget_prefs\", 0)\n                        .edit();\n                prefs.putBoolean(\"transperant_background\" + mAppWidgetId,\n                        ((CheckBox) findViewById(R.id.chkTransperantBackground)).isChecked());\n                prefs.apply();\n                // Push widget update to surface with newly set prefix\n                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);\n                BankdroidWidgetProvider.updateAppWidget(context, appWidgetManager,\n                        mAppWidgetId, account);\n\n                Intent resultValue = new Intent();\n                resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);\n                setResult(RESULT_OK, resultValue);\n                finish();\n            }\n        });\n\n        refreshView();\n    }\n\n    private void refreshView() {\n        ArrayList<Bank> banks = BankFactory.banksFromDb(this, true);\n\n        if (banks.size() > 0) {\n            findViewById(R.id.chkTransperantBackground).setVisibility(View.VISIBLE);\n            findViewById(R.id.txtAccountsDesc).setVisibility(View.GONE);\n            ListView lv = (ListView) findViewById(R.id.lstAccountsList);\n            adapter = new AccountsAdapter(this, false);\n            adapter.setGroups(banks);\n            lv.setAdapter(adapter);\n        }\n    }\n\n\n    @Override\n    public boolean shouldShowActionBar() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/banking/BankFactory.java",
    "content": "/*\n * Copyright (C) 2014 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking;\n\nimport com.crashlytics.android.answers.CustomEvent;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.db.Crypto;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.db.Database;\nimport com.liato.bankdroid.db.DatabaseHelper;\nimport com.liato.bankdroid.utils.LoggingUtils;\n\nimport net.sf.andhsli.hotspotlogin.SimpleCrypto;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.support.annotation.Nullable;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport timber.log.Timber;\n\npublic class BankFactory {\n\n    private static Bank fromBanktypeId(int id, Context context) throws BankException {\n        return LegacyBankFactory.fromBanktypeId(id, context);\n    }\n\n\n    public static List<Bank> listBanks(Context context) {\n        return LegacyBankFactory.listBanks(context);\n    }\n\n    @Nullable\n    public static Bank bankFromDb(long id, Context context, boolean loadAccounts) {\n        Bank bank = null;\n        DBAdapter db = new DBAdapter(context);\n        Cursor c = db.getBank(id);\n\n        if (c != null && c.getCount() > 0) {\n            try {\n                bank = fromBanktypeId(c.getInt(c.getColumnIndex(\"banktype\")), context);\n                bank.setProperties(loadProperties(id, context));\n\n                bank.setData(new BigDecimal(c.getString(c.getColumnIndex(\"balance\"))),\n                        (c.getInt(c.getColumnIndex(\"disabled\")) != 0),\n                        c.getLong(c.getColumnIndex(\"_id\")),\n                        c.getString(c.getColumnIndex(\"currency\")),\n                        c.getString(c.getColumnIndex(\"custname\")),\n                        c.getInt(c.getColumnIndex(\"hideAccounts\")));\n                if (loadAccounts) {\n                    bank.setAccounts(accountsFromDb(context, bank.getDbId()));\n                }\n            } catch (BankException e) {\n                Timber.w(e, \"Failed getting bank from database\");\n            } finally {\n                c.close();\n            }\n        }\n        return bank;\n    }\n\n    public static ArrayList<Bank> banksFromDb(Context context, boolean loadAccounts) {\n        ArrayList<Bank> banks = new ArrayList<>();\n        DBAdapter db = new DBAdapter(context);\n        Cursor c = db.fetchBanks();\n        try {\n            if (c == null || c.getCount() == 0) {\n                return banks;\n            }\n            while (!c.isLast() && !c.isAfterLast()) {\n                c.moveToNext();\n                try {\n                    Bank bank = fromBanktypeId(c.getInt(c.getColumnIndex(\"banktype\")), context);\n                    long id = c.getLong(c.getColumnIndex(\"_id\"));\n                    bank.setProperties(loadProperties(id, context));\n                    bank.setData(new BigDecimal(c.getString(c.getColumnIndex(\"balance\"))),\n                            (c.getInt(c.getColumnIndex(\"disabled\")) != 0),\n                            id,\n                            c.getString(c.getColumnIndex(\"currency\")),\n                            c.getString(c.getColumnIndex(\"custname\")),\n                            c.getInt(c.getColumnIndex(\"hideAccounts\")));\n                    if (loadAccounts) {\n                        bank.setAccounts(accountsFromDb(context, bank.getDbId()));\n                    }\n                    banks.add(bank);\n                } catch (BankException e) {\n                    Timber.w(e, \"BankFactory.banksFromDb()\");\n                }\n            }\n        } finally {\n            if (c != null) {\n                c.close();\n            }\n        }\n        return banks;\n    }\n\n    @Nullable\n    public static Account accountFromDb(Context context, String accountId,\n            boolean loadTransactions) {\n        DBAdapter db = new DBAdapter(context);\n        Cursor ac = db.getAccount(accountId);\n\n        Account account;\n        try {\n            if (ac == null || ac.isClosed() || (ac.isBeforeFirst() && ac.isAfterLast())) {\n                return null;\n            }\n\n            account = new Account(ac.getString(ac.getColumnIndex(\"name\")),\n                    new BigDecimal(ac.getString(ac.getColumnIndex(\"balance\"))),\n                    ac.getString(ac.getColumnIndex(\"id\")).split(\"_\", 2)[1],\n                    ac.getLong(ac.getColumnIndex(\"bankid\")),\n                    ac.getInt(ac.getColumnIndex(\"acctype\")));\n            account.setHidden(ac.getInt(ac.getColumnIndex(\"hidden\")) == 1);\n            account.setNotify(ac.getInt(ac.getColumnIndex(\"notify\")) == 1);\n            account.setCurrency(ac.getString(ac.getColumnIndex(\"currency\")));\n            account.setAliasfor(ac.getString(ac.getColumnIndex(\"aliasfor\")));\n        } finally {\n            if (ac != null) {\n                ac.close();\n            }\n        }\n\n        if (loadTransactions) {\n            ArrayList<Transaction> transactions = new ArrayList<>();\n            String fromAccount = accountId;\n            if (account.getAliasfor() != null && account.getAliasfor().length() > 0) {\n                fromAccount = Long.toString(account.getBankDbId()) + \"_\" + account.getAliasfor();\n            }\n            Cursor tc = db.fetchTransactions(fromAccount);\n            try {\n                if (!(tc == null || tc.isClosed() || (tc.isBeforeFirst() && tc.isAfterLast()))) {\n                    while (!tc.isLast() && !tc.isAfterLast()) {\n                        tc.moveToNext();\n                        transactions.add(new Transaction(tc.getString(tc.getColumnIndex(\"transdate\")),\n                                tc.getString(tc.getColumnIndex(\"btransaction\")),\n                                new BigDecimal(tc.getString(tc.getColumnIndex(\"amount\"))),\n                                tc.getString(tc.getColumnIndex(\"currency\"))));\n                    }\n                }\n            } finally {\n                if (tc != null) {\n                    tc.close();\n                }\n            }\n            account.setTransactions(transactions);\n        }\n        return account;\n    }\n\n    private static ArrayList<Account> accountsFromDb(Context context, long bankId) {\n        ArrayList<Account> accounts = new ArrayList<>();\n        DBAdapter db = new DBAdapter(context);\n        Cursor c = db.fetchAccounts(bankId);\n        try {\n            if (c == null || c.getCount() == 0) {\n                return accounts;\n            }\n            while (!c.isLast() && !c.isAfterLast()) {\n                c.moveToNext();\n                try {\n                    Account account = new Account(c.getString(c.getColumnIndex(\"name\")),\n                            new BigDecimal(c.getString(c.getColumnIndex(\"balance\"))),\n                            c.getString(c.getColumnIndex(\"id\")).split(\"_\", 2)[1],\n                            c.getLong(c.getColumnIndex(\"bankid\")),\n                            c.getInt(c.getColumnIndex(\"acctype\")));\n                    account.setHidden(c.getInt(c.getColumnIndex(\"hidden\")) == 1);\n                    account.setNotify(c.getInt(c.getColumnIndex(\"notify\")) == 1);\n                    account.setCurrency(c.getString(c.getColumnIndex(\"currency\")));\n                    account.setAliasfor(c.getString(c.getColumnIndex(\"aliasfor\")));\n                    accounts.add(account);\n                } catch (ArrayIndexOutOfBoundsException e) {\n                    // Probably an old Avanza account\n                    Timber.w(e, \"Attempted to load an account without an ID: %d\", bankId);\n                }\n            }\n        } finally {\n            if (c != null) {\n                c.close();\n            }\n        }\n        return accounts;\n    }\n\n    private static Map<String, String> loadProperties(long bankId, Context context) {\n        Map<String, String> properties = new HashMap<>();\n        Map<String, String> decryptedProperties = new HashMap<>();\n        DBAdapter db = new DBAdapter(context);\n        Cursor c = db.fetchProperties(Long.toString(bankId));\n        try {\n            if (c == null || c.getCount() == 0) {\n                return properties;\n            }\n            while (!c.isLast() && !c.isAfterLast()) {\n                c.moveToNext();\n                String key = c.getString(c.getColumnIndex(Database.PROPERTY_KEY));\n                String value = c.getString(c.getColumnIndex(Database.PROPERTY_VALUE));\n                if (LegacyProviderConfiguration.PASSWORD.equals(key)) {\n                    try {\n                        value = SimpleCrypto.decrypt(Crypto.getKey(), value);\n                        decryptedProperties.put(key, value);\n                    } catch (Exception e) {\n                        Timber.i(\"%s %s\",\n                                \"Failed decrypting bank properties.\",\n                                \"This usually means they are unencrypted, which is exactly what we want them to be.\");\n                    }\n                }\n                properties.put(key, value);\n            }\n        } finally {\n          if (c != null) {\n              c.close();\n          }\n        }\n\n        storeDecryptedProperties(context, bankId, decryptedProperties);\n\n        return properties;\n    }\n\n    /**\n     * Stores decrypted passwords on disk.\n     * <p/>\n     * This is a step in removing password encryption alltogether.\n     * <p/>\n     * The background is that it's broken on Androin Nougat anyway, and that it\n     * didn't provide any extra security before that either.\n     * <p/>\n     * Since Bankdroid needs to send plain text passwords to the banks, it must\n     * be possible to retrieve the plain text passwords automatically. And if the\n     * passwords are encrypted on disk, Bankdroid needs to have the key. And if\n     * Bankdroid stores both the key and the encrypted password on the phone, a\n     * determined attacker could get both anyway, and the encryption is useless.\n     * <p/>\n     * The only thing the encryption has protected against is a using rooting\n     * their own device and retrieving their own plain text passwords. This would\n     * enable the attacker to reaa their own account balance from the bank. Which\n     * they likely already could even before this change...\n     */\n    private static void storeDecryptedProperties(\n            Context context, long bankId, Map<String, String> decryptedProperties)\n    {\n        if (decryptedProperties.isEmpty()) {\n            return;\n        }\n\n        Timber.i(\"Storing %d decrypted properties...\", decryptedProperties.size());\n        SQLiteDatabase db = DatabaseHelper.getHelper(context).getWritableDatabase();\n        for (Map.Entry<String, String> property : decryptedProperties.entrySet()) {\n            String value = property.getValue();\n            if (value != null && !value.isEmpty()) {\n                ContentValues propertyValues = new ContentValues();\n                propertyValues.put(Database.PROPERTY_KEY, property.getKey());\n                propertyValues.put(Database.PROPERTY_VALUE, value);\n                propertyValues.put(Database.PROPERTY_CONNECTION_ID, bankId);\n                db.insertWithOnConflict(\n                        Database.PROPERTY_TABLE_NAME, null, propertyValues,\n                        SQLiteDatabase.CONFLICT_REPLACE);\n            }\n        }\n        Timber.i(\"%d decrypted properties stored\", decryptedProperties.size());\n\n        LoggingUtils.logCustom(new CustomEvent(\"Passwords Decrypted\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/db/DBAdapter.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.db;\n\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.support.annotation.Nullable;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.Map;\n\n\npublic class DBAdapter {\n\n    private SQLiteDatabase mDb;\n\n    /**\n     * Constructor - takes the context to allow the database to be\n     * opened/created\n     *\n     * @param ctx the Context within which to work\n     */\n    public DBAdapter(Context ctx) {\n        DatabaseHelper dbHelper = DatabaseHelper.getHelper(ctx);\n        mDb = dbHelper.getWritableDatabase();\n    }\n\n    /**\n     * @deprecated Only used during refactoring. Should be removed before next major version (2.0)\n     */\n    @Deprecated\n    public static void save(Bank bank, Context context) {\n        DBAdapter db = new DBAdapter(context);\n        long id = db.updateBank(bank);\n\n        bank.setDbid(id);\n    }\n\n    /**\n     * @deprecated Only used during refactoring. Should be removed before next major version (2.0)\n     */\n    @Deprecated\n    public static void disable(Bank bank, Context context) {\n        DBAdapter db = new DBAdapter(context);\n        db.disableBank(bank.getDbId());\n    }\n\n    public long createBank(Bank bank) {\n        return updateBank(bank);\n    }\n\n    /**\n     * Delete the bank with the given bankId\n     *\n     * @param bankId id of bank to delete\n     */\n    public int deleteBank(long bankId) {\n        int c = mDb.delete(\"banks\", \"_id=\" + bankId, null);\n        c += this.deleteAccounts(bankId);\n        return c;\n    }\n\n    /**\n     * Delete the accounts for the given bankIdbank with the given rowId\n     *\n     * @param bankId id of bank to delete\n     */\n    public int deleteAccounts(long bankId) {\n        int c = mDb.delete(\"accounts\", \"bankid=\" + bankId, null);\n        return c;\n    }\n\n    public int deleteTransactions(String account) {\n        int c = mDb.delete(\"transactions\", \"account='\" + account + \"'\", null);\n        return c;\n    }\n\n    private int deleteProperties(long bankId) {\n        return mDb.delete(Database.PROPERTY_TABLE_NAME, Database.PROPERTY_CONNECTION_ID + \"=\"\n                + bankId, null);\n    }\n\n    /**\n     * Return a Cursor over the list of all banks in the database\n     *\n     * @return Cursor over all banks\n     */\n    public Cursor fetchBanks() {\n        return mDb.query(\"banks\",\n                new String[]{\"_id\", \"balance\", \"banktype\", \"disabled\",\n                        \"custname\", \"updated\", \"sortorder\", \"currency\", \"hideAccounts\"},\n                null, null, null, null, \"_id asc\");\n    }\n\n    /**\n     * Return a Cursor over the list of all accounts belonging to a bank\n     *\n     * @return Cursor over all accounts belonging to a bank\n     */\n    public Cursor fetchAccounts(long bankId) {\n        return mDb.query(\"accounts\",\n                new String[]{\"bankid\", \"balance\", \"name\", \"id\", \"acctype\", \"hidden\", \"notify\",\n                        \"currency\", \"aliasfor\"}, \"bankid=\" + bankId, null, null, null, null);\n    }\n\n    public Cursor fetchTransactions(String account) {\n        return mDb.query(\"transactions\",\n                new String[]{\"transdate\", \"btransaction\", \"amount\", \"currency\"},\n                \"account='\" + account + \"'\", null, null, null, null);\n    }\n\n    public Cursor fetchProperties(String bankId) {\n        return mDb.query(Database.PROPERTY_TABLE_NAME, null,\n                Database.PROPERTY_CONNECTION_ID + \"='\" + bankId + \"'\", null, null, null, null);\n    }\n\n    public long updateBank(Bank bank) {\n        Calendar cal = Calendar.getInstance();\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n        ContentValues initialValues = new ContentValues();\n        initialValues.put(\"banktype\", bank.getBanktypeId());\n        initialValues.put(\"disabled\", 0);\n        initialValues.put(\"balance\", bank.getBalance().toPlainString());\n        initialValues.put(\"currency\", bank.getCurrency());\n        initialValues.put(\"custname\", bank.getCustomName());\n        initialValues.put(\"updated\", sdf.format(cal.getTime()));\n        initialValues.put(\"hideAccounts\", bank.getHideAccounts() ? 1 : 0);\n\n        long bankId = bank.getDbId();\n        if (bankId == -1) {\n            bankId = mDb.insert(\"banks\", null, initialValues);\n        } else {\n            mDb.update(\"banks\", initialValues, \"_id=\" + bankId, null);\n            deleteAccounts(bankId);\n            deleteProperties(bankId);\n        }\n        if (bankId != -1) {\n            Map<String, String> properties = bank.getProperties();\n            for (Map.Entry<String, String> property : properties.entrySet()) {\n                String value = property.getValue();\n                if (value != null && !value.isEmpty()) {\n                    ContentValues propertyValues = new ContentValues();\n                    propertyValues.put(Database.PROPERTY_KEY, property.getKey());\n                    propertyValues.put(Database.PROPERTY_VALUE, value);\n                    propertyValues.put(Database.PROPERTY_CONNECTION_ID, bankId);\n                    mDb.insert(Database.PROPERTY_TABLE_NAME, null, propertyValues);\n                }\n            }\n\n            ArrayList<Account> accounts = bank.getAccounts();\n            for (Account acc : accounts) {\n                ContentValues vals = new ContentValues();\n                vals.put(\"bankid\", bankId);\n                vals.put(\"balance\", acc.getBalance().toPlainString());\n                vals.put(\"name\", acc.getName());\n                vals.put(\"id\", bankId + \"_\" + acc.getId());\n                vals.put(\"hidden\", acc.isHidden() ? 1 : 0);\n                vals.put(\"notify\", acc.isNotify() ? 1 : 0);\n                vals.put(\"currency\", acc.getCurrency());\n                vals.put(\"acctype\", acc.getType());\n                vals.put(\"aliasfor\", acc.getAliasfor());\n                mDb.insert(\"accounts\", null, vals);\n                if (acc.getAliasfor() == null || acc.getAliasfor().length() == 0) {\n                    List<Transaction> transactions = acc.getTransactions();\n                    if (transactions != null && !transactions.isEmpty()) {\n                        deleteTransactions(bankId + \"_\" + acc.getId());\n                        for (Transaction transaction : transactions) {\n                            ContentValues transvals = new ContentValues();\n                            transvals.put(\"transdate\", transaction.getDate());\n                            transvals.put(\"btransaction\", transaction.getTransaction());\n                            transvals.put(\"amount\", transaction.getAmount().toPlainString());\n                            transvals.put(\"account\",\n                                    bankId + \"_\" + acc.getId());\n                            transvals.put(\"currency\", transaction.getCurrency());\n                            mDb.insert(\"transactions\", null, transvals);\n                        }\n                    }\n                }\n            }\n        }\n        return bankId;\n    }\n\n    public void disableBank(long bankId) {\n        if (bankId == -1) {\n            return;\n        }\n        ContentValues initialValues = new ContentValues();\n        initialValues.put(\"disabled\", 1);\n        mDb.update(\"banks\", initialValues, \"_id=\" + bankId, null);\n    }\n\n    @Nullable\n    public Cursor getBank(String bankId) {\n        Cursor c = mDb.query(\"banks\",\n                new String[]{\"_id\", \"balance\", \"banktype\", \"disabled\",\n                        \"custname\", \"updated\", \"sortorder\", \"currency\", \"hideAccounts\"},\n                \"_id=\" + bankId, null, null, null, null);\n        if (c != null) {\n            c.moveToFirst();\n        }\n        return c;\n    }\n\n    @Nullable\n    public Cursor getBank(long bankId) {\n        return getBank(Long.toString(bankId));\n    }\n\n    @Nullable\n    public Cursor getAccount(String id) {\n        Cursor c = mDb.query(\"accounts\",\n                new String[]{\"id\", \"balance\", \"name\", \"bankid\", \"acctype\", \"hidden\", \"notify\",\n                        \"currency\", \"aliasfor\"}, \"id='\" + id + \"'\", null, null, null, null);\n        if (c != null) {\n            c.moveToFirst();\n        }\n        return c;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/db/Database.java",
    "content": "package com.liato.bankdroid.db;\n\npublic class Database {\n\n    static final String DATABASE_NAME = \"data\";\n\n    static final int DATABASE_VERSION = 12;\n\n    public static final String PROPERTY_TABLE_NAME = \"connection_properties\";\n    public static final String PROPERTY_CONNECTION_ID = \"connection_id\";\n    public static final String PROPERTY_KEY = \"property\";\n    public static final String PROPERTY_VALUE = \"value\";\n\n    static final String TABLE_CONNECTION_PROPERTIES = \"CREATE TABLE \" + PROPERTY_TABLE_NAME + \" (\" +\n            PROPERTY_CONNECTION_ID + \" INTEGER REFERENCES \" + LegacyDatabase.BANK_TABLE_NAME + \"(\" + LegacyDatabase.BANK_ID + \") ON DELETE CASCADE, \" +\n            PROPERTY_KEY + \" TEXT NOT NULL, \" +\n            PROPERTY_VALUE + \" TEXT, \" +\n            \"PRIMARY KEY (\" + PROPERTY_CONNECTION_ID + \",\" + PROPERTY_KEY + \"));\";\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/db/DatabaseHelper.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.db;\n\nimport com.liato.bankdroid.banking.LegacyProviderConfiguration;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\nimport timber.log.Timber;\n\nimport static com.liato.bankdroid.db.Database.PROPERTY_CONNECTION_ID;\nimport static com.liato.bankdroid.db.Database.PROPERTY_KEY;\nimport static com.liato.bankdroid.db.Database.PROPERTY_TABLE_NAME;\nimport static com.liato.bankdroid.db.Database.PROPERTY_VALUE;\n\n/**\n * @since 8 jan 2011\n */\nfinal public class DatabaseHelper extends SQLiteOpenHelper {\n\n    private static DatabaseHelper instance;\n\n    private DatabaseHelper(final Context context) {\n        super(context, Database.DATABASE_NAME, null,\n                Database.DATABASE_VERSION);\n    }\n\n    public static synchronized DatabaseHelper getHelper(Context context) {\n        if (instance == null) {\n            instance = new DatabaseHelper(context);\n        }\n        return instance;\n    }\n\n    @Override\n    public void onCreate(final SQLiteDatabase db) {\n        db.execSQL(LegacyDatabase.TABLE_BANKS);\n        db.execSQL(LegacyDatabase.TABLE_ACCOUNTS);\n        db.execSQL(LegacyDatabase.TABLE_TRANSACTIONS);\n        db.execSQL(Database.TABLE_CONNECTION_PROPERTIES);\n    }\n\n    @Override\n    public void onUpgrade(final SQLiteDatabase db, final int oldVersion,\n            final int newVersion) {\n        Timber.d(\"Upgrading database from version %d to %d\", newVersion, oldVersion);\n        // Version <= 1.7.2\n        if (oldVersion <= 9) {\n            // Add an \"extras\" field to the bank and and \"alias for\" field to the account.\n            db.execSQL(\"ALTER TABLE \" + LegacyDatabase.BANK_TABLE_NAME + \" ADD \" +\n                    LegacyDatabase.BANK_EXTRAS + \" text;\");\n            db.execSQL(\"ALTER TABLE \" + LegacyDatabase.ACCOUNT_TABLE_NAME + \" ADD \" +\n                    LegacyDatabase.ACCOUNT_ALIAS_FOR + \" text;\");\n        }\n        if (oldVersion <= 10) {\n            db.execSQL(\"ALTER TABLE \" + LegacyDatabase.BANK_TABLE_NAME + \" ADD \" +\n                    LegacyDatabase.BANK_HIDE_ACCOUNTS + \" integer;\");\n        }\n        if (oldVersion <= 11) {\n            try {\n                db.beginTransaction();\n                db.execSQL(Database.TABLE_CONNECTION_PROPERTIES);\n                migrateProperties(db);\n                db.setTransactionSuccessful();\n            } finally {\n                db.endTransaction();\n            }\n        }\n    }\n\n    private void migrateProperties(final SQLiteDatabase db) {\n        String tempTable = LegacyDatabase.BANK_TABLE_NAME + \"_temp\";\n        db.execSQL(\"ALTER TABLE \" + LegacyDatabase.BANK_TABLE_NAME + \" RENAME TO \" + tempTable + \";\");\n\n        // Drop username, password and extras fields from bank table\n        db.execSQL(LegacyDatabase.TABLE_BANKS);\n        db.execSQL(\"INSERT INTO \" + LegacyDatabase.BANK_TABLE_NAME + \" SELECT \"\n            + LegacyDatabase.BANK_ID + \",\"\n            + LegacyDatabase.BANK_BALANCE + \",\"\n            + LegacyDatabase.BANK_TYPE + \",\"\n            + LegacyDatabase.BANK_CUSTOM_NAME + \",\"\n            + LegacyDatabase.BANK_UPDATED + \",\"\n            + LegacyDatabase.BANK_SORT_ORDER + \",\"\n            + LegacyDatabase.BANK_CURRENCY + \",\"\n            + LegacyDatabase.BANK_DISABLED + \",\"\n            + LegacyDatabase.BANK_HIDE_ACCOUNTS + \" FROM \" + tempTable);\n\n        // Add username, password and extras fields to properties table.\n        Cursor c = db.query(tempTable, null, null, null, null, null, null);\n        try {\n            if (!(c == null || c.isClosed() || (c.isBeforeFirst() && c.isAfterLast()))) {\n                while (!c.isLast() && !c.isAfterLast()) {\n                    c.moveToNext();\n                    long id = c.getLong(c.getColumnIndex(LegacyDatabase.BANK_ID));\n\n                    ContentValues usernameProperty = new ContentValues();\n                    usernameProperty.put(PROPERTY_CONNECTION_ID, id);\n                    usernameProperty.put(PROPERTY_KEY, LegacyProviderConfiguration.USERNAME);\n                    usernameProperty.put(PROPERTY_VALUE, c.getString(c.getColumnIndex(LegacyDatabase.BANK_USERNAME)));\n                    db.insert(PROPERTY_TABLE_NAME, null, usernameProperty);\n\n                    ContentValues passwordProperty = new ContentValues();\n                    passwordProperty.put(PROPERTY_CONNECTION_ID, id);\n                    passwordProperty.put(PROPERTY_KEY, LegacyProviderConfiguration.PASSWORD);\n                    passwordProperty.put(PROPERTY_VALUE, c.getString(c.getColumnIndex(LegacyDatabase.BANK_PASSWORD)));\n                    db.insert(PROPERTY_TABLE_NAME, null, passwordProperty);\n\n                    String extras = c.getString(c.getColumnIndex(LegacyDatabase.BANK_EXTRAS));\n                    if (extras != null && !extras.isEmpty()) {\n                        ContentValues extrasProperty = new ContentValues();\n                        extrasProperty.put(PROPERTY_CONNECTION_ID, id);\n                        extrasProperty.put(PROPERTY_KEY, LegacyProviderConfiguration.EXTRAS);\n                        extrasProperty.put(PROPERTY_VALUE, extras);\n                        db.insert(PROPERTY_TABLE_NAME, null, extrasProperty);\n                    }\n                }\n            }\n        } finally {\n            if (c != null) {\n                c.close();\n            }\n        }\n        db.execSQL(\"DROP TABLE \" + tempTable);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/db/LegacyDatabase.java",
    "content": "package com.liato.bankdroid.db;\n\nclass LegacyDatabase {\n\n    static final String BANK_TABLE_NAME = \"banks\";\n\n    static final String BANK_ID = \"_id\";\n\n    static final String BANK_BALANCE = \"balance\";\n\n    static final String BANK_TYPE = \"banktype\";\n\n    static final String BANK_USERNAME = \"username\";\n\n    static final String BANK_PASSWORD = \"password\";\n\n    static final String BANK_CUSTOM_NAME = \"custname\";\n\n    static final String BANK_UPDATED = \"updated\";\n\n    static final String BANK_SORT_ORDER = \"sortorder\";\n\n    static final String BANK_CURRENCY = \"currency\";\n\n    static final String BANK_DISABLED = \"disabled\";\n\n    static final String BANK_HIDE_ACCOUNTS = \"hideAccounts\";\n\n    static final String BANK_EXTRAS = \"extras\";\n\n\n    static final String ACCOUNT_TABLE_NAME = \"accounts\";\n\n    static final String ACCOUNT_BANK_ID = \"bankid\";\n\n    static final String ACCOUNT_ID = \"id\";\n\n    static final String ACCOUNT_BALANCE = \"balance\";\n\n    static final String ACCOUNT_CURRENCY = \"currency\";\n\n    static final String ACCOUNT_TYPE = \"acctype\";\n\n    static final String ACCOUNT_NAME = \"name\";\n\n    static final String ACCOUNT_HIDDEN = \"hidden\";\n\n    static final String ACCOUNT_NOTIFY = \"notify\";\n\n    static final String ACCOUNT_ALIAS_FOR = \"aliasfor\";\n\n\n    static final String TRANSACTION_TABLE_NAME = \"transactions\";\n\n    static final String TRANSACTION_ID = \"_id\";\n\n    static final String TRANSACTION_DATE = \"transdate\";\n\n    static final String TRANSACTION_DESCRIPTION = \"btransaction\";\n\n    static final String TRANSACTION_AMOUNT = \"amount\";\n\n    static final String TRANSACTION_CURRENCY = \"currency\";\n\n    static final String TRANSACTION_ACCOUNT_ID = \"account\";\n\n    static final String TABLE_BANKS = new StringBuilder(\"create table \")\n            .append(BANK_TABLE_NAME)\n            .append(\" (\")\n            .append(BANK_ID)\n            .append(\" integer primary key autoincrement, \")\n            .append(BANK_BALANCE)\n            .append(\" text not null, \")\n            .append(BANK_TYPE)\n            .append(\" integer not null, \")\n            .append(BANK_CUSTOM_NAME)\n            .append(\" text, \")\n            .append(BANK_UPDATED)\n            .append(\" text, \")\n            .append(BANK_SORT_ORDER)\n            .append(\" real, \")\n            .append(BANK_CURRENCY)\n            .append(\" text, \")\n            .append(BANK_DISABLED)\n            .append(\" integer, \")\n            .append(BANK_HIDE_ACCOUNTS)\n            .append(\" integer);\").toString();\n\n    static final String TABLE_ACCOUNTS = new StringBuilder(\"create table \")\n            .append(ACCOUNT_TABLE_NAME)\n            .append(\" (\")\n            .append(ACCOUNT_BANK_ID)\n            .append(\" integer not null, \")\n            .append(ACCOUNT_ID)\n            .append(\" text not null, \")\n            .append(ACCOUNT_BALANCE)\n            .append(\" text not null, \")\n            .append(ACCOUNT_TYPE)\n            .append(\" integer not null, \")\n            .append(ACCOUNT_HIDDEN)\n            .append(\" integer not null, \")\n            .append(ACCOUNT_NOTIFY)\n            .append(\" integer not null, \")\n            .append(ACCOUNT_CURRENCY)\n            .append(\" text, \")\n            .append(ACCOUNT_NAME)\n            .append(\" text not null, \")\n            .append(ACCOUNT_ALIAS_FOR)\n            .append(\" text);\").toString();\n\n    static final String TABLE_TRANSACTIONS = new StringBuilder(\"create table \")\n            .append(TRANSACTION_TABLE_NAME)\n            .append(\" (\")\n            .append(TRANSACTION_ID)\n            .append(\" integer primary key autoincrement, \")\n            .append(TRANSACTION_DATE)\n            .append(\" text not null, \")\n            .append(TRANSACTION_DESCRIPTION)\n            .append(\" text not null, \")\n            .append(TRANSACTION_AMOUNT)\n            .append(\" text not null, \")\n            .append(TRANSACTION_CURRENCY)\n            .append(\" text, \")\n            .append(TRANSACTION_ACCOUNT_ID)\n            .append(\" text not null);\").toString();\n\n    private LegacyDatabase() {\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/liveview/LiveViewService.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n *\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.liato.bankdroid.liveview;\n\nimport com.liato.bankdroid.MainActivity;\nimport com.liato.bankdroid.R;\nimport com.sonyericsson.extras.liveview.IPluginServiceCallbackV1;\nimport com.sonyericsson.extras.liveview.IPluginServiceV1;\n\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport timber.log.Timber;\n\n/**\n * Implementation of the Live View plug-in service.\n *\n * @author firetech\n */\npublic class LiveViewService extends Service {\n\n    // Announce intent information keys\n    public static final String INTENT_EXTRA_ANNOUNCE = \"isAnnounce\";\n\n    public static final String INTENT_EXTRA_TITLE = \"title\";\n\n    public static final String INTENT_EXTRA_TEXT = \"text\";\n\n    // Template menu icon file name.\n    private static final String MENU_ICON_FILENAME = \"plugin_icon.png\";\n\n    // There should only be one instance of the service\n    protected static boolean alreadyRunning = false;\n\n    // Plugin name\n    protected String mPluginName = null;\n\n    // Current plugin Id\n    protected int mPluginId = 0;\n\n    // Menu icon that will be shown in LiveView unit\n    protected String mMenuIcon = null;\n\n    // Reference to LiveView application stub\n    private IPluginServiceV1 mLiveView = null;\n\n    /**\n     * The service connection that is used to bind the plugin to the LiveView\n     * service.\n     *\n     * When connected to the service, the plugin is registered. When\n     * disconnected to the service, the plugin is unregistered.\n     */\n    private ServiceConnection mServiceConnection = new ServiceConnection() {\n\n        @Override\n        public void onServiceConnected(final ComponentName className, IBinder service) {\n            Timber.d(\"Enter LiveViewService.ServiceConnection.onServiceConnected.\");\n\n            mLiveView = IPluginServiceV1.Stub.asInterface(service);\n\n            // Init adapter\n            LiveViewCallback lvCallback = new LiveViewCallback();\n\n            // Install plugin\n            try {\n                if (mLiveView != null) {\n                    // Register\n                    mPluginId = mLiveView\n                            .register(lvCallback, mMenuIcon, mPluginName, false, getPackageName());\n                    Timber.d(\"Plugin registered with id: %d\", mPluginId);\n                }\n            } catch (RemoteException re) {\n                Timber.e(\"Failed to install plugin. Stop self.\");\n                stopSelf();\n            }\n\n            Timber.d(\"Plugin registered. mPluginId: %d\", mPluginId);\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName className) {\n            Timber.d(\"Enter LiveViewService.ServiceConnection.onServiceDisconnected.\");\n            stopSelf();\n        }\n\n    };\n\n    /**\n     * Check if service is already running.\n     *\n     * @return running?\n     */\n    public static boolean isAlreadyRunning() {\n        return alreadyRunning;\n    }\n\n\n    public void onCreate() {\n        super.onCreate();\n        Timber.d(\"Enter LiveViewService.onCreate.\");\n\n        // Load menu icon\n        int iconId = R.drawable.ic_launcher;\n        mMenuIcon = PluginUtils.storeIconToFile(this, getResources(), iconId, MENU_ICON_FILENAME);\n    }\n\n    public void onDestroy() {\n        Timber.d(\"Enter LiveViewService.onDestroy.\");\n\n        // Unbind from LiveView service\n        if (mServiceConnection != null) {\n            unbindService(mServiceConnection);\n        }\n\n        // No longer a running service\n        alreadyRunning = false;\n\n        super.onDestroy();\n    }\n\n    public void onStart(Intent intent, int startId) {\n        super.onStart(intent, startId);\n        Timber.d(\"Enter LiveViewService.onStart.\");\n        if (intent == null) {\n            return;\n        }\n        if (intent.getBooleanExtra(INTENT_EXTRA_ANNOUNCE, false)) {\n            Bundle extras = intent.getExtras();\n            if (extras != null) {\n                try {\n                    if (mLiveView != null) {\n                        mLiveView.sendAnnounce(mPluginId, mMenuIcon,\n                                extras.getString(INTENT_EXTRA_TITLE),\n                                extras.getString(INTENT_EXTRA_TEXT), System.currentTimeMillis(),\n                                \"\");\n                        Timber.d(\"Announce sent to LiveView Application\");\n                    } else {\n                        Timber.d(\"LiveView Application not reachable\");\n                    }\n                } catch (Exception e) {\n                    Timber.e(e, \"Failed to send announce\");\n                }\n            }\n\n        } else {\n            // We end up here when LiveView Application probes the plugin\n            if (isAlreadyRunning()) {\n                Timber.d(\"Already started.\");\n            } else {\n                // Init\n                mPluginName = getResources().getString(R.string.app_name);\n\n                // Bind to LiveView\n                connectToLiveView();\n\n                // Singleton\n                alreadyRunning = true;\n            }\n        }\n    }\n\n    @Override\n    public IBinder onBind(final Intent intent) {\n        Timber.d(\"Enter LiveViewService.onBind.\");\n        return null;\n    }\n\n    /**\n     * Connects to the LiveView service.\n     */\n    private void connectToLiveView() {\n        boolean result = bindService(new Intent(PluginConstants.LIVEVIEW_SERVICE_BIND_INTENT),\n                mServiceConnection, 0);\n        if (result) {\n            Timber.d(\"Bound to LiveView.\");\n        } else {\n            Timber.d(\"No bind.\");\n            stopSelf();\n        }\n    }\n\n    /**\n     * When a user presses the \"open in phone\" button on the LiveView device, this method is\n     * called.\n     *\n     * Opens the MainActivity on the phone.\n     */\n    protected void openInPhone(String openInPhoneAction) {\n        Timber.d(\"openInPhone\");\n        Intent i = new Intent(this, MainActivity.class)\n                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(i);\n    }\n\n    /**\n     * LiveView callback interface method.\n     */\n    private class LiveViewCallback extends IPluginServiceCallbackV1.Stub {\n\n        Handler mCallbackHandler = new Handler();\n\n\n        public String getPluginName() throws RemoteException {\n            return mPluginName;\n        }\n\n\n        public void openInPhone(final String openInPhoneAction) throws RemoteException {\n            mCallbackHandler.post(new Runnable() {\n                public void run() {\n                    LiveViewService.this.openInPhone(openInPhoneAction);\n                }\n            });\n        }\n\n        //Unused methods required by API.\n        public void startPlugin() throws RemoteException {\n        }\n\n        public void stopPlugin() throws RemoteException {\n        }\n\n        public void onUnregistered() throws RemoteException {\n        }\n\n        public void displayCaps(int displayWidthPixels, int displayHeigthPixels)\n                throws RemoteException {\n        }\n\n        public void button(String buttonType, boolean doublepress,\n                boolean longpress) throws RemoteException {\n        }\n\n        public void screenMode(int screenMode) throws RemoteException {\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/liveview/PluginConstants.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n *\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.liato.bankdroid.liveview;\n\n/**\n * Plugin common constants.\n *\n * @author firetech\n */\npublic final class PluginConstants {\n\n    // Broadcast receiver constants\n    public static final String BROADCAST_COMMAND = \"CMD\";\n\n    public static final String BROADCAST_COMMAND_PREFERENCES = \"preferences\";\n\n    public static final String BROADCAST_COMMAND_START = \"start\";\n\n    public static final String BROADCAST_COMMAND_PLUGIN_NAME = \"pluginName\";\n\n    // LiveView Plugin interface intents\n    public static final String LIVEVIEW_SERVICE_BIND_INTENT\n            = \"com.sonyericsson.extras.liveview.PLUGIN_SERVICE_V1\";\n\n    public static final String LIVEVIEW_BROADCAST_LAUNCH_EVENT\n            = \"com.sonyericsson.extras.liveview.LAUNCH_PLUGIN\";\n\n    // Log tag\n    public static final String LOG_TAG = \"BankDroidLiveViewPlugin\";\n\n    private PluginConstants() {\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/liveview/PluginReceiver.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n *\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.liato.bankdroid.liveview;\n\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.SettingsActivity;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport timber.log.Timber;\n\n/**\n * Receives broadcast intents from LiveView service.\n *\n * @author firetech\n */\npublic class PluginReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        String command = intent.getExtras().getString(PluginConstants.BROADCAST_COMMAND);\n        Timber.v(\"Received command: %s\", command);\n\n        if (command == null) {\n            return;\n        }\n\n        if (command.contentEquals(PluginConstants.BROADCAST_COMMAND_PREFERENCES)) {\n            String pluginName = intent.getExtras()\n                    .getString(PluginConstants.BROADCAST_COMMAND_PLUGIN_NAME);\n            String myPluginName = context.getResources().getString(R.string.app_name);\n\n            if (pluginName != null && pluginName.contentEquals(myPluginName)) {\n                Timber.v(\"Starting preferences!\");\n\n                Intent prefsIntent = new Intent(context, SettingsActivity.class);\n                prefsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                context.startActivity(prefsIntent);\n            }\n        } else if (command.contentEquals(PluginConstants.BROADCAST_COMMAND_START)) {\n            if (LiveViewService.isAlreadyRunning()) {\n                Timber.v(\"Service is already running.\");\n            } else {\n                Timber.v(\"Starting service!\");\n\n                context.startService(new Intent(context, LiveViewService.class));\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/liveview/PluginUtils.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copyright (c) 2010 Sony Ericsson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n *\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.liato.bankdroid.liveview;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport timber.log.Timber;\n\n/**\n * Utils for LiveView plugin.\n *\n * @author firetech\n */\npublic final class PluginUtils {\n\n    private PluginUtils() {\n\n    }\n\n    /**\n     * Stores icon to phone file system\n     *\n     * @param resources Reference to project resources\n     * @param resource  Reference to specific resource\n     * @param fileName  The icon file name\n     */\n    public static String storeIconToFile(Context ctx, Resources resources, int resource,\n            String fileName) {\n        Timber.d(\"Store icon to file.\");\n\n        if (resources == null) {\n            return \"\";\n        }\n\n        Bitmap bitmap = BitmapFactory.decodeStream(resources.openRawResource(resource));\n\n        try {\n            FileOutputStream fos = ctx.openFileOutput(fileName, Context.MODE_WORLD_READABLE);\n            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);\n            fos.flush();\n            fos.close();\n        } catch (IOException e) {\n            Timber.e(e, \"Failed to store to device\");\n        }\n\n        File iconFile = ctx.getFileStreamPath(fileName);\n        Timber.d(\"Icon stored. %s\", iconFile.getAbsolutePath());\n\n        return iconFile.getAbsolutePath();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/ChooseLockPattern.java",
    "content": "/*\n * Copyright (C) 2007 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport com.google.common.collect.Lists;\n\nimport com.liato.bankdroid.R;\nimport com.liato.bankdroid.lockpattern.LockPatternView.DisplayMode;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.Window;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * If the user has a lock pattern set already, makes them confirm the existing one.\n *\n * Then, prompts the user to choose a lock pattern:\n * - prompts for initial pattern\n * - asks for confirmation / restart\n * - saves chosen password when confirmed\n */\npublic class ChooseLockPattern extends Activity implements View.OnClickListener {\n\n    /**\n     * Used by the choose lock pattern wizard to indicate the wizard is\n     * finished, and each activity in the wizard should finish.\n     * <p>\n     * Previously, each activity in the wizard would finish itself after\n     * starting the next activity. However, this leads to broken 'Back'\n     * behavior. So, now an activity does not finish itself until it gets this\n     * result.\n     */\n    static final int RESULT_FINISHED = RESULT_FIRST_USER;\n\n    // how long after a confirmation message is shown before moving on\n    static final int INFORMATION_MSG_TIMEOUT_MS = 3000;\n\n    // how long we wait to clear a wrong pattern\n    private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;\n\n    private static final int ID_EMPTY_MESSAGE = -1;\n\n    private static final String KEY_UI_STAGE = \"uiStage\";\n\n    private static final String KEY_PATTERN_CHOICE = \"chosenPattern\";\n\n    /**\n     * The patten used during the help screen to show how to draw a pattern.\n     */\n    private final List<LockPatternView.Cell> mAnimatePattern =\n            Collections.unmodifiableList(\n                    Lists.newArrayList(\n                            LockPatternView.Cell.of(0, 0),\n                            LockPatternView.Cell.of(0, 1),\n                            LockPatternView.Cell.of(1, 1),\n                            LockPatternView.Cell.of(2, 1)\n                    ));\n\n    protected TextView mHeaderText;\n\n    protected LockPatternView mLockPatternView;\n\n    protected TextView mFooterText;\n\n    protected List<LockPatternView.Cell> mChosenPattern = null;\n\n    protected LockPatternUtils mLockPatternUtils;\n\n    private TextView mFooterLeftButton;\n\n    private TextView mFooterRightButton;\n\n    private Stage mUiStage = Stage.Introduction;\n\n    private Runnable mClearPatternRunnable = new Runnable() {\n        public void run() {\n            mLockPatternView.clearPattern();\n        }\n    };\n\n    /**\n     * The pattern listener that responds according to a user choosing a new\n     * lock pattern.\n     */\n    protected LockPatternView.OnPatternListener mChooseNewLockPatternListener\n            = new LockPatternView.OnPatternListener() {\n\n        public void onPatternStart() {\n            mLockPatternView.removeCallbacks(mClearPatternRunnable);\n            patternInProgress();\n        }\n\n        public void onPatternCleared() {\n            mLockPatternView.removeCallbacks(mClearPatternRunnable);\n        }\n\n        public void onPatternDetected(List<LockPatternView.Cell> pattern) {\n            if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {\n                if (mChosenPattern == null) {\n                    throw new IllegalStateException(\n                            \"null chosen pattern in stage 'need to confirm\");\n                }\n                if (mChosenPattern.equals(pattern)) {\n                    updateStage(Stage.ChoiceConfirmed);\n                } else {\n                    updateStage(Stage.ConfirmWrong);\n                }\n            } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort) {\n                if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {\n                    updateStage(Stage.ChoiceTooShort);\n                } else {\n                    mChosenPattern = new ArrayList<LockPatternView.Cell>(pattern);\n                    updateStage(Stage.FirstChoiceValid);\n                }\n            } else {\n                throw new IllegalStateException(\"Unexpected stage \" + mUiStage + \" when \"\n                        + \"entering the pattern.\");\n            }\n        }\n\n        private void patternInProgress() {\n            mHeaderText.setText(R.string.lockpattern_recording_inprogress);\n            mFooterText.setText(\"\");\n            mFooterLeftButton.setEnabled(false);\n            mFooterRightButton.setEnabled(false);\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        mLockPatternUtils = new LockPatternUtils(this);\n\n        requestWindowFeature(Window.FEATURE_NO_TITLE);\n\n        setupViews();\n\n        // make it so unhandled touch events within the unlock screen go to the\n        // lock pattern view.\n        final LinearLayoutWithDefaultTouchRecepient topLayout\n                = (LinearLayoutWithDefaultTouchRecepient) findViewById(\n                R.id.topLayout);\n        topLayout.setDefaultTouchRecepient(mLockPatternView);\n\n        if (savedInstanceState == null) {\n            // first launch\n            updateStage(Stage.Introduction);\n            if (mLockPatternUtils.savedPatternExists()) {\n                confirmPattern();\n            }\n        } else {\n            // restore from previous state\n            final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);\n            if (patternString != null) {\n                mChosenPattern = LockPatternUtils.stringToPattern(patternString);\n            }\n            updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);\n        }\n    }\n\n    /**\n     * Keep all \"find view\" related stuff confined to this function since in\n     * case someone needs to subclass and customize.\n     */\n    protected void setupViews() {\n        setContentView(R.layout.choose_lock_pattern);\n\n        mHeaderText = (TextView) findViewById(R.id.headerText);\n\n        mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);\n        mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);\n        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());\n\n        mFooterText = (TextView) findViewById(R.id.footerText);\n\n        mFooterLeftButton = (TextView) findViewById(R.id.footerLeftButton);\n        mFooterRightButton = (TextView) findViewById(R.id.footerRightButton);\n\n        mFooterLeftButton.setOnClickListener(this);\n        mFooterRightButton.setOnClickListener(this);\n    }\n\n    public void onClick(View v) {\n        if (v == mFooterLeftButton) {\n            if (mUiStage.leftMode == LeftButtonMode.Retry) {\n                mChosenPattern = null;\n                mLockPatternView.clearPattern();\n                updateStage(Stage.Introduction);\n            } else if (mUiStage.leftMode == LeftButtonMode.Cancel) {\n                // They are canceling the entire wizard\n                setResult(RESULT_FINISHED);\n                finish();\n            } else {\n                throw new IllegalStateException(\"left footer button pressed, but stage of \" +\n                        mUiStage + \" doesn't make sense\");\n            }\n        } else if (v == mFooterRightButton) {\n\n            if (mUiStage.rightMode == RightButtonMode.Continue) {\n                if (mUiStage != Stage.FirstChoiceValid) {\n                    throw new IllegalStateException(\"expected ui stage \" + Stage.FirstChoiceValid\n                            + \" when button is \" + RightButtonMode.Continue);\n                }\n                updateStage(Stage.NeedToConfirm);\n            } else if (mUiStage.rightMode == RightButtonMode.Confirm) {\n                if (mUiStage != Stage.ChoiceConfirmed) {\n                    throw new IllegalStateException(\"expected ui stage \" + Stage.ChoiceConfirmed\n                            + \" when button is \" + RightButtonMode.Confirm);\n                }\n                saveChosenPatternAndFinish();\n            } else if (mUiStage.rightMode == RightButtonMode.Ok) {\n                if (mUiStage != Stage.HelpScreen) {\n                    throw new IllegalStateException(\n                            \"Help screen is only mode with ok button, but \" +\n                                    \"stage is \" + mUiStage);\n                }\n                mLockPatternView.clearPattern();\n                mLockPatternView.setDisplayMode(DisplayMode.Correct);\n                updateStage(Stage.Introduction);\n            }\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {\n            if (mUiStage == Stage.HelpScreen) {\n                updateStage(Stage.Introduction);\n                return true;\n            }\n        }\n        if (keyCode == KeyEvent.KEYCODE_MENU && mUiStage == Stage.Introduction) {\n            updateStage(Stage.HelpScreen);\n            return true;\n        }\n\n        return super.onKeyDown(keyCode, event);\n    }\n\n    /**\n     * Launch screen to confirm the existing lock pattern.\n     *\n     * @see #onActivityResult(int, int, android.content.Intent)\n     */\n    protected void confirmPattern() {\n        final Intent intent = new Intent(this, ConfirmLockPattern.class);\n        //intent.setClassName(\"com.liato.bankdroid.lockpattern\", \"com.liato.bankdroid.lockpattern.ConfirmLockPattern\");\n        startActivityForResult(intent, 55);\n    }\n\n    /**\n     * @see #confirmPattern\n     */\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode,\n            Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        if (requestCode != 55) {\n            return;\n        }\n\n        if (resultCode != Activity.RESULT_OK) {\n            setResult(RESULT_FINISHED);\n            finish();\n        }\n        updateStage(Stage.Introduction);\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());\n        if (mChosenPattern != null) {\n            outState.putString(KEY_PATTERN_CHOICE,\n                    LockPatternUtils.patternToString(mChosenPattern));\n        }\n\n        super.onSaveInstanceState(outState);\n    }\n\n    /**\n     * Updates the messages and buttons appropriate to what stage the user\n     * is at in choosing a view.  This doesn't handle clearing out the pattern;\n     * the pattern is expected to be in the right state.\n     */\n    protected void updateStage(Stage stage) {\n\n        mUiStage = stage;\n\n        // header text, footer text, visibility and\n        // enabled state all known from the stage\n        if (stage == Stage.ChoiceTooShort) {\n            mHeaderText.setText(\n                    getResources().getString(\n                            stage.headerMessage,\n                            LockPatternUtils.MIN_LOCK_PATTERN_SIZE));\n        } else {\n            mHeaderText.setText(stage.headerMessage);\n        }\n        if (stage.footerMessage == ID_EMPTY_MESSAGE) {\n            mFooterText.setText(\"\");\n        } else {\n            mFooterText.setText(stage.footerMessage);\n        }\n\n        if (stage.leftMode == LeftButtonMode.Gone) {\n            mFooterLeftButton.setVisibility(View.GONE);\n        } else {\n            mFooterLeftButton.setVisibility(View.VISIBLE);\n            mFooterLeftButton.setText(stage.leftMode.text);\n            mFooterLeftButton.setEnabled(stage.leftMode.enabled);\n        }\n\n        mFooterRightButton.setText(stage.rightMode.text);\n        mFooterRightButton.setEnabled(stage.rightMode.enabled);\n\n        // same for whether the patten is enabled\n        if (stage.patternEnabled) {\n            mLockPatternView.enableInput();\n        } else {\n            mLockPatternView.disableInput();\n        }\n\n        // the rest of the stuff varies enough that it is easier just to handle\n        // on a case by case basis.\n        mLockPatternView.setDisplayMode(DisplayMode.Correct);\n\n        switch (mUiStage) {\n            case Introduction:\n                mLockPatternView.clearPattern();\n                break;\n            case HelpScreen:\n                mLockPatternView.setPattern(DisplayMode.Animate, mAnimatePattern);\n                break;\n            case ChoiceTooShort:\n                mLockPatternView.setDisplayMode(DisplayMode.Wrong);\n                postClearPatternRunnable();\n                break;\n            case FirstChoiceValid:\n                break;\n            case NeedToConfirm:\n                mLockPatternView.clearPattern();\n                break;\n            case ConfirmWrong:\n                mLockPatternView.setDisplayMode(DisplayMode.Wrong);\n                postClearPatternRunnable();\n                break;\n            case ChoiceConfirmed:\n                break;\n        }\n    }\n\n    // clear the wrong pattern unless they have started a new one\n    // already\n    private void postClearPatternRunnable() {\n        mLockPatternView.removeCallbacks(mClearPatternRunnable);\n        mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);\n    }\n\n    private void saveChosenPatternAndFinish() {\n        final boolean lockVirgin = !mLockPatternUtils.isPatternEverChosen();\n\n        mLockPatternUtils.saveLockPattern(mChosenPattern);\n        mLockPatternUtils.setLockPatternEnabled(true);\n\n        if (lockVirgin) {\n            mLockPatternUtils.setVisiblePatternEnabled(true);\n            mLockPatternUtils.setTactileFeedbackEnabled(false);\n        }\n\n        setResult(RESULT_FINISHED);\n        finish();\n    }\n\n\n    /**\n     * The states of the left footer button.\n     */\n    enum LeftButtonMode {\n        Cancel(android.R.string.cancel, true),\n        CancelDisabled(android.R.string.cancel, false),\n        Retry(R.string.lockpattern_retry_button_text, true),\n        RetryDisabled(R.string.lockpattern_retry_button_text, false),\n        Gone(ID_EMPTY_MESSAGE, false);\n\n        final int text;\n\n        final boolean enabled;\n\n        /**\n         * @param text    The displayed text for this mode.\n         * @param enabled Whether the button should be enabled.\n         */\n        LeftButtonMode(int text, boolean enabled) {\n            this.text = text;\n            this.enabled = enabled;\n        }\n    }\n\n\n    /**\n     * The states of the right button.\n     */\n    enum RightButtonMode {\n        Continue(R.string.lockpattern_continue_button_text, true),\n        ContinueDisabled(R.string.lockpattern_continue_button_text, false),\n        Confirm(R.string.lockpattern_confirm_button_text, true),\n        ConfirmDisabled(R.string.lockpattern_confirm_button_text, false),\n        Ok(android.R.string.ok, true);\n\n        final int text;\n\n        final boolean enabled;\n\n        /**\n         * @param text    The displayed text for this mode.\n         * @param enabled Whether the button should be enabled.\n         */\n        RightButtonMode(int text, boolean enabled) {\n            this.text = text;\n            this.enabled = enabled;\n        }\n    }\n\n    /**\n     * Keep track internally of where the user is in choosing a pattern.\n     */\n    protected enum Stage {\n\n        Introduction(\n                R.string.lockpattern_recording_intro_header,\n                LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled,\n                R.string.lockpattern_recording_intro_footer, true),\n        HelpScreen(\n                R.string.lockpattern_settings_help_how_to_record,\n                LeftButtonMode.Gone, RightButtonMode.Ok, ID_EMPTY_MESSAGE, false),\n        ChoiceTooShort(\n                R.string.lockpattern_recording_incorrect_too_short,\n                LeftButtonMode.Retry, RightButtonMode.ContinueDisabled,\n                ID_EMPTY_MESSAGE, true),\n        FirstChoiceValid(\n                R.string.lockpattern_pattern_entered_header,\n                LeftButtonMode.Retry, RightButtonMode.Continue, ID_EMPTY_MESSAGE, false),\n        NeedToConfirm(\n                R.string.lockpattern_need_to_confirm,\n                LeftButtonMode.CancelDisabled, RightButtonMode.ConfirmDisabled,\n                ID_EMPTY_MESSAGE, true),\n        ConfirmWrong(\n                R.string.lockpattern_need_to_unlock_wrong,\n                LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled,\n                ID_EMPTY_MESSAGE, true),\n        ChoiceConfirmed(\n                R.string.lockpattern_pattern_confirmed_header,\n                LeftButtonMode.Cancel, RightButtonMode.Confirm, ID_EMPTY_MESSAGE, false);\n\n        final int headerMessage;\n\n        final LeftButtonMode leftMode;\n\n        final RightButtonMode rightMode;\n\n        final int footerMessage;\n\n        final boolean patternEnabled;\n\n        /**\n         * @param headerMessage  The message displayed at the top.\n         * @param leftMode       The mode of the left button.\n         * @param rightMode      The mode of the right button.\n         * @param footerMessage  The footer message.\n         * @param patternEnabled Whether the pattern widget is enabled.\n         */\n        Stage(int headerMessage,\n                LeftButtonMode leftMode,\n                RightButtonMode rightMode,\n                int footerMessage, boolean patternEnabled) {\n            this.headerMessage = headerMessage;\n            this.leftMode = leftMode;\n            this.rightMode = rightMode;\n            this.footerMessage = footerMessage;\n            this.patternEnabled = patternEnabled;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/ChooseLockPatternExample.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport com.liato.bankdroid.R;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.graphics.drawable.AnimationDrawable;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.view.View;\nimport android.widget.ImageView;\n\npublic class ChooseLockPatternExample extends Activity implements View.OnClickListener {\n\n    private static final int REQUESTCODE_CHOOSE = 1;\n\n    private static final long START_DELAY = 1000;\n\n    private View mNextButton;\n\n    private View mSkipButton;\n\n    private AnimationDrawable mAnimation;\n\n    private Runnable mRunnable = new Runnable() {\n        public void run() {\n            startAnimation(mAnimation);\n        }\n    };\n\n    private Handler mHandler = new Handler();\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.choose_lock_pattern_example);\n        initViews();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mHandler.postDelayed(mRunnable, START_DELAY);\n    }\n\n    @Override\n    protected void onPause() {\n        stopAnimation(mAnimation);\n        super.onPause();\n    }\n\n    public void onClick(View v) {\n        if (v == mSkipButton) {\n            // Canceling, so finish all\n            setResult(ChooseLockPattern.RESULT_FINISHED);\n            finish();\n        } else if (v == mNextButton) {\n            stopAnimation(mAnimation);\n            Intent intent = new Intent(this, ChooseLockPattern.class);\n            startActivityForResult(intent, REQUESTCODE_CHOOSE);\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == REQUESTCODE_CHOOSE && resultCode == ChooseLockPattern.RESULT_FINISHED) {\n            setResult(resultCode);\n            finish();\n        }\n    }\n\n    private void initViews() {\n        mNextButton = findViewById(R.id.next_button);\n        mNextButton.setOnClickListener(this);\n\n        mSkipButton = findViewById(R.id.skip_button);\n        mSkipButton.setOnClickListener(this);\n\n        View imageView = (ImageView) findViewById(R.id.lock_anim);\n        imageView.setBackgroundResource(R.drawable.lock_anim);\n        imageView.setOnClickListener(this);\n        mAnimation = (AnimationDrawable) imageView.getBackground();\n    }\n\n    protected void startAnimation(final AnimationDrawable animation) {\n        if (animation != null && !animation.isRunning()) {\n            animation.run();\n        }\n    }\n\n    protected void stopAnimation(final AnimationDrawable animation) {\n        if (animation != null && animation.isRunning()) {\n            animation.stop();\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/ChooseLockPatternTutorial.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport com.liato.bankdroid.R;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\n\npublic class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {\n\n    private static final int REQUESTCODE_EXAMPLE = 1;\n\n    private View mNextButton;\n\n    private View mSkipButton;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        // Don't show the tutorial if the user has seen it before.\n        LockPatternUtils lockPatternUtils = new LockPatternUtils(this);\n        if (savedInstanceState == null && lockPatternUtils.isPatternEverChosen()) {\n            Intent intent = new Intent();\n            intent.setClassName(\"com.android.settings\", \"com.android.settings.ChooseLockPattern\");\n            startActivity(intent);\n            finish();\n        } else {\n            initViews();\n        }\n    }\n\n    private void initViews() {\n        setContentView(R.layout.choose_lock_pattern_tutorial);\n        mNextButton = findViewById(R.id.next_button);\n        mNextButton.setOnClickListener(this);\n        mSkipButton = findViewById(R.id.skip_button);\n        mSkipButton.setOnClickListener(this);\n    }\n\n    public void onClick(View v) {\n        if (v == mSkipButton) {\n            // Canceling, so finish all\n            setResult(ChooseLockPattern.RESULT_FINISHED);\n            finish();\n        } else if (v == mNextButton) {\n            startActivityForResult(new Intent(this, ChooseLockPatternExample.class),\n                    REQUESTCODE_EXAMPLE);\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == REQUESTCODE_EXAMPLE && resultCode == ChooseLockPattern.RESULT_FINISHED) {\n            setResult(resultCode);\n            finish();\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/ConfirmLockPattern.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.R;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.CountDownTimer;\nimport android.os.SystemClock;\nimport android.view.KeyEvent;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.TextView;\n\nimport java.util.List;\n\n/**\n * Launch this when you want the user to confirm their lock pattern.\n *\n * Sets an activity result of {@link Activity#RESULT_OK} when the user\n * successfully confirmed their pattern.\n */\npublic class ConfirmLockPattern extends Activity {\n\n    /**\n     * Names of {@link CharSequence} fields within the originating {@link Intent}\n     * that are used to configure the keyguard confirmation view's labeling.\n     * The view will use the system-defined resource strings for any labels that\n     * the caller does not supply.\n     */\n    public static final String HEADER_TEXT = \"com.liato.bankdroid.header\";\n\n    public static final String FOOTER_TEXT = \"com.liato.bankdroid.footer\";\n\n    public static final String HEADER_WRONG_TEXT = \"com.liato.bankdroid.header_wrong\";\n\n    public static final String FOOTER_WRONG_TEXT = \"com.liato.bankdroid.footer_wrong\";\n\n    // how long we wait to clear a wrong pattern\n    private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;\n\n    private static final String KEY_NUM_WRONG_ATTEMPTS = \"num_wrong_attempts\";\n\n    private LockPatternView mLockPatternView;\n\n    private LockPatternUtils mLockPatternUtils;\n\n    private int mNumWrongConfirmAttempts;\n\n    private CountDownTimer mCountdownTimer;\n\n    private TextView mHeaderTextView;\n\n    private TextView mFooterTextView;\n\n    // caller-supplied text for various prompts\n    private CharSequence mHeaderText;\n\n    private CharSequence mFooterText;\n\n    private CharSequence mHeaderWrongText;\n\n    private CharSequence mFooterWrongText;\n\n    private Runnable mClearPatternRunnable = new Runnable() {\n        public void run() {\n            mLockPatternView.clearPattern();\n        }\n    };\n\n    /**\n     * The pattern listener that responds according to a user confirming\n     * an existing lock pattern.\n     */\n    private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener\n            = new LockPatternView.OnPatternListener() {\n\n        public void onPatternStart() {\n            mLockPatternView.removeCallbacks(mClearPatternRunnable);\n        }\n\n        public void onPatternCleared() {\n            mLockPatternView.removeCallbacks(mClearPatternRunnable);\n        }\n\n        public void onPatternDetected(List<LockPatternView.Cell> pattern) {\n            if (mLockPatternUtils.checkPattern(pattern)) {\n                setResult(RESULT_OK);\n                finish();\n            } else {\n                if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL &&\n                        ++mNumWrongConfirmAttempts\n                                >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {\n                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();\n                    handleAttemptLockout(deadline);\n                } else {\n                    updateStage(Stage.NeedToUnlockWrong);\n                    postClearPatternRunnable();\n                }\n            }\n        }\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        mLockPatternUtils = new LockPatternUtils(this);\n\n        requestWindowFeature(Window.FEATURE_NO_TITLE);\n        setContentView(R.layout.confirm_lock_pattern);\n\n        mHeaderTextView = (TextView) findViewById(R.id.headerText);\n        mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);\n        mFooterTextView = (TextView) findViewById(R.id.footerText);\n\n        // make it so unhandled touch events within the unlock screen go to the\n        // lock pattern view.\n        final LinearLayoutWithDefaultTouchRecepient topLayout\n                = (LinearLayoutWithDefaultTouchRecepient) findViewById(\n                R.id.topLayout);\n        topLayout.setDefaultTouchRecepient(mLockPatternView);\n\n        Intent intent = getIntent();\n        if (intent != null) {\n            mHeaderText = intent.getCharSequenceExtra(HEADER_TEXT);\n            mFooterText = intent.getCharSequenceExtra(FOOTER_TEXT);\n            mHeaderWrongText = intent.getCharSequenceExtra(HEADER_WRONG_TEXT);\n            mFooterWrongText = intent.getCharSequenceExtra(FOOTER_WRONG_TEXT);\n        }\n\n        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());\n        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());\n        mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);\n        updateStage(Stage.NeedToUnlock);\n\n        if (savedInstanceState != null) {\n            mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);\n        } else {\n            // on first launch, if no lock pattern is set, then finish with\n            // success (don't want user to get stuck confirming something that\n            // doesn't exist).\n            if (!mLockPatternUtils.savedPatternExists()) {\n                setResult(RESULT_OK);\n                finish();\n            }\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        // deliberately not calling super since we are managing this in full\n        outState.putInt(KEY_NUM_WRONG_ATTEMPTS, mNumWrongConfirmAttempts);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onPause() {\n        if (mCountdownTimer != null) {\n            mCountdownTimer.cancel();\n        }\n\n        super.onPause();\n    }\n\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_BACK) {\n            Intent homeIntent = new Intent(Intent.ACTION_MAIN);\n            homeIntent.addCategory(Intent.CATEGORY_HOME);\n            homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            startActivity(homeIntent);\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n        // if the user is currently locked out, enforce it.\n        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();\n        if (deadline != 0) {\n            handleAttemptLockout(deadline);\n        }\n    }\n\n    private void updateStage(Stage stage) {\n\n        switch (stage) {\n            case NeedToUnlock:\n                if (mHeaderText != null) {\n                    mHeaderTextView.setText(mHeaderText);\n                } else {\n                    mHeaderTextView.setText(R.string.lockpattern_need_to_unlock);\n                }\n                if (mFooterText != null) {\n                    mFooterTextView.setText(mFooterText);\n                } else {\n                    mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);\n                }\n\n                mLockPatternView.setEnabled(true);\n                mLockPatternView.enableInput();\n                break;\n            case NeedToUnlockWrong:\n                if (mHeaderWrongText != null) {\n                    mHeaderTextView.setText(mHeaderWrongText);\n                } else {\n                    mHeaderTextView.setText(R.string.lockpattern_need_to_unlock_wrong);\n                }\n                if (mFooterWrongText != null) {\n                    mFooterTextView.setText(mFooterWrongText);\n                } else {\n                    mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);\n                }\n\n                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);\n                mLockPatternView.setEnabled(true);\n                mLockPatternView.enableInput();\n                break;\n            case LockedOut:\n                mLockPatternView.clearPattern();\n                // enabled = false means: disable input, and have the\n                // appearance of being disabled.\n                mLockPatternView.setEnabled(false); // appearance of being disabled\n                break;\n        }\n    }\n\n    // clear the wrong pattern unless they have started a new one\n    // already\n    private void postClearPatternRunnable() {\n        mLockPatternView.removeCallbacks(mClearPatternRunnable);\n        mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);\n    }\n\n    private void handleAttemptLockout(long elapsedRealtimeDeadline) {\n        updateStage(Stage.LockedOut);\n        long elapsedRealtime = SystemClock.elapsedRealtime();\n        mCountdownTimer = new CountDownTimer(\n                elapsedRealtimeDeadline - elapsedRealtime,\n                LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {\n\n            @Override\n            public void onTick(long millisUntilFinished) {\n                mHeaderTextView\n                        .setText(R.string.lockpattern_too_many_failed_confirmation_attempts_header);\n                final int secondsCountdown = (int) (millisUntilFinished / 1000);\n                mFooterTextView.setText(getString(\n                        R.string.lockpattern_too_many_failed_confirmation_attempts_footer,\n                        secondsCountdown));\n            }\n\n            @Override\n            public void onFinish() {\n                mNumWrongConfirmAttempts = 0;\n                updateStage(Stage.NeedToUnlock);\n            }\n        }.start();\n    }\n\n    @Override\n    public void finish() {\n        Helpers.setActivityAnimation(this, R.anim.zoom_enter, R.anim.zoom_exit);\n        super.finish();\n    }\n\n    private enum Stage {\n        NeedToUnlock,\n        NeedToUnlockWrong,\n        LockedOut\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/LinearLayoutWithDefaultTouchRecepient.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport android.content.Context;\nimport android.graphics.Rect;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.widget.LinearLayout;\n\n\n/**\n * Like a normal linear layout, but supports dispatching all otherwise unhandled\n * touch events to a particular descendant.  This is for the unlock screen, so\n * that a wider range of touch events than just the lock pattern widget can kick\n * off a lock pattern if the finger is eventually dragged into the bounds of the\n * lock pattern view.\n */\npublic class LinearLayoutWithDefaultTouchRecepient extends LinearLayout {\n\n    private final Rect mTempRect = new Rect();\n\n    private View mDefaultTouchRecepient;\n\n    public LinearLayoutWithDefaultTouchRecepient(Context context) {\n        super(context);\n    }\n\n    public LinearLayoutWithDefaultTouchRecepient(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public void setDefaultTouchRecepient(View defaultTouchRecepient) {\n        mDefaultTouchRecepient = defaultTouchRecepient;\n    }\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n        if (mDefaultTouchRecepient == null) {\n            return super.dispatchTouchEvent(ev);\n        }\n\n        if (super.dispatchTouchEvent(ev)) {\n            return true;\n        }\n        mTempRect.set(0, 0, 0, 0);\n        offsetRectIntoDescendantCoords(mDefaultTouchRecepient, mTempRect);\n        ev.setLocation(ev.getX() + mTempRect.left, ev.getY() + mTempRect.top);\n        return mDefaultTouchRecepient.dispatchTouchEvent(ev);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/LockPatternUtils.java",
    "content": "/*\n * Copyright (C) 2007 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\nimport com.google.common.collect.Lists;\n\nimport com.liato.bankdroid.utils.StringUtils;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.os.SystemClock;\nimport android.preference.PreferenceManager;\nimport android.provider.Settings;\nimport android.text.TextUtils;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport timber.log.Timber;\n\n/**\n * Utilities for the lock patten and its settings.\n */\npublic class LockPatternUtils {\n\n    /**\n     * The maximum number of incorrect attempts before the user is prevented\n     * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.\n     */\n    public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;\n\n    /**\n     * The number of incorrect attempts before which we fall back on an alternative\n     * method of verifying the user, and resetting their lock pattern.\n     */\n    public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;\n\n    /**\n     * How long the user is prevented from trying again after entering the\n     * wrong pattern too many times.\n     */\n    public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;\n\n    /**\n     * The interval of the countdown for showing progress of the lockout.\n     */\n    public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;\n\n    /**\n     * The minimum number of dots in a valid pattern.\n     */\n    public static final int MIN_LOCK_PATTERN_SIZE = 4;\n\n    /**\n     * The minimum number of dots the user must include in a wrong pattern\n     * attempt for it to be counted against the counts that affect\n     * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}\n     */\n    public static final int MIN_PATTERN_REGISTER_FAIL = 3;\n\n    private static final String LOCK_PATTERN_FILE = \"gesture.key\";\n\n    private final static String LOCKOUT_PERMANENT_KEY = \"lockscreen.lockedoutpermanently\";\n\n    private final static String LOCKOUT_ATTEMPT_DEADLINE = \"lockscreen.lockoutattemptdeadline\";\n\n    private final static String PATTERN_EVER_CHOSEN = \"lockscreen.patterneverchosen\";\n\n    private static String sLockPatternFilename;\n\n    private static SharedPreferences mPrefs;\n\n    private final ContentResolver mContentResolver;\n\n    public LockPatternUtils(Context context) {\n        mContentResolver = context.getContentResolver();\n        mPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        // Initialize the location of gesture lock file\n        if (sLockPatternFilename == null) {\n            sLockPatternFilename = context.getFilesDir() + LOCK_PATTERN_FILE;\n            //sLockPatternFilename = android.os.Environment.getDataDirectory()\n            //        .getAbsolutePath() + LOCK_PATTERN_FILE;\n        }\n    }\n\n    /**\n     * Deserialize a pattern.\n     *\n     * @param string The pattern serialized with {@link #patternToString}\n     * @return The pattern.\n     */\n    public static List<LockPatternView.Cell> stringToPattern(String string) {\n        List<LockPatternView.Cell> result = Lists.newArrayList();\n\n        final byte[] bytes = StringUtils.getBytes(string);\n        for (int i = 0; i < bytes.length; i++) {\n            byte b = bytes[i];\n            result.add(LockPatternView.Cell.of(b / 3, b % 3));\n        }\n        return result;\n    }\n\n    /**\n     * Serialize a pattern.\n     *\n     * @param pattern The pattern.\n     * @return The pattern in string form.\n     */\n    public static String patternToString(List<LockPatternView.Cell> pattern) {\n        if (pattern == null) {\n            return \"\";\n        }\n        final int patternSize = pattern.size();\n\n        byte[] res = new byte[patternSize];\n        for (int i = 0; i < patternSize; i++) {\n            LockPatternView.Cell cell = pattern.get(i);\n            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());\n        }\n        return StringUtils.toString(res);\n    }\n\n    /*\n     * Generate an SHA-1 hash for the pattern. Not the most secure, but it is\n     * at least a second level of protection. First level is that the file\n     * is in a location only readable by the system process.\n     * @param pattern the gesture pattern.\n     * @return the hash of the pattern in a byte array.\n     */\n    static byte[] patternToHash(List<LockPatternView.Cell> pattern) {\n        if (pattern == null) {\n            return null;\n        }\n\n        final int patternSize = pattern.size();\n        byte[] res = new byte[patternSize];\n        for (int i = 0; i < patternSize; i++) {\n            LockPatternView.Cell cell = pattern.get(i);\n            res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());\n        }\n        try {\n            MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n            byte[] hash = md.digest(res);\n            return hash;\n        } catch (NoSuchAlgorithmException nsa) {\n            return res;\n        }\n    }\n\n    /**\n     * Check to see if a pattern matches the saved pattern.  If no pattern exists,\n     * always returns true.\n     *\n     * @param pattern The pattern to check.\n     * @return Whether the pattern matchees the stored one.\n     */\n    public boolean checkPattern(List<LockPatternView.Cell> pattern) {\n        try {\n            // Read all the bytes from the file\n            RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, \"r\");\n            final byte[] stored = new byte[(int) raf.length()];\n            int got = raf.read(stored, 0, stored.length);\n            raf.close();\n            if (got <= 0) {\n                return true;\n            }\n            // Compare the hash from the file with the entered pattern's hash\n            return Arrays.equals(stored, LockPatternUtils.patternToHash(pattern));\n        } catch (FileNotFoundException fnfe) {\n            return true;\n        } catch (IOException ioe) {\n            return true;\n        }\n    }\n\n    /**\n     * Check to see if the user has stored a lock pattern.\n     *\n     * @return Whether a saved pattern exists.\n     */\n    public boolean savedPatternExists() {\n        try {\n            // Check if we can read a byte from the file\n            RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, \"r\");\n            byte first = raf.readByte();\n            raf.close();\n            return true;\n        } catch (FileNotFoundException fnfe) {\n            return false;\n        } catch (IOException ioe) {\n            return false;\n        }\n    }\n\n    /**\n     * Return true if the user has ever chosen a pattern.  This is true even if the pattern is\n     * currently cleared.\n     *\n     * @return True if the user has ever chosen a pattern.\n     */\n    public boolean isPatternEverChosen() {\n        return getBoolean(PATTERN_EVER_CHOSEN);\n    }\n\n    /**\n     * Save a lock pattern.\n     *\n     * @param pattern The new pattern to save.\n     */\n    public void saveLockPattern(List<LockPatternView.Cell> pattern) {\n        if (pattern == null) {\n            Timber.d(\"Removing lock pattern\");\n        } else {\n            Timber.v(\"Saving lock pattern: %s\", LockPatternUtils.patternToString(pattern));\n        }\n        // Compute the hash\n        final byte[] hash = LockPatternUtils.patternToHash(pattern);\n        try {\n            // Write the hash to file\n            RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, \"rw\");\n            // Truncate the file if pattern is null, to clear the lock\n            if (pattern == null) {\n                raf.setLength(0);\n            } else {\n                raf.write(hash, 0, hash.length);\n            }\n            raf.close();\n            setBoolean(PATTERN_EVER_CHOSEN, true);\n        } catch (FileNotFoundException fnfe) {\n            // Cant do much, unless we want to fail over to using the settings provider\n            Timber.e(fnfe, \"Unable to save lock pattern to %s\", sLockPatternFilename);\n        } catch (IOException ioe) {\n            // Cant do much\n            Timber.e(ioe, \"Unable to save lock pattern to %s\", sLockPatternFilename);\n        }\n    }\n\n    /**\n     * @return Whether the lock pattern is enabled.\n     */\n    public boolean isLockPatternEnabled() {\n        return getBoolean(Settings.System.LOCK_PATTERN_ENABLED);\n    }\n\n    /**\n     * Set whether the lock pattern is enabled.\n     */\n    public void setLockPatternEnabled(boolean enabled) {\n        setBoolean(Settings.System.LOCK_PATTERN_ENABLED, enabled);\n    }\n\n    /**\n     * @return Whether the visible pattern is enabled.\n     */\n    public boolean isVisiblePatternEnabled() {\n        return getBoolean(Settings.System.LOCK_PATTERN_VISIBLE);\n    }\n\n    /**\n     * Set whether the visible pattern is enabled.\n     */\n    public void setVisiblePatternEnabled(boolean enabled) {\n        setBoolean(Settings.System.LOCK_PATTERN_VISIBLE, enabled);\n    }\n\n    /**\n     * @return Whether tactile feedback for the pattern is enabled.\n     */\n    public boolean isTactileFeedbackEnabled() {\n        return getBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);\n    }\n\n    /**\n     * Set whether tactile feedback for the pattern is enabled.\n     */\n    public void setTactileFeedbackEnabled(boolean enabled) {\n        setBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled);\n    }\n\n    /**\n     * Set and store the lockout deadline, meaning the user can't attempt his/her unlock\n     * pattern until the deadline has passed.\n     *\n     * @return the chosen deadline.\n     */\n    public long setLockoutAttemptDeadline() {\n        final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;\n        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);\n        return deadline;\n    }\n\n    /**\n     * @return The elapsed time in millis in the future when the user is allowed to\n     * attempt to enter his/her lock pattern, or 0 if the user is welcome to\n     * enter a pattern.\n     */\n    public long getLockoutAttemptDeadline() {\n        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);\n        final long now = SystemClock.elapsedRealtime();\n        if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {\n            return 0L;\n        }\n        return deadline;\n    }\n\n    /**\n     * @return Whether the user is permanently locked out until they verify their\n     * credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed\n     * attempts.\n     */\n    public boolean isPermanentlyLocked() {\n        return getBoolean(LOCKOUT_PERMANENT_KEY);\n    }\n\n    /**\n     * Set the state of whether the device is permanently locked, meaning the user\n     * must authenticate via other means.  If false, that means the user has gone\n     * out of permanent lock, so the existing (forgotten) lock pattern needs to\n     * be cleared.\n     *\n     * @param locked Whether the user is permanently locked out until they verify their\n     *               credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed\n     *               attempts.\n     */\n    public void setPermanentlyLocked(boolean locked) {\n        setBoolean(LOCKOUT_PERMANENT_KEY, locked);\n\n        if (!locked) {\n            setLockPatternEnabled(false);\n            saveLockPattern(null);\n        }\n    }\n\n    /**\n     * @return A formatted string of the next alarm (for showing on the lock screen),\n     * or null if there is no next alarm.\n     */\n    public String getNextAlarm() {\n        String nextAlarm = Settings.System.getString(mContentResolver,\n                Settings.System.NEXT_ALARM_FORMATTED);\n        if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {\n            return null;\n        }\n        return nextAlarm;\n    }\n\n    private boolean getBoolean(String systemSettingKey) {\n        return mPrefs.getBoolean(systemSettingKey, false);\n    }\n\n    private void setBoolean(String systemSettingKey, boolean enabled) {\n        Editor editor = mPrefs.edit();\n        editor.putBoolean(systemSettingKey, enabled);\n        editor.apply();\n    }\n\n    private long getLong(String systemSettingKey, long def) {\n        return mPrefs.getLong(systemSettingKey, def);\n    }\n\n    private void setLong(String systemSettingKey, long value) {\n        Editor editor = mPrefs.edit();\n        editor.putLong(systemSettingKey, value);\n        editor.apply();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/lockpattern/LockPatternView.java",
    "content": "/*\n * Copyright (C) 2007 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.lockpattern;\n\n\nimport com.liato.bankdroid.R;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.Rect;\nimport android.os.Debug;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.SystemClock;\nimport android.os.Vibrator;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Displays and detects the user's unlock attempt, which is a drag of a finger\n * across 9 regions of the screen.\n *\n * Is also capable of displaying a static pattern in \"in progress\", \"wrong\" or\n * \"correct\" states.\n */\npublic class LockPatternView extends View {\n\n    // TODO: make this common with PhoneWindow\n    static final int STATUS_BAR_HEIGHT = 25;\n\n    // Vibrator pattern for creating a tactile bump\n    private static final long[] VIBE_PATTERN = {0, 1, 40, 41};\n\n    private static final boolean PROFILE_DRAWING = false;\n\n    /**\n     * How many milliseconds we spend animating each circle of a lock pattern\n     * if the animating mode is set.  The entire animation should take this\n     * constant * the length of the pattern to complete.\n     */\n    private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;\n\n    private final Path mCurrentPath = new Path();\n\n    private final Rect mInvalidate = new Rect();\n\n    protected int mPaddingLeft;\n\n    protected int mPaddingRight;\n\n    protected int mPaddingTop;\n\n    protected int mPaddingBottom;\n\n    private boolean mDrawingProfilingStarted = false;\n\n    private Paint mPaint = new Paint();\n\n    private Paint mPathPaint = new Paint();\n\n    private OnPatternListener mOnPatternListener;\n\n    private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);\n\n    /**\n     * Lookup table for the circles of the pattern we are currently drawing.\n     * This will be the cells of the complete pattern unless we are animating,\n     * in which case we use this to hold the cells we are drawing for the in\n     * progress animation.\n     */\n    private boolean[][] mPatternDrawLookup = new boolean[3][3];\n\n    /**\n     * the in progress point:\n     * - during interaction: where the user's finger is\n     * - during animation: the current tip of the animating line\n     */\n    private float mInProgressX = -1;\n\n    private float mInProgressY = -1;\n\n    private long mAnimatingPeriodStart;\n\n    private DisplayMode mPatternDisplayMode = DisplayMode.Correct;\n\n    private boolean mInputEnabled = true;\n\n    private boolean mInStealthMode = false;\n\n    private boolean mTactileFeedbackEnabled = true;\n\n    private boolean mPatternInProgress = false;\n\n    private float mDiameterFactor = 0.5f;\n\n    private float mHitFactor = 0.6f;\n\n    private float mSquareWidth;\n\n    private float mSquareHeight;\n\n    private Bitmap mBitmapBtnDefault;\n\n    private Bitmap mBitmapBtnTouched;\n\n    private Bitmap mBitmapCircleDefault;\n\n    private Bitmap mBitmapCircleGreen;\n\n    private Bitmap mBitmapCircleRed;\n\n    private Bitmap mBitmapArrowGreenUp;\n\n    private Bitmap mBitmapArrowRedUp;\n\n    private int mBitmapWidth;\n\n    private int mBitmapHeight;\n\n\n    private Vibrator vibe; // Vibrator for creating tactile feedback\n\n    public LockPatternView(Context context) {\n        this(context, null);\n    }\n\n    public LockPatternView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        //vibe = new Vibrator();\n        vibe = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);\n\n        setClickable(true);\n\n        mPathPaint.setAntiAlias(true);\n        mPathPaint.setDither(true);\n        mPathPaint.setColor(Color.WHITE);   // TODO this should be from the style\n        mPathPaint.setAlpha(128);\n        mPathPaint.setStyle(Paint.Style.STROKE);\n        mPathPaint.setStrokeJoin(Paint.Join.ROUND);\n        mPathPaint.setStrokeCap(Paint.Cap.ROUND);\n\n        // lot's of bitmaps!\n\n        mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default);\n        mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched);\n        mBitmapCircleDefault = getBitmapFor(R.drawable.indicator_code_lock_point_area_default);\n\n        mBitmapCircleGreen = getBitmapFor(R.drawable.indicator_code_lock_point_area_green);\n        mBitmapCircleRed = getBitmapFor(R.drawable.indicator_code_lock_point_area_red);\n\n        mBitmapArrowGreenUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_green_up);\n        mBitmapArrowRedUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_red_up);\n\n        // we assume all bitmaps have the same size\n        mBitmapWidth = mBitmapBtnDefault.getWidth();\n        mBitmapHeight = mBitmapBtnDefault.getHeight();\n    }\n\n    private Bitmap getBitmapFor(int resId) {\n        return BitmapFactory.decodeResource(getContext().getResources(), resId);\n    }\n\n    /**\n     * @return Whether the view is in stealth mode.\n     */\n    public boolean isInStealthMode() {\n        return mInStealthMode;\n    }\n\n    /**\n     * Set whether the view is in stealth mode.  If true, there will be no\n     * visible feedback as the user enters the pattern.\n     *\n     * @param inStealthMode Whether in stealth mode.\n     */\n    public void setInStealthMode(boolean inStealthMode) {\n        mInStealthMode = inStealthMode;\n    }\n\n    /**\n     * @return Whether the view has tactile feedback enabled.\n     */\n    public boolean isTactileFeedbackEnabled() {\n        return mTactileFeedbackEnabled;\n    }\n\n    /**\n     * Set whether the view will use tactile feedback.  If true, there will be\n     * tactile feedback as the user enters the pattern.\n     *\n     * @param tactileFeedbackEnabled Whether tactile feedback is enabled\n     */\n    public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {\n        mTactileFeedbackEnabled = tactileFeedbackEnabled;\n    }\n\n    /**\n     * Set the call back for pattern detection.\n     *\n     * @param onPatternListener The call back.\n     */\n    public void setOnPatternListener(\n            OnPatternListener onPatternListener) {\n        mOnPatternListener = onPatternListener;\n    }\n\n    /**\n     * Set the pattern explicitely (rather than waiting for the user to input\n     * a pattern).\n     *\n     * @param displayMode How to display the pattern.\n     * @param pattern     The pattern.\n     */\n    public void setPattern(DisplayMode displayMode, List<Cell> pattern) {\n        mPattern.clear();\n        mPattern.addAll(pattern);\n        clearPatternDrawLookup();\n        for (Cell cell : pattern) {\n            mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true;\n        }\n\n        setDisplayMode(displayMode);\n    }\n\n    /**\n     * Set the display mode of the current pattern.  This can be useful, for\n     * instance, after detecting a pattern to tell this view whether change the\n     * in progress result to correct or wrong.\n     *\n     * @param displayMode The display mode.\n     */\n    public void setDisplayMode(DisplayMode displayMode) {\n        mPatternDisplayMode = displayMode;\n        if (displayMode == DisplayMode.Animate) {\n            if (mPattern.size() == 0) {\n                throw new IllegalStateException(\"you must have a pattern to \"\n                        + \"animate if you want to set the display mode to animate\");\n            }\n            mAnimatingPeriodStart = SystemClock.elapsedRealtime();\n            final Cell first = mPattern.get(0);\n            mInProgressX = getCenterXForColumn(first.getColumn());\n            mInProgressY = getCenterYForRow(first.getRow());\n            clearPatternDrawLookup();\n        }\n        invalidate();\n    }\n\n    /**\n     * Clear the pattern.\n     */\n    public void clearPattern() {\n        resetPattern();\n    }\n\n    /**\n     * Reset all pattern state.\n     */\n    private void resetPattern() {\n        mPattern.clear();\n        clearPatternDrawLookup();\n        mPatternDisplayMode = DisplayMode.Correct;\n        invalidate();\n    }\n\n    /**\n     * Clear the pattern lookup table.\n     */\n    private void clearPatternDrawLookup() {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                mPatternDrawLookup[i][j] = false;\n            }\n        }\n    }\n\n    /**\n     * Disable input (for instance when displaying a message that will\n     * timeout so user doesn't get view into messy state).\n     */\n    public void disableInput() {\n        mInputEnabled = false;\n    }\n\n    /**\n     * Enable input.\n     */\n    public void enableInput() {\n        mInputEnabled = true;\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        final int width = w - mPaddingLeft - mPaddingRight;\n        mSquareWidth = width / 3.0f;\n\n        final int height = h - mPaddingTop - mPaddingBottom;\n        mSquareHeight = height / 3.0f;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        final int width = MeasureSpec.getSize(widthMeasureSpec);\n        final int height = MeasureSpec.getSize(heightMeasureSpec);\n        final int squareSide = Math.min(width, height);\n        setMeasuredDimension(squareSide, squareSide);\n    }\n\n    /**\n     * Determines whether the point x, y will add a new point to the current\n     * pattern (in addition to finding the cell, also makes heuristic choices\n     * such as filling in gaps based on current pattern).\n     *\n     * @param x The x coordinate.\n     * @param y The y coordinate.\n     */\n    private Cell detectAndAddHit(float x, float y) {\n        final Cell cell = checkForNewHit(x, y);\n        if (cell != null) {\n\n            // check for gaps in existing pattern\n            Cell fillInGapCell = null;\n            final ArrayList<Cell> pattern = mPattern;\n            if (!pattern.isEmpty()) {\n                final Cell lastCell = pattern.get(pattern.size() - 1);\n                int dRow = cell.row - lastCell.row;\n                int dColumn = cell.column - lastCell.column;\n\n                int fillInRow = lastCell.row;\n                int fillInColumn = lastCell.column;\n\n                if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {\n                    fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);\n                }\n\n                if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {\n                    fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);\n                }\n\n                fillInGapCell = Cell.of(fillInRow, fillInColumn);\n            }\n\n            if (fillInGapCell != null &&\n                    !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {\n                addCellToPattern(fillInGapCell);\n            }\n            addCellToPattern(cell);\n            if (mTactileFeedbackEnabled) {\n                vibe.vibrate(VIBE_PATTERN, -1); // Generate tactile feedback\n            }\n            return cell;\n        }\n        return null;\n    }\n\n    private void addCellToPattern(Cell newCell) {\n        mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;\n        mPattern.add(newCell);\n    }\n\n    // helper method to find which cell a point maps to\n    private Cell checkForNewHit(float x, float y) {\n\n        final int rowHit = getRowHit(y);\n        if (rowHit < 0) {\n            return null;\n        }\n        final int columnHit = getColumnHit(x);\n        if (columnHit < 0) {\n            return null;\n        }\n\n        if (mPatternDrawLookup[rowHit][columnHit]) {\n            return null;\n        }\n        return Cell.of(rowHit, columnHit);\n    }\n\n    /**\n     * Helper method to find the row that y falls into.\n     *\n     * @param y The y coordinate\n     * @return The row that y falls in, or -1 if it falls in no row.\n     */\n    private int getRowHit(float y) {\n\n        final float squareHeight = mSquareHeight;\n        float hitSize = squareHeight * mHitFactor;\n\n        float offset = mPaddingTop + (squareHeight - hitSize) / 2f;\n        for (int i = 0; i < 3; i++) {\n\n            final float hitTop = offset + squareHeight * i;\n            if (y >= hitTop && y <= hitTop + hitSize) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * Helper method to find the column x fallis into.\n     *\n     * @param x The x coordinate.\n     * @return The column that x falls in, or -1 if it falls in no column.\n     */\n    private int getColumnHit(float x) {\n        final float squareWidth = mSquareWidth;\n        float hitSize = squareWidth * mHitFactor;\n\n        float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;\n        for (int i = 0; i < 3; i++) {\n\n            final float hitLeft = offset + squareWidth * i;\n            if (x >= hitLeft && x <= hitLeft + hitSize) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent motionEvent) {\n        if (!mInputEnabled || !isEnabled()) {\n            return false;\n        }\n\n        final float x = motionEvent.getX();\n        final float y = motionEvent.getY();\n        Cell hitCell;\n        switch (motionEvent.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                resetPattern();\n                hitCell = detectAndAddHit(x, y);\n                if (hitCell != null && mOnPatternListener != null) {\n                    mPatternInProgress = true;\n                    mPatternDisplayMode = DisplayMode.Correct;\n                    mOnPatternListener.onPatternStart();\n                } else if (mOnPatternListener != null) {\n                    mPatternInProgress = false;\n                    mOnPatternListener.onPatternCleared();\n                }\n                if (hitCell != null) {\n                    final float startX = getCenterXForColumn(hitCell.column);\n                    final float startY = getCenterYForRow(hitCell.row);\n\n                    final float widthOffset = mSquareWidth / 2f;\n                    final float heightOffset = mSquareHeight / 2f;\n\n                    invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),\n                            (int) (startX + widthOffset), (int) (startY + heightOffset));\n                }\n                mInProgressX = x;\n                mInProgressY = y;\n                if (PROFILE_DRAWING) {\n                    if (!mDrawingProfilingStarted) {\n                        Debug.startMethodTracing(\"LockPatternDrawing\");\n                        mDrawingProfilingStarted = true;\n                    }\n                }\n                return true;\n            case MotionEvent.ACTION_UP:\n                // report pattern detected\n                if (!mPattern.isEmpty() && mOnPatternListener != null) {\n                    mPatternInProgress = false;\n                    mOnPatternListener.onPatternDetected(mPattern);\n                    invalidate();\n                }\n                if (PROFILE_DRAWING) {\n                    if (mDrawingProfilingStarted) {\n                        Debug.stopMethodTracing();\n                        mDrawingProfilingStarted = false;\n                    }\n                }\n                return true;\n            case MotionEvent.ACTION_MOVE:\n                final int patternSizePreHitDetect = mPattern.size();\n                hitCell = detectAndAddHit(x, y);\n                final int patternSize = mPattern.size();\n                if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {\n                    mPatternInProgress = true;\n                    mOnPatternListener.onPatternStart();\n                }\n                // note current x and y for rubber banding of in progress\n                // patterns\n                final float dx = Math.abs(x - mInProgressX);\n                final float dy = Math.abs(y - mInProgressY);\n                if (dx + dy > mSquareWidth * 0.01f) {\n                    float oldX = mInProgressX;\n                    float oldY = mInProgressY;\n\n                    mInProgressX = x;\n                    mInProgressY = y;\n\n                    if (mPatternInProgress && patternSize > 0) {\n                        final ArrayList<Cell> pattern = mPattern;\n                        final float radius = mSquareWidth * mDiameterFactor * 0.5f;\n\n                        final Cell lastCell = pattern.get(patternSize - 1);\n\n                        float startX = getCenterXForColumn(lastCell.column);\n                        float startY = getCenterYForRow(lastCell.row);\n\n                        float left;\n                        float top;\n                        float right;\n                        float bottom;\n\n                        final Rect invalidateRect = mInvalidate;\n\n                        if (startX < x) {\n                            left = startX;\n                            right = x;\n                        } else {\n                            left = x;\n                            right = startX;\n                        }\n\n                        if (startY < y) {\n                            top = startY;\n                            bottom = y;\n                        } else {\n                            top = y;\n                            bottom = startY;\n                        }\n\n                        // Invalidate between the pattern's last cell and the current location\n                        invalidateRect.set((int) (left - radius), (int) (top - radius),\n                                (int) (right + radius), (int) (bottom + radius));\n\n                        if (startX < oldX) {\n                            left = startX;\n                            right = oldX;\n                        } else {\n                            left = oldX;\n                            right = startX;\n                        }\n\n                        if (startY < oldY) {\n                            top = startY;\n                            bottom = oldY;\n                        } else {\n                            top = oldY;\n                            bottom = startY;\n                        }\n\n                        // Invalidate between the pattern's last cell and the previous location\n                        invalidateRect.union((int) (left - radius), (int) (top - radius),\n                                (int) (right + radius), (int) (bottom + radius));\n\n                        // Invalidate between the pattern's new cell and the pattern's previous cell\n                        if (hitCell != null) {\n                            startX = getCenterXForColumn(hitCell.column);\n                            startY = getCenterYForRow(hitCell.row);\n\n                            if (patternSize >= 2) {\n                                // (re-using hitcell for old cell)\n                                hitCell = pattern.get(patternSize - 1 - (patternSize\n                                        - patternSizePreHitDetect));\n                                oldX = getCenterXForColumn(hitCell.column);\n                                oldY = getCenterYForRow(hitCell.row);\n\n                                if (startX < oldX) {\n                                    left = startX;\n                                    right = oldX;\n                                } else {\n                                    left = oldX;\n                                    right = startX;\n                                }\n\n                                if (startY < oldY) {\n                                    top = startY;\n                                    bottom = oldY;\n                                } else {\n                                    top = oldY;\n                                    bottom = startY;\n                                }\n                            } else {\n                                left = startX;\n                                right = startX;\n                                top = startY;\n                                bottom = startY;\n                            }\n\n                            final float widthOffset = mSquareWidth / 2f;\n                            final float heightOffset = mSquareHeight / 2f;\n\n                            invalidateRect.set((int) (left - widthOffset),\n                                    (int) (top - heightOffset), (int) (right + widthOffset),\n                                    (int) (bottom + heightOffset));\n                        }\n\n                        invalidate(invalidateRect);\n                    } else {\n                        invalidate();\n                    }\n                }\n                return true;\n            case MotionEvent.ACTION_CANCEL:\n                resetPattern();\n                if (mOnPatternListener != null) {\n                    mPatternInProgress = false;\n                    mOnPatternListener.onPatternCleared();\n                }\n                if (PROFILE_DRAWING) {\n                    if (mDrawingProfilingStarted) {\n                        Debug.stopMethodTracing();\n                        mDrawingProfilingStarted = false;\n                    }\n                }\n                return true;\n        }\n        return false;\n    }\n\n    private float getCenterXForColumn(int column) {\n        return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;\n    }\n\n    private float getCenterYForRow(int row) {\n        return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        final ArrayList<Cell> pattern = mPattern;\n        final int count = pattern.size();\n        final boolean[][] drawLookup = mPatternDrawLookup;\n\n        if (mPatternDisplayMode == DisplayMode.Animate) {\n\n            // figure out which circles to draw\n\n            // + 1 so we pause on complete pattern\n            final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;\n            final int spotInCycle = (int) (SystemClock.elapsedRealtime() -\n                    mAnimatingPeriodStart) % oneCycle;\n            final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;\n\n            clearPatternDrawLookup();\n            for (int i = 0; i < numCircles; i++) {\n                final Cell cell = pattern.get(i);\n                drawLookup[cell.getRow()][cell.getColumn()] = true;\n            }\n\n            // figure out in progress portion of ghosting line\n\n            final boolean needToUpdateInProgressPoint = numCircles > 0\n                    && numCircles < count;\n\n            if (needToUpdateInProgressPoint) {\n                final float percentageOfNextCircle =\n                        ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) /\n                                MILLIS_PER_CIRCLE_ANIMATING;\n\n                final Cell currentCell = pattern.get(numCircles - 1);\n                final float centerX = getCenterXForColumn(currentCell.column);\n                final float centerY = getCenterYForRow(currentCell.row);\n\n                final Cell nextCell = pattern.get(numCircles);\n                final float dx = percentageOfNextCircle *\n                        (getCenterXForColumn(nextCell.column) - centerX);\n                final float dy = percentageOfNextCircle *\n                        (getCenterYForRow(nextCell.row) - centerY);\n                mInProgressX = centerX + dx;\n                mInProgressY = centerY + dy;\n            }\n            // TODO: Infinite loop here...\n            invalidate();\n        }\n\n        final float squareWidth = mSquareWidth;\n        final float squareHeight = mSquareHeight;\n\n        float radius = (squareWidth * mDiameterFactor * 0.5f);\n        mPathPaint.setStrokeWidth(radius);\n\n        final Path currentPath = mCurrentPath;\n        currentPath.rewind();\n\n        // TODO: the path should be created and cached every time we hit-detect a cell\n        // only the last segment of the path should be computed here\n        // draw the path of the pattern (unless the user is in progress, and\n        // we are in stealth mode)\n        final boolean drawPath = (!mInStealthMode || mPatternDisplayMode == DisplayMode.Wrong);\n        if (drawPath) {\n            boolean anyCircles = false;\n            for (int i = 0; i < count; i++) {\n                Cell cell = pattern.get(i);\n\n                // only draw the part of the pattern stored in\n                // the lookup table (this is only different in the case\n                // of animation).\n                if (!drawLookup[cell.row][cell.column]) {\n                    break;\n                }\n                anyCircles = true;\n\n                float centerX = getCenterXForColumn(cell.column);\n                float centerY = getCenterYForRow(cell.row);\n                if (i == 0) {\n                    currentPath.moveTo(centerX, centerY);\n                } else {\n                    currentPath.lineTo(centerX, centerY);\n                }\n            }\n\n            // add last in progress section\n            if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)\n                    && anyCircles) {\n                currentPath.lineTo(mInProgressX, mInProgressY);\n            }\n            canvas.drawPath(currentPath, mPathPaint);\n        }\n\n        // draw the circles\n        final int paddingTop = mPaddingTop;\n        final int paddingLeft = mPaddingLeft;\n\n        for (int i = 0; i < 3; i++) {\n            float topY = paddingTop + i * squareHeight;\n            //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);\n            for (int j = 0; j < 3; j++) {\n                float leftX = paddingLeft + j * squareWidth;\n                drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);\n            }\n        }\n\n        // draw the arrows associated with the path (unless the user is in progress, and\n        // we are in stealth mode)\n        boolean oldFlag = (mPaint.getFlags() & Paint.FILTER_BITMAP_FLAG) != 0;\n        mPaint.setFilterBitmap(true); // draw with higher quality since we render with transforms\n        if (drawPath) {\n            for (int i = 0; i < count - 1; i++) {\n                Cell cell = pattern.get(i);\n                Cell next = pattern.get(i + 1);\n\n                // only draw the part of the pattern stored in\n                // the lookup table (this is only different in the case\n                // of animation).\n                if (!drawLookup[next.row][next.column]) {\n                    break;\n                }\n\n                float leftX = paddingLeft + cell.column * squareWidth;\n                float topY = paddingTop + cell.row * squareHeight;\n\n                drawArrow(canvas, leftX, topY, cell, next);\n            }\n        }\n        mPaint.setFilterBitmap(oldFlag); // restore default flag\n    }\n\n    private void drawArrow(Canvas canvas, float leftX, float topY, Cell start, Cell end) {\n        boolean green = mPatternDisplayMode != DisplayMode.Wrong;\n\n        final int endRow = end.row;\n        final int startRow = start.row;\n        final int endColumn = end.column;\n        final int startColumn = start.column;\n\n        // offsets for centering the bitmap in the cell\n        final int offsetX = ((int) mSquareWidth - mBitmapWidth) / 2;\n        final int offsetY = ((int) mSquareHeight - mBitmapHeight) / 2;\n\n        // compute transform to place arrow bitmaps at correct angle inside circle.\n        // This assumes that the arrow image is drawn at 12:00 with it's top edge\n        // coincident with the circle bitmap's top edge.\n        Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;\n        Matrix matrix = new Matrix();\n        final int cellWidth = mBitmapCircleDefault.getWidth();\n        final int cellHeight = mBitmapCircleDefault.getHeight();\n\n        // the up arrow bitmap is at 12:00, so find the rotation from x axis and add 90 degrees.\n        final float theta = (float) Math.atan2(\n                (double) (endRow - startRow), (double) (endColumn - startColumn));\n        final float angle = (float) Math.toDegrees(theta) + 90.0f;\n\n        // compose matrix\n        matrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position\n        matrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f);  // rotate about cell center\n        matrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos\n        canvas.drawBitmap(arrow, matrix, mPaint);\n    }\n\n    /**\n     * @param partOfPattern Whether this circle is part of the pattern.\n     */\n    private void drawCircle(Canvas canvas, int leftX, int topY, boolean partOfPattern) {\n        Bitmap outerCircle;\n        Bitmap innerCircle;\n\n        if (!partOfPattern || (mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)) {\n            // unselected circle\n            outerCircle = mBitmapCircleDefault;\n            innerCircle = mBitmapBtnDefault;\n        } else if (mPatternInProgress) {\n            // user is in middle of drawing a pattern\n            outerCircle = mBitmapCircleGreen;\n            innerCircle = mBitmapBtnTouched;\n        } else if (mPatternDisplayMode == DisplayMode.Wrong) {\n            // the pattern is wrong\n            outerCircle = mBitmapCircleRed;\n            innerCircle = mBitmapBtnDefault;\n        } else if (mPatternDisplayMode == DisplayMode.Correct ||\n                mPatternDisplayMode == DisplayMode.Animate) {\n            // the pattern is correct\n            outerCircle = mBitmapCircleGreen;\n            innerCircle = mBitmapBtnDefault;\n        } else {\n            throw new IllegalStateException(\"unknown display mode \" + mPatternDisplayMode);\n        }\n\n        final int width = mBitmapWidth;\n        final int height = mBitmapHeight;\n\n        final float squareWidth = mSquareWidth;\n        final float squareHeight = mSquareHeight;\n\n        int offsetX = (int) ((squareWidth - width) / 2f);\n        int offsetY = (int) ((squareHeight - height) / 2f);\n\n        canvas.drawBitmap(outerCircle, leftX + offsetX, topY + offsetY, mPaint);\n        canvas.drawBitmap(innerCircle, leftX + offsetX, topY + offsetY, mPaint);\n    }\n\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n        return new SavedState(superState,\n                LockPatternUtils.patternToString(mPattern),\n                mPatternDisplayMode.ordinal(),\n                mInputEnabled, mInStealthMode, mTactileFeedbackEnabled);\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        final SavedState ss = (SavedState) state;\n        super.onRestoreInstanceState(ss.getSuperState());\n        setPattern(\n                DisplayMode.Correct,\n                LockPatternUtils.stringToPattern(ss.getSerializedPattern()));\n        mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];\n        mInputEnabled = ss.isInputEnabled();\n        mInStealthMode = ss.isInStealthMode();\n        mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled();\n    }\n\n    /**\n     * How to display the current pattern.\n     */\n    public enum DisplayMode {\n\n        /**\n         * The pattern drawn is correct (i.e draw it in a friendly color)\n         */\n        Correct,\n\n        /**\n         * Animate the pattern (for demo, and help).\n         */\n        Animate,\n\n        /**\n         * The pattern is wrong (i.e draw a foreboding color)\n         */\n        Wrong\n    }\n\n    /**\n     * The call back interface for detecting patterns entered by the user.\n     */\n    public interface OnPatternListener {\n\n        /**\n         * A new pattern has begun.\n         */\n        void onPatternStart();\n\n        /**\n         * The pattern was cleared.\n         */\n        void onPatternCleared();\n\n        /**\n         * A pattern was detected from the user.\n         *\n         * @param pattern The pattern.\n         */\n        void onPatternDetected(List<Cell> pattern);\n    }\n\n    /**\n     * Represents a cell in the 3 X 3 matrix of the unlock pattern view.\n     */\n    public static class Cell {\n\n        // keep # objects limited to 9\n        static Cell[][] sCells = new Cell[3][3];\n\n        static {\n            for (int i = 0; i < 3; i++) {\n                for (int j = 0; j < 3; j++) {\n                    sCells[i][j] = new Cell(i, j);\n                }\n            }\n        }\n\n        int row;\n\n        int column;\n\n        /**\n         * @param row    The row of the cell.\n         * @param column The column of the cell.\n         */\n        private Cell(int row, int column) {\n            checkRange(row, column);\n            this.row = row;\n            this.column = column;\n        }\n\n        /**\n         * @param row    The row of the cell.\n         * @param column The column of the cell.\n         */\n        public static synchronized Cell of(int row, int column) {\n            checkRange(row, column);\n            return sCells[row][column];\n        }\n\n        private static void checkRange(int row, int column) {\n            if (row < 0 || row > 2) {\n                throw new IllegalArgumentException(\"row must be in range 0-2\");\n            }\n            if (column < 0 || column > 2) {\n                throw new IllegalArgumentException(\"column must be in range 0-2\");\n            }\n        }\n\n        public int getRow() {\n            return row;\n        }\n\n        public int getColumn() {\n            return column;\n        }\n\n        public String toString() {\n            return \"(row=\" + row + \",clmn=\" + column + \")\";\n        }\n    }\n\n    /**\n     * The parecelable for saving and restoring a lock pattern view.\n     */\n    private static class SavedState extends BaseSavedState {\n\n        public static final Parcelable.Creator<SavedState> CREATOR =\n                new Creator<SavedState>() {\n                    public SavedState createFromParcel(Parcel in) {\n                        return new SavedState(in);\n                    }\n\n                    public SavedState[] newArray(int size) {\n                        return new SavedState[size];\n                    }\n                };\n\n        private final String mSerializedPattern;\n\n        private final int mDisplayMode;\n\n        private final boolean mInputEnabled;\n\n        private final boolean mInStealthMode;\n\n        private final boolean mTactileFeedbackEnabled;\n\n        /**\n         * Constructor called from {@link LockPatternView#onSaveInstanceState()}\n         */\n        private SavedState(Parcelable superState, String serializedPattern, int displayMode,\n                boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {\n            super(superState);\n            mSerializedPattern = serializedPattern;\n            mDisplayMode = displayMode;\n            mInputEnabled = inputEnabled;\n            mInStealthMode = inStealthMode;\n            mTactileFeedbackEnabled = tactileFeedbackEnabled;\n        }\n\n        /**\n         * Constructor called from {@link #CREATOR}\n         */\n        private SavedState(Parcel in) {\n            super(in);\n            mSerializedPattern = in.readString();\n            mDisplayMode = in.readInt();\n            mInputEnabled = (Boolean) in.readValue(null);\n            mInStealthMode = (Boolean) in.readValue(null);\n            mTactileFeedbackEnabled = (Boolean) in.readValue(null);\n        }\n\n        public String getSerializedPattern() {\n            return mSerializedPattern;\n        }\n\n        public int getDisplayMode() {\n            return mDisplayMode;\n        }\n\n        public boolean isInputEnabled() {\n            return mInputEnabled;\n        }\n\n        public boolean isInStealthMode() {\n            return mInStealthMode;\n        }\n\n        public boolean isTactileFeedbackEnabled() {\n            return mTactileFeedbackEnabled;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            super.writeToParcel(dest, flags);\n            dest.writeString(mSerializedPattern);\n            dest.writeInt(mDisplayMode);\n            dest.writeValue(mInputEnabled);\n            dest.writeValue(mInStealthMode);\n            dest.writeValue(mTactileFeedbackEnabled);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/provider/BankTransactionsProvider.java",
    "content": "/*\n * Copyright (C) 2010 Magnusart <http://www.magnusart.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.provider;\n\nimport com.liato.bankdroid.db.DatabaseHelper;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteQueryBuilder;\nimport android.net.Uri;\nimport android.preference.PreferenceManager;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport timber.log.Timber;\n\n/**\n * <p>\n * This is the implementation of the BankTransactionsProvider. It provides\n * access to the transaction data for specific banks.\n * </p>\n *\n * @author Magnus Andersson\n * @see IBankTransactionsProvider\n * @since 8 jan 2011\n */\npublic class BankTransactionsProvider extends ContentProvider implements\n        IBankTransactionsProvider {\n\n    private static final String CONTENT_PROVIDER_ENABLED = \"content_provider_enabled\";\n\n    private static final String CONTENT_PROVIDER_API_KEY = \"content_provider_api_key\";\n\n    private final static int TRANSACTIONS = 0;\n\n    private final static int BANK_ACCOUNTS = 1;\n\n    private static final String WILD_CARD = \"*\";\n\n    private static final String BANK_TABLE = \"banks\";\n\n    private static final String ACCOUNT_TABLE = \"accounts\";\n\n    private static final String BANK_ACCOUNT_TABLES = BANK_TABLE + \" LEFT JOIN \" + ACCOUNT_TABLE\n            + \" ON banks.\"\n            + BANK_ID + \" = accounts.bankid\";\n\n    private static final String TRANSACTIONS_TABLE = \"transactions\";\n\n    private final static UriMatcher URI_MATCHER;\n\n    private final static Map<String, String> BANK_ACCOUNT_PROJECTION_MAP;\n\n    private final static Map<String, String> TRANS_PROJECTION_MAP;\n\n    static {\n        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);\n        URI_MATCHER.addURI(AUTHORITY, TRANSACTIONS_CAT + \"/\" + WILD_CARD,\n                TRANSACTIONS);\n        URI_MATCHER.addURI(AUTHORITY, BANK_ACCOUNTS_CAT + \"/\" + WILD_CARD,\n                BANK_ACCOUNTS);\n\n        // Projections are \"Poor mans views\" of the data.\n        BANK_ACCOUNT_PROJECTION_MAP = new HashMap<String, String>();\n\n        // Must match bankAccountProjection in\n        // IBankTransactionsProvider#bankAccountProjection\n        BANK_ACCOUNT_PROJECTION_MAP.put(BANK_ID, BANK_ID);\n        BANK_ACCOUNT_PROJECTION_MAP.put(BANK_NAME, BANK_NAME);\n        BANK_ACCOUNT_PROJECTION_MAP.put(BANK_TYPE, BANK_TYPE);\n        BANK_ACCOUNT_PROJECTION_MAP.put(BANK_LAST_UPDATED, BANK_LAST_UPDATED);\n        BANK_ACCOUNT_PROJECTION_MAP.put(ACC_ID, ACC_ID);\n        BANK_ACCOUNT_PROJECTION_MAP.put(ACC_NAME, ACC_NAME);\n        // Table name has to be explicitly included here since Banks also have a column named balance.\n        BANK_ACCOUNT_PROJECTION_MAP.put(ACC_BALANCE, ACCOUNT_TABLE + \".\" + ACC_BALANCE);\n        BANK_ACCOUNT_PROJECTION_MAP.put(ACC_TYPE, ACC_TYPE);\n\n        TRANS_PROJECTION_MAP = new HashMap<String, String>();\n\n        // Must match transactionProjection in\n        // IBankTransactionsProvider#transactionProjection\n        TRANS_PROJECTION_MAP.put(TRANS_ID, TRANS_ID);\n        TRANS_PROJECTION_MAP.put(TRANS_DATE, TRANS_DATE);\n        TRANS_PROJECTION_MAP.put(TRANS_DESC, TRANS_DESC);\n        TRANS_PROJECTION_MAP.put(TRANS_AMT, TRANS_AMT);\n        TRANS_PROJECTION_MAP.put(TRANS_CUR, TRANS_CUR);\n        TRANS_PROJECTION_MAP.put(TRANS_ACCNT, TRANS_ACCNT);\n    }\n\n    private DatabaseHelper dbHelper;\n\n    public static String getApiKey(final Context ctx) {\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(ctx);\n        if (!prefs.getBoolean(CONTENT_PROVIDER_ENABLED, false)) {\n            throw new IllegalStateException(\n                    \"Access to Content Provider is not enabled.\");\n        }\n\n        final String apiKey = prefs.getString(CONTENT_PROVIDER_API_KEY, \"\");\n\n        if (apiKey.equals(\"\")) {\n            throw new IllegalArgumentException(\"The API-Key must be set.\");\n        }\n\n        return apiKey;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int delete(final Uri uri, final String selection,\n            final String[] selectionArgs) {\n        throw new UnsupportedOperationException(\n                \"This provider does not implement the delete method\");\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String getType(final Uri uri) {\n        Timber.d(\"Got URI: %s\", uri.toString());\n\n        switch (URI_MATCHER.match(uri)) {\n            case BANK_ACCOUNTS:\n                return BANK_ACCOUNTS_MIME;\n            case TRANSACTIONS:\n                return TRANSACTIONS_MIME;\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI: \" + uri);\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Uri insert(final Uri uri, final ContentValues values) {\n        throw new UnsupportedOperationException(\n                \"This provider does not implement the insert method\");\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public boolean onCreate() {\n        dbHelper = DatabaseHelper.getHelper(getContext());\n        return true;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Cursor query(final Uri uri, final String[] projection,\n            final String selection, final String[] selectionArgs,\n            final String sortOrder) {\n\n        if (!isApiKeyEnabled(getContext())) {\n            return null;\n        }\n\n        final String apiKey = uri.getPathSegments().get(1);\n\n        Timber.v(\"Trying to access database with %s\", apiKey);\n\n        if (!apiKey.startsWith(API_KEY, 0)) {\n            return null;\n            // throw new IllegalArgumentException(API_KEY +\n            // \"<API-KEY> must be a part of the URI!\");\n        }\n\n        final String key = apiKey.replace(API_KEY, \"\");\n\n        if (!key.equals(getApiKey(getContext()))) {\n            return null;\n            // throw new\n            // IllegalAccessError(\"The supplied API_KEY does not exist\");\n        }\n\n        final SQLiteDatabase db = dbHelper.getReadableDatabase();\n        SQLiteQueryBuilder qb;\n\n        if (BANK_ACCOUNTS_MIME.equals(getType(uri))) {\n            qb = new SQLiteQueryBuilder();\n            qb.setTables(BANK_ACCOUNT_TABLES);\n            qb.setProjectionMap(BANK_ACCOUNT_PROJECTION_MAP);\n            qb.setDistinct(true);\n        } else if (TRANSACTIONS_MIME.equals(getType(uri))) {\n            qb = new SQLiteQueryBuilder();\n            qb.setTables(TRANSACTIONS_TABLE);\n            qb.setProjectionMap(TRANS_PROJECTION_MAP);\n        } else {\n            throw new IllegalArgumentException(\"Unsupported URI: \" + uri);\n        }\n\n        final Cursor cur = qb.query(db, projection, selection, selectionArgs,\n                null, null, sortOrder);\n\n        cur.setNotificationUri(getContext().getContentResolver(), uri);\n        return cur;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int update(final Uri uri, final ContentValues values,\n            final String selection, final String[] selectionArgs) {\n        throw new UnsupportedOperationException(\n                \"This provider does not implement the update method\");\n    }\n\n    private boolean isApiKeyEnabled(final Context ctx) {\n        final SharedPreferences prefs = PreferenceManager\n                .getDefaultSharedPreferences(ctx);\n        return prefs.getBoolean(CONTENT_PROVIDER_ENABLED, false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/utils/EmulatorUtils.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport android.os.Build;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.Set;\n\nclass EmulatorUtils {\n    static final boolean RUNNING_ON_EMULATOR = isRunningOnEmulator();\n    static final boolean RUNNING_ON_ANDROID = isRunningOnAndroid();\n\n    private EmulatorUtils() {\n    }\n\n    private static boolean isRunningOnEmulator() {\n        // Inspired by\n        // http://stackoverflow.com/questions/2799097/how-can-i-detect-when-an-android-application-is-running-in>\n        if (Build.PRODUCT == null) {\n            return false;\n        }\n\n        Set<String> parts = new HashSet<>(Arrays.asList(Build.PRODUCT.split(\"_\")));\n        if (parts.size() == 0) {\n            return false;\n        }\n\n        parts.remove(\"sdk\");\n        parts.remove(\"google\");\n        parts.remove(\"x86\");\n        parts.remove(\"64\");\n        parts.remove(\"phone\");\n\n        // If the build identifier contains only the above keywords in some order, then we're\n        // in an emulator\n        return parts.isEmpty();\n    }\n\n    private static boolean isRunningOnAndroid() {\n        // Inspired by:\n        // https://developer.android.com/reference/java/lang/System.html#getProperties()\n        // Developed using trial and error...\n        final Properties properties = System.getProperties();\n        final String httpAgent = (String) properties.get(\"http.agent\");\n        return httpAgent != null && httpAgent.contains(\"Android\");\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/utils/LoggingUtils.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport com.crashlytics.android.Crashlytics;\nimport com.crashlytics.android.answers.Answers;\nimport com.crashlytics.android.answers.CustomEvent;\nimport com.liato.bankdroid.BuildConfig;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport io.fabric.sdk.android.Fabric;\nimport timber.log.Timber;\n\npublic class LoggingUtils {\n\n    private static final boolean IS_CRASHLYTICS_ENABLED = isCrashlyticsEnabled();\n    private static final String DEFAULT_TAG = \"Bankdroid\";\n\n    private static Class<Timber> initializedLoggingClass = null;\n\n    private LoggingUtils() {\n    }\n\n    public static void createLogger(Context context) {\n       Timber.Tree tree =  IS_CRASHLYTICS_ENABLED ?\n               new CrashlyticsTree(context) :\n               new LocalTree();\n\n        if (initializedLoggingClass != Timber.class) {\n            initializedLoggingClass = Timber.class;\n            Timber.plant(tree);\n            Timber.v(\"Logging tree planted: %s\", tree.getClass());\n        }\n    }\n\n    private static boolean isCrashlyticsEnabled() {\n        return EmulatorUtils.RUNNING_ON_ANDROID &&\n                !EmulatorUtils.RUNNING_ON_EMULATOR;\n    }\n\n    public static void logCustom(CustomEvent event) {\n        if (!isCrashlyticsEnabled()) {\n            return;\n        }\n\n        event.putCustomAttribute(\"App Version\", BuildConfig.VERSION_NAME);\n        Answers.getInstance().logCustom(event);\n    }\n\n    public static void logDisabledBank(Bank bank) {\n        if (!isCrashlyticsEnabled()) {\n            return;\n        }\n\n        logCustom(new CustomEvent(\"Disabled Bank\").\n                putCustomAttribute(\"Name\", bank.getName()));\n    }\n\n    public static void logBankUpdate(Bank bank, boolean withTransactions) {\n        if (!isCrashlyticsEnabled()) {\n            return;\n        }\n\n        logCustom(new CustomEvent(\"Bank Updated\").\n                putCustomAttribute(\"Name\", bank.getName()).\n                putCustomAttribute(\"With Transactions\", Boolean.toString(withTransactions)));\n\n        boolean hasTransactions = false;\n        for (Account account : bank.getAccounts()) {\n            if (account.getTransactions() != null && !account.getTransactions().isEmpty()) {\n                hasTransactions = true;\n            }\n        }\n        if (withTransactions && !hasTransactions) {\n            logCustom(new CustomEvent(\"Bank Without Transactions\").\n                    putCustomAttribute(\"Name\", bank.getName()));\n        }\n    }\n\n    private static class CrashlyticsTree extends Timber.Tree {\n        CrashlyticsTree(Context context) {\n            Fabric.with(context, new Crashlytics());\n        }\n\n        @Override\n        protected void log(int priority, String tag, String message, Throwable t) {\n            if (BuildConfig.DEBUG) {\n                tag = \"DEBUG\";\n            } else if (TextUtils.isEmpty(tag)) {\n                tag = DEFAULT_TAG;\n            }\n\n            // This call logs to *both* Crashlytics and LogCat, and will log the Exception backtrace\n            // to LogCat on exceptions.\n            Crashlytics.log(priority, tag, message);\n\n            if (t != null) {\n                Crashlytics.logException(t);\n            }\n        }\n    }\n\n    private static class LocalTree extends Timber.Tree {\n        @Override\n        protected void log(int priority, String tag, String message, Throwable t) {\n            if (BuildConfig.DEBUG) {\n                tag = \"DEBUG\";\n            } else if (TextUtils.isEmpty(tag)) {\n                tag = DEFAULT_TAG;\n            }\n\n            // Empirical evidence shows any exception stack trace is already part of the message, so\n            // no need to print the exception explicitly here.\n            Log.println(priority, tag, message);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/liato/bankdroid/utils/NetworkUtils.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.SocketException;\nimport java.net.UnknownHostException;\n\npublic class NetworkUtils {\n\n    private NetworkUtils() {\n    }\n\n    public static boolean isInternetAvailable() {\n        return ping(new byte[]{8, 8, 8, 8}, 500);\n    }\n\n\n    private static boolean ping(byte[] ipAddress, int timeout) {\n        DatagramSocket datagramSocket = null;\n        try {\n            datagramSocket = new DatagramSocket();\n            datagramSocket.setSoTimeout(timeout);\n            datagramSocket.connect(InetAddress.getByAddress(ipAddress), 7);\n            if (datagramSocket.isConnected()) {\n                return true;\n            }\n        } catch (SocketException | UnknownHostException e) {\n            return false;\n        } finally {\n            if (datagramSocket != null) {\n                datagramSocket.close();\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/net/margaritov/preference/colorpicker/AlphaPatternDrawable.java",
    "content": "/*\n * Copyright (C) 2010 Daniel Nilsson\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage net.margaritov.preference.colorpicker;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\n\n/**\n * This drawable that draws a simple white and gray chessboard pattern.\n * It's pattern you will often see as a background behind a\n * partly transparent image in many applications.\n *\n * @author Daniel Nilsson\n */\npublic class AlphaPatternDrawable extends Drawable {\n\n    private int mRectangleSize = 10;\n\n    private Paint mPaint = new Paint();\n\n    private Paint mPaintWhite = new Paint();\n\n    private Paint mPaintGray = new Paint();\n\n    private int numRectanglesHorizontal;\n\n    private int numRectanglesVertical;\n\n    /**\n     * Bitmap in which the pattern will be cahched.\n     */\n    private Bitmap mBitmap;\n\n    public AlphaPatternDrawable(int rectangleSize) {\n        mRectangleSize = rectangleSize;\n        mPaintWhite.setColor(0xffffffff);\n        mPaintGray.setColor(0xffcbcbcb);\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n        canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);\n    }\n\n    @Override\n    public int getOpacity() {\n        return 0;\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        throw new UnsupportedOperationException(\"Alpha is not supported by this drawwable.\");\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter cf) {\n        throw new UnsupportedOperationException(\"ColorFilter is not supported by this drawwable.\");\n    }\n\n    @Override\n    protected void onBoundsChange(Rect bounds) {\n        super.onBoundsChange(bounds);\n\n        int height = bounds.height();\n        int width = bounds.width();\n\n        numRectanglesHorizontal = width / mRectangleSize;\n        numRectanglesVertical = height / mRectangleSize;\n\n        generatePatternBitmap();\n\n    }\n\n    /**\n     * This will generate a bitmap with the pattern\n     * as big as the rectangle we were allow to draw on.\n     * We do this to chache the bitmap so we don't need to\n     * recreate it each time draw() is called since it\n     * takes a few milliseconds.\n     */\n    private void generatePatternBitmap() {\n\n        if (getBounds().width() <= 0 || getBounds().height() <= 0) {\n            return;\n        }\n\n        mBitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);\n        Canvas canvas = new Canvas(mBitmap);\n\n        Rect r = new Rect();\n        boolean verticalStartWhite = true;\n        for (int i = 0; i <= numRectanglesVertical; i++) {\n\n            boolean isWhite = verticalStartWhite;\n            for (int j = 0; j <= numRectanglesHorizontal; j++) {\n\n                r.top = i * mRectangleSize;\n                r.left = j * mRectangleSize;\n                r.bottom = r.top + mRectangleSize;\n                r.right = r.left + mRectangleSize;\n\n                canvas.drawRect(r, isWhite ? mPaintWhite : mPaintGray);\n\n                isWhite = !isWhite;\n            }\n\n            verticalStartWhite = !verticalStartWhite;\n\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/net/margaritov/preference/colorpicker/ColorPickerDialog.java",
    "content": "/*\n * Copyright (C) 2010 Daniel Nilsson\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage net.margaritov.preference.colorpicker;\n\n\nimport com.liato.bankdroid.R;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.graphics.PixelFormat;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\n\npublic class ColorPickerDialog\n        extends\n        Dialog\n        implements\n        ColorPickerView.OnColorChangedListener,\n        View.OnClickListener {\n\n    private ColorPickerView mColorPicker;\n\n    private ColorPickerPanelView mNewColor;\n\n    private OnColorChangedListener mListener;\n\n    private final ViewGroup mParent;\n\n    public ColorPickerDialog(ViewGroup parent, Context context, int initialColor) {\n        super(context);\n\n        this.mParent = parent;\n\n        init(initialColor);\n    }\n\n    private void init(int color) {\n        // To fight color branding.\n        getWindow().setFormat(PixelFormat.RGBA_8888);\n\n        setUp(color);\n\n    }\n\n    private void setUp(int color) {\n\n        LayoutInflater inflater = (LayoutInflater) getContext()\n                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n\n        View layout = inflater.inflate(R.layout.dialog_color_picker, mParent, false);\n\n        setContentView(layout);\n\n        setTitle(R.string.dialog_color_picker);\n\n        mColorPicker = (ColorPickerView) layout.findViewById(R.id.color_picker_view);\n        ColorPickerPanelView oldColor = (ColorPickerPanelView) layout.findViewById(R.id.old_color_panel);\n        mNewColor = (ColorPickerPanelView) layout.findViewById(R.id.new_color_panel);\n\n        ((LinearLayout) oldColor.getParent()).setPadding(\n                Math.round(mColorPicker.getDrawingOffset()),\n                0,\n                Math.round(mColorPicker.getDrawingOffset()),\n                0\n        );\n\n        oldColor.setOnClickListener(this);\n        mNewColor.setOnClickListener(this);\n        mColorPicker.setOnColorChangedListener(this);\n        oldColor.setColor(color);\n        mColorPicker.setColor(color, true);\n\n    }\n\n    @Override\n    public void onColorChanged(int color) {\n\n        mNewColor.setColor(color);\n\n        /*\n                if (mListener != null) {\n            mListener.onColorChanged(color);\n        }\n        */\n\n    }\n\n    public void setAlphaSliderVisible(boolean visible) {\n        mColorPicker.setAlphaSliderVisible(visible);\n    }\n\n    /**\n     * Set a OnColorChangedListener to get notified when the color\n     * selected by the user has changed.\n     */\n    public void setOnColorChangedListener(OnColorChangedListener listener) {\n        mListener = listener;\n    }\n\n    public int getColor() {\n        return mColorPicker.getColor();\n    }\n\n    @Override\n    public void onClick(View v) {\n        if (v.getId() == R.id.new_color_panel) {\n            if (mListener != null) {\n                mListener.onColorChanged(mNewColor.getColor());\n            }\n        }\n        dismiss();\n    }\n\n    public interface OnColorChangedListener {\n\n        void onColorChanged(int color);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPanelView.java",
    "content": "/*\n * Copyright (C) 2010 Daniel Nilsson\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage net.margaritov.preference.colorpicker;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.util.AttributeSet;\nimport android.view.View;\n\n/**\n * This class draws a panel which which will be filled with a color which can be set.\n * It can be used to show the currently selected color which you will get from\n * the {@link ColorPickerView}.\n *\n * @author Daniel Nilsson\n */\npublic class ColorPickerPanelView extends View {\n\n    /**\n     * The width in pixels of the border\n     * surrounding the color panel.\n     */\n    private final static float BORDER_WIDTH_PX = 1;\n\n    private float mDensity = 1f;\n\n    private int mBorderColor = 0xff6E6E6E;\n\n    private int mColor = 0xff000000;\n\n    private Paint mBorderPaint;\n\n    private Paint mColorPaint;\n\n    private RectF mDrawingRect;\n\n    private RectF mColorRect;\n\n    private AlphaPatternDrawable mAlphaPattern;\n\n\n    public ColorPickerPanelView(Context context) {\n        this(context, null);\n    }\n\n    public ColorPickerPanelView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ColorPickerPanelView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init();\n    }\n\n    private void init() {\n        mBorderPaint = new Paint();\n        mColorPaint = new Paint();\n        mDensity = getContext().getResources().getDisplayMetrics().density;\n    }\n\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n\n        final RectF rect = mColorRect;\n\n        if (BORDER_WIDTH_PX > 0) {\n            mBorderPaint.setColor(mBorderColor);\n            canvas.drawRect(mDrawingRect, mBorderPaint);\n        }\n\n        if (mAlphaPattern != null) {\n            mAlphaPattern.draw(canvas);\n        }\n\n        mColorPaint.setColor(mColor);\n\n        canvas.drawRect(rect, mColorPaint);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int width = MeasureSpec.getSize(widthMeasureSpec);\n        int height = MeasureSpec.getSize(heightMeasureSpec);\n\n        setMeasuredDimension(width, height);\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n\n        mDrawingRect = new RectF();\n        mDrawingRect.left = getPaddingLeft();\n        mDrawingRect.right = w - getPaddingRight();\n        mDrawingRect.top = getPaddingTop();\n        mDrawingRect.bottom = h - getPaddingBottom();\n\n        setUpColorRect();\n\n    }\n\n    private void setUpColorRect() {\n        final RectF dRect = mDrawingRect;\n\n        float left = dRect.left + BORDER_WIDTH_PX;\n        float top = dRect.top + BORDER_WIDTH_PX;\n        float bottom = dRect.bottom - BORDER_WIDTH_PX;\n        float right = dRect.right - BORDER_WIDTH_PX;\n\n        mColorRect = new RectF(left, top, right, bottom);\n\n        mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity));\n\n        mAlphaPattern.setBounds(\n                Math.round(mColorRect.left),\n                Math.round(mColorRect.top),\n                Math.round(mColorRect.right),\n                Math.round(mColorRect.bottom)\n        );\n\n    }\n\n    /**\n     * Get the color currently show by this view.\n     */\n    public int getColor() {\n        return mColor;\n    }\n\n    /**\n     * Set the color that should be shown by this view.\n     */\n    public void setColor(int color) {\n        mColor = color;\n        invalidate();\n    }\n\n    /**\n     * Get the color of the border surrounding the panel.\n     */\n    public int getBorderColor() {\n        return mBorderColor;\n    }\n\n    /**\n     * Set the color of the border surrounding the panel.\n     */\n    public void setBorderColor(int color) {\n        mBorderColor = color;\n        invalidate();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPreference.java",
    "content": "/*\n * Copyright (C) 2011 Sergey Margaritov\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage net.margaritov.preference.colorpicker;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.Color;\nimport android.preference.Preference;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\n\nimport timber.log.Timber;\n\n/**\n * A preference type that allows a user to choose a time\n *\n * @author Sergey Margaritov\n */\npublic class ColorPickerPreference\n        extends\n        Preference\n        implements\n        Preference.OnPreferenceClickListener,\n        ColorPickerDialog.OnColorChangedListener {\n\n    private static final String ANDROID_NS = \"http://schemas.android.com/apk/res/android\";\n\n    private ViewGroup parent;\n\n    View mView;\n\n    int mDefaultValue = Color.BLACK;\n\n    private int mValue = Color.BLACK;\n\n    private float mDensity = 0;\n\n    private boolean mAlphaSliderEnabled = false;\n\n    public ColorPickerPreference(Context context) {\n        super(context);\n        init(context, null);\n    }\n\n    public ColorPickerPreference(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    public ColorPickerPreference(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init(context, attrs);\n    }\n\n    /**\n     * For custom purposes. Not used by ColorPickerPreferrence\n     *\n     * @author Unknown\n     */\n    public static String convertToARGB(int color) {\n        String alpha = Integer.toHexString(Color.alpha(color));\n        String red = Integer.toHexString(Color.red(color));\n        String green = Integer.toHexString(Color.green(color));\n        String blue = Integer.toHexString(Color.blue(color));\n\n        if (alpha.length() == 1) {\n            alpha = \"0\" + alpha;\n        }\n\n        if (red.length() == 1) {\n            red = \"0\" + red;\n        }\n\n        if (green.length() == 1) {\n            green = \"0\" + green;\n        }\n\n        if (blue.length() == 1) {\n            blue = \"0\" + blue;\n        }\n\n        return \"#\" + alpha + red + green + blue;\n    }\n\n    /**\n     * For custom purposes. Not used by ColorPickerPreferrence\n     *\n     * @author Unknown\n     */\n    public static int convertToColorInt(String argb) throws NumberFormatException {\n\n        if (argb.startsWith(\"#\")) {\n            argb = argb.replace(\"#\", \"\");\n        }\n\n        int alpha = -1, red = -1, green = -1, blue = -1;\n\n        if (argb.length() == 8) {\n            alpha = Integer.parseInt(argb.substring(0, 2), 16);\n            red = Integer.parseInt(argb.substring(2, 4), 16);\n            green = Integer.parseInt(argb.substring(4, 6), 16);\n            blue = Integer.parseInt(argb.substring(6, 8), 16);\n        } else if (argb.length() == 6) {\n            alpha = 255;\n            red = Integer.parseInt(argb.substring(0, 2), 16);\n            green = Integer.parseInt(argb.substring(2, 4), 16);\n            blue = Integer.parseInt(argb.substring(4, 6), 16);\n        }\n\n        return Color.argb(alpha, red, green, blue);\n    }\n\n    @Override\n    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {\n        onColorChanged(restoreValue ? getValue() : (Integer) defaultValue);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        mDensity = getContext().getResources().getDisplayMetrics().density;\n        setOnPreferenceClickListener(this);\n        if (attrs != null) {\n            String defaultValue = attrs.getAttributeValue(ANDROID_NS, \"defaultValue\");\n            if (defaultValue.startsWith(\"#\")) {\n                try {\n                    mDefaultValue = convertToColorInt(defaultValue);\n                } catch (NumberFormatException e) {\n                    Timber.w(\"Wrong color: %s\", defaultValue);\n                    mDefaultValue = convertToColorInt(\"#FF000000\");\n                }\n            } else {\n                int resourceId = attrs.getAttributeResourceValue(ANDROID_NS, \"defaultValue\", 0);\n                if (resourceId != 0) {\n                    mDefaultValue = context.getResources().getInteger(resourceId);\n                }\n            }\n            mAlphaSliderEnabled = attrs.getAttributeBooleanValue(null, \"alphaSlider\",\n                    false);\n        }\n        mValue = mDefaultValue;\n    }\n\n    @Override\n    protected View onCreateView(ViewGroup parent) {\n        this.parent = parent;\n        return super.onCreateView(parent);\n    }\n\n    @Override\n    protected void onBindView(View view) {\n        super.onBindView(view);\n        mView = view;\n        setPreviewColor();\n    }\n\n    private void setPreviewColor() {\n        if (mView == null) {\n            return;\n        }\n        ImageView iView = new ImageView(getContext());\n        LinearLayout widgetFrameView = ((LinearLayout) mView\n                .findViewById(android.R.id.widget_frame));\n        if (widgetFrameView == null) {\n            return;\n        }\n        widgetFrameView.setPadding(\n                widgetFrameView.getPaddingLeft(),\n                widgetFrameView.getPaddingTop(),\n                (int) (mDensity * 8),\n                widgetFrameView.getPaddingBottom()\n        );\n        // remove already create preview image\n        int count = widgetFrameView.getChildCount();\n        if (count > 0) {\n            widgetFrameView.removeViews(0, count);\n        }\n        widgetFrameView.setVisibility(View.VISIBLE);\n        widgetFrameView.addView(iView);\n        iView.setBackgroundDrawable(new AlphaPatternDrawable((int) (5 * mDensity)));\n        iView.setImageBitmap(getPreviewBitmap());\n    }\n\n    private Bitmap getPreviewBitmap() {\n        int d = (int) (mDensity * 31); //30dip\n        int color = getValue();\n        Bitmap bm = Bitmap.createBitmap(d, d, Config.ARGB_8888);\n        int w = bm.getWidth();\n        int h = bm.getHeight();\n        int c = color;\n        for (int i = 0; i < w; i++) {\n            for (int j = i; j < h; j++) {\n                c = (i <= 1 || j <= 1 || i >= w - 2 || j >= h - 2) ? Color.GRAY : color;\n                bm.setPixel(i, j, c);\n                if (i != j) {\n                    bm.setPixel(j, i, c);\n                }\n            }\n        }\n\n        return bm;\n    }\n\n    public int getValue() {\n        try {\n            if (isPersistent()) {\n                mValue = getPersistedInt(mDefaultValue);\n            }\n        } catch (ClassCastException e) {\n            mValue = mDefaultValue;\n        }\n\n        return mValue;\n    }\n\n    @Override\n    public void onColorChanged(int color) {\n        if (isPersistent()) {\n            persistInt(color);\n        }\n        mValue = color;\n        setPreviewColor();\n        OnPreferenceChangeListener listener = getOnPreferenceChangeListener();\n        if (listener != null) {\n            listener.onPreferenceChange(this, color);\n        }\n    }\n\n    @Override\n    public boolean onPreferenceClick(Preference preference) {\n        ColorPickerDialog picker = new ColorPickerDialog(parent, getContext(), getValue());\n        picker.setOnColorChangedListener(this);\n        if (mAlphaSliderEnabled) {\n            picker.setAlphaSliderVisible(true);\n        }\n        picker.show();\n\n        return false;\n    }\n\n    /**\n     * Toggle Alpha Slider visibility (by default it's disabled)\n     */\n    public void setAlphaSliderEnabled(boolean enable) {\n        mAlphaSliderEnabled = enable;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/net/margaritov/preference/colorpicker/ColorPickerView.java",
    "content": "/*\n * Copyright (C) 2010 Daniel Nilsson\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage net.margaritov.preference.colorpicker;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ComposeShader;\nimport android.graphics.LinearGradient;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Align;\nimport android.graphics.Paint.Style;\nimport android.graphics.Point;\nimport android.graphics.PorterDuff;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport android.graphics.Shader.TileMode;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\n\n/**\n * Displays a color picker to the user and allow them\n * to select a color. A slider for the alpha channel is\n * also available. Enable it by setting\n * setAlphaSliderVisible(boolean) to true.\n *\n * @author Daniel Nilsson\n */\npublic class ColorPickerView extends View {\n\n    private final static int PANEL_SAT_VAL = 0;\n\n    /*\n     * To remember which panel that has the \"focus\" when\n     * processing hardware button data.\n     */\n    private int mLastTouchedPanel = PANEL_SAT_VAL;\n\n    private final static int PANEL_HUE = 1;\n\n    private final static int PANEL_ALPHA = 2;\n\n    /**\n     * The width in pixels of the border\n     * surrounding all color panels.\n     */\n    private final static float BORDER_WIDTH_PX = 1;\n\n    /**\n     * The width in dp of the hue panel.\n     */\n    private float huePanelWidth = 30f;\n\n    /**\n     * The height in dp of the alpha panel\n     */\n    private float alphaPanelHeight = 20f;\n\n    /**\n     * The distance in dp between the different\n     * color panels.\n     */\n    private float panelSpacing = 10f;\n\n    /**\n     * The radius in dp of the color palette tracker circle.\n     */\n    private float paletteCircleTrackerRadius = 5f;\n\n    /**\n     * The dp which the tracker of the hue or alpha panel\n     * will extend outside of its bounds.\n     */\n    private float rectangleTrackerOffset = 2f;\n\n    private float mDensity = 1f;\n\n    private OnColorChangedListener mListener;\n\n    private Paint mSatValPaint;\n\n    private Paint mSatValTrackerPaint;\n\n    private Paint mHuePaint;\n\n    private Paint mHueTrackerPaint;\n\n    private Paint mAlphaPaint;\n\n    private Paint mAlphaTextPaint;\n\n    private Paint mBorderPaint;\n\n    private Shader mValShader;\n\n    private Shader mSatShader;\n\n    private Shader mHueShader;\n\n    private Shader mAlphaShader;\n\n    private int mAlpha = 0xff;\n\n    private float mHue = 360f;\n\n    private float mSat = 0f;\n\n    private float mVal = 0f;\n\n    private String mAlphaSliderText = \"\";\n\n    private int mSliderTrackerColor = 0xff1c1c1c;\n\n    private int mBorderColor = 0xff6E6E6E;\n\n    private boolean mShowAlphaPanel = false;\n\n    /**\n     * Offset from the edge we must have or else\n     * the finger tracker will get clipped when\n     * it is drawn outside of the view.\n     */\n    private float mDrawingOffset;\n\n\n    /*\n     * Distance form the edges of the view\n     * of where we are allowed to draw.\n     */\n    private RectF mDrawingRect;\n\n    private RectF mSatValRect;\n\n    private RectF mHueRect;\n\n    private RectF mAlphaRect;\n\n    private AlphaPatternDrawable mAlphaPattern;\n\n    private Point mStartTouchPoint = null;\n\n    public ColorPickerView(Context context) {\n        this(context, null);\n    }\n\n    public ColorPickerView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ColorPickerView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init();\n    }\n\n    private void init() {\n        if (Integer.parseInt(android.os.Build.VERSION.SDK) >= 11) {\n            setLayerType(View.LAYER_TYPE_SOFTWARE, null);\n        }\n        mDensity = getContext().getResources().getDisplayMetrics().density;\n        paletteCircleTrackerRadius *= mDensity;\n        rectangleTrackerOffset *= mDensity;\n        huePanelWidth *= mDensity;\n        alphaPanelHeight *= mDensity;\n        panelSpacing = panelSpacing * mDensity;\n\n        mDrawingOffset = calculateRequiredOffset();\n\n        initPaintTools();\n\n        //Needed for receiving trackball motion events.\n        setFocusable(true);\n        setFocusableInTouchMode(true);\n    }\n\n    private void initPaintTools() {\n\n        mSatValPaint = new Paint();\n        mSatValTrackerPaint = new Paint();\n        mHuePaint = new Paint();\n        mHueTrackerPaint = new Paint();\n        mAlphaPaint = new Paint();\n        mAlphaTextPaint = new Paint();\n        mBorderPaint = new Paint();\n\n        mSatValTrackerPaint.setStyle(Style.STROKE);\n        mSatValTrackerPaint.setStrokeWidth(2f * mDensity);\n        mSatValTrackerPaint.setAntiAlias(true);\n\n        mHueTrackerPaint.setColor(mSliderTrackerColor);\n        mHueTrackerPaint.setStyle(Style.STROKE);\n        mHueTrackerPaint.setStrokeWidth(2f * mDensity);\n        mHueTrackerPaint.setAntiAlias(true);\n\n        mAlphaTextPaint.setColor(0xff1c1c1c);\n        mAlphaTextPaint.setTextSize(14f * mDensity);\n        mAlphaTextPaint.setAntiAlias(true);\n        mAlphaTextPaint.setTextAlign(Align.CENTER);\n        mAlphaTextPaint.setFakeBoldText(true);\n\n\n    }\n\n    private float calculateRequiredOffset() {\n        float offset = Math.max(paletteCircleTrackerRadius, rectangleTrackerOffset);\n        offset = Math.max(offset, BORDER_WIDTH_PX * mDensity);\n\n        return offset * 1.5f;\n    }\n\n    private int[] buildHueColorArray() {\n\n        int[] hue = new int[361];\n\n        int count = 0;\n        for (int i = hue.length - 1; i >= 0; i--, count++) {\n            hue[count] = Color.HSVToColor(new float[]{i, 1f, 1f});\n        }\n\n        return hue;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n\n        if (mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) {\n            return;\n        }\n\n        drawSatValPanel(canvas);\n        drawHuePanel(canvas);\n        drawAlphaPanel(canvas);\n\n    }\n\n    private void drawSatValPanel(Canvas canvas) {\n\n        final RectF rect = mSatValRect;\n\n        if (BORDER_WIDTH_PX > 0) {\n            mBorderPaint.setColor(mBorderColor);\n            canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX,\n                    rect.bottom + BORDER_WIDTH_PX, mBorderPaint);\n        }\n\n        if (mValShader == null) {\n            mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,\n                    0xffffffff, 0xff000000, TileMode.CLAMP);\n        }\n\n        int rgb = Color.HSVToColor(new float[]{mHue, 1f, 1f});\n\n        mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,\n                0xffffffff, rgb, TileMode.CLAMP);\n        ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);\n        mSatValPaint.setShader(mShader);\n\n        canvas.drawRect(rect, mSatValPaint);\n\n        Point p = satValToPoint(mSat, mVal);\n\n        mSatValTrackerPaint.setColor(0xff000000);\n        canvas.drawCircle(p.x, p.y, paletteCircleTrackerRadius - 1f * mDensity,\n                mSatValTrackerPaint);\n\n        mSatValTrackerPaint.setColor(0xffdddddd);\n        canvas.drawCircle(p.x, p.y, paletteCircleTrackerRadius, mSatValTrackerPaint);\n\n    }\n\n    private void drawHuePanel(Canvas canvas) {\n\n        final RectF rect = mHueRect;\n\n        if (BORDER_WIDTH_PX > 0) {\n            mBorderPaint.setColor(mBorderColor);\n            canvas.drawRect(rect.left - BORDER_WIDTH_PX,\n                    rect.top - BORDER_WIDTH_PX,\n                    rect.right + BORDER_WIDTH_PX,\n                    rect.bottom + BORDER_WIDTH_PX,\n                    mBorderPaint);\n        }\n\n        if (mHueShader == null) {\n            mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,\n                    buildHueColorArray(), null, TileMode.CLAMP);\n            mHuePaint.setShader(mHueShader);\n        }\n\n        canvas.drawRect(rect, mHuePaint);\n\n        float rectHeight = 4 * mDensity / 2;\n\n        Point p = hueToPoint(mHue);\n\n        RectF r = new RectF();\n        r.left = rect.left - rectangleTrackerOffset;\n        r.right = rect.right + rectangleTrackerOffset;\n        r.top = p.y - rectHeight;\n        r.bottom = p.y + rectHeight;\n\n        canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);\n\n    }\n\n    private void drawAlphaPanel(Canvas canvas) {\n\n        if (!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) {\n            return;\n        }\n\n        final RectF rect = mAlphaRect;\n\n        if (BORDER_WIDTH_PX > 0) {\n            mBorderPaint.setColor(mBorderColor);\n            canvas.drawRect(rect.left - BORDER_WIDTH_PX,\n                    rect.top - BORDER_WIDTH_PX,\n                    rect.right + BORDER_WIDTH_PX,\n                    rect.bottom + BORDER_WIDTH_PX,\n                    mBorderPaint);\n        }\n\n        mAlphaPattern.draw(canvas);\n\n        float[] hsv = new float[]{mHue, mSat, mVal};\n        int color = Color.HSVToColor(hsv);\n        int acolor = Color.HSVToColor(0, hsv);\n\n        mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,\n                color, acolor, TileMode.CLAMP);\n\n        mAlphaPaint.setShader(mAlphaShader);\n\n        canvas.drawRect(rect, mAlphaPaint);\n\n        if (mAlphaSliderText != null && mAlphaSliderText != \"\") {\n            canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity,\n                    mAlphaTextPaint);\n        }\n\n        float rectWidth = 4 * mDensity / 2;\n\n        Point p = alphaToPoint(mAlpha);\n\n        RectF r = new RectF();\n        r.left = p.x - rectWidth;\n        r.right = p.x + rectWidth;\n        r.top = rect.top - rectangleTrackerOffset;\n        r.bottom = rect.bottom + rectangleTrackerOffset;\n\n        canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);\n\n    }\n\n    private Point hueToPoint(float hue) {\n\n        final RectF rect = mHueRect;\n        final float height = rect.height();\n\n        Point p = new Point();\n\n        p.y = (int) (height - (hue * height / 360f) + rect.top);\n        p.x = (int) rect.left;\n\n        return p;\n    }\n\n    private Point satValToPoint(float sat, float val) {\n\n        final RectF rect = mSatValRect;\n        final float height = rect.height();\n        final float width = rect.width();\n\n        Point p = new Point();\n\n        p.x = (int) (sat * width + rect.left);\n        p.y = (int) ((1f - val) * height + rect.top);\n\n        return p;\n    }\n\n    private Point alphaToPoint(int alpha) {\n\n        final RectF rect = mAlphaRect;\n        final float width = rect.width();\n\n        Point p = new Point();\n\n        p.x = (int) (width - (alpha * width / 0xff) + rect.left);\n        p.y = (int) rect.top;\n\n        return p;\n\n    }\n\n    private float[] pointToSatVal(float x, float y) {\n\n        final RectF rect = mSatValRect;\n        float[] result = new float[2];\n\n        float width = rect.width();\n        float height = rect.height();\n\n        if (x < rect.left) {\n            x = 0f;\n        } else if (x > rect.right) {\n            x = width;\n        } else {\n            x = x - rect.left;\n        }\n\n        if (y < rect.top) {\n            y = 0f;\n        } else if (y > rect.bottom) {\n            y = height;\n        } else {\n            y = y - rect.top;\n        }\n\n        result[0] = 1.f / width * x;\n        result[1] = 1.f - (1.f / height * y);\n\n        return result;\n    }\n\n    private float pointToHue(float y) {\n\n        final RectF rect = mHueRect;\n\n        float height = rect.height();\n\n        if (y < rect.top) {\n            y = 0f;\n        } else if (y > rect.bottom) {\n            y = height;\n        } else {\n            y = y - rect.top;\n        }\n\n        return 360f - (y * 360f / height);\n    }\n\n    private int pointToAlpha(int x) {\n\n        final RectF rect = mAlphaRect;\n        final int width = (int) rect.width();\n\n        if (x < rect.left) {\n            x = 0;\n        } else if (x > rect.right) {\n            x = width;\n        } else {\n            x = x - (int) rect.left;\n        }\n\n        return 0xff - (x * 0xff / width);\n\n    }\n\n    @Override\n    public boolean onTrackballEvent(MotionEvent event) {\n\n        float x = event.getX();\n        float y = event.getY();\n\n        boolean update = false;\n\n        if (event.getAction() == MotionEvent.ACTION_MOVE) {\n\n            switch (mLastTouchedPanel) {\n\n                case PANEL_SAT_VAL:\n\n                    float sat, val;\n\n                    sat = mSat + x / 50f;\n                    val = mVal - y / 50f;\n\n                    if (sat < 0f) {\n                        sat = 0f;\n                    } else if (sat > 1f) {\n                        sat = 1f;\n                    }\n\n                    if (val < 0f) {\n                        val = 0f;\n                    } else if (val > 1f) {\n                        val = 1f;\n                    }\n\n                    mSat = sat;\n                    mVal = val;\n\n                    update = true;\n\n                    break;\n\n                case PANEL_HUE:\n\n                    float hue = mHue - y * 10f;\n\n                    if (hue < 0f) {\n                        hue = 0f;\n                    } else if (hue > 360f) {\n                        hue = 360f;\n                    }\n\n                    mHue = hue;\n\n                    update = true;\n\n                    break;\n\n                case PANEL_ALPHA:\n\n                    if (!mShowAlphaPanel || mAlphaRect == null) {\n                        update = false;\n                    } else {\n\n                        int alpha = (int) (mAlpha - x * 10);\n\n                        if (alpha < 0) {\n                            alpha = 0;\n                        } else if (alpha > 0xff) {\n                            alpha = 0xff;\n                        }\n\n                        mAlpha = alpha;\n\n                        update = true;\n                    }\n\n                    break;\n            }\n\n\n        }\n\n        if (update) {\n\n            if (mListener != null) {\n                mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));\n            }\n\n            invalidate();\n            return true;\n        }\n\n        return super.onTrackballEvent(event);\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n\n        boolean update = false;\n\n        switch (event.getAction()) {\n\n            case MotionEvent.ACTION_DOWN:\n\n                mStartTouchPoint = new Point((int) event.getX(), (int) event.getY());\n\n                update = moveTrackersIfNeeded(event);\n\n                break;\n\n            case MotionEvent.ACTION_MOVE:\n\n                update = moveTrackersIfNeeded(event);\n\n                break;\n\n            case MotionEvent.ACTION_UP:\n\n                mStartTouchPoint = null;\n\n                update = moveTrackersIfNeeded(event);\n\n                break;\n\n        }\n\n        if (update) {\n\n            if (mListener != null) {\n                mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));\n            }\n\n            invalidate();\n            return true;\n        }\n\n        return super.onTouchEvent(event);\n    }\n\n    private boolean moveTrackersIfNeeded(MotionEvent event) {\n\n        if (mStartTouchPoint == null) {\n            return false;\n        }\n\n        boolean update = false;\n\n        int startX = mStartTouchPoint.x;\n        int startY = mStartTouchPoint.y;\n\n        if (mHueRect.contains(startX, startY)) {\n            mLastTouchedPanel = PANEL_HUE;\n\n            mHue = pointToHue(event.getY());\n\n            update = true;\n        } else if (mSatValRect.contains(startX, startY)) {\n\n            mLastTouchedPanel = PANEL_SAT_VAL;\n\n            float[] result = pointToSatVal(event.getX(), event.getY());\n\n            mSat = result[0];\n            mVal = result[1];\n\n            update = true;\n        } else if (mAlphaRect != null && mAlphaRect.contains(startX, startY)) {\n\n            mLastTouchedPanel = PANEL_ALPHA;\n\n            mAlpha = pointToAlpha((int) event.getX());\n\n            update = true;\n        }\n\n        return update;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int width = 0;\n        int height = 0;\n\n        int widthMode = MeasureSpec.getMode(widthMeasureSpec);\n        int heightMode = MeasureSpec.getMode(heightMeasureSpec);\n\n        int widthAllowed = MeasureSpec.getSize(widthMeasureSpec);\n        int heightAllowed = MeasureSpec.getSize(heightMeasureSpec);\n\n        widthAllowed = chooseWidth(widthMode, widthAllowed);\n        heightAllowed = chooseHeight(heightMode, heightAllowed);\n\n        if (!mShowAlphaPanel) {\n\n            height = (int) (widthAllowed - panelSpacing - huePanelWidth);\n\n            //If calculated height (based on the width) is more than the allowed height.\n            if (height > heightAllowed || getTag().equals(\"landscape\")) {\n                height = heightAllowed;\n                width = (int) (height + panelSpacing + huePanelWidth);\n            } else {\n                width = widthAllowed;\n            }\n        } else {\n\n            width = (int) (heightAllowed - alphaPanelHeight + huePanelWidth);\n\n            if (width > widthAllowed) {\n                width = widthAllowed;\n                height = (int) (widthAllowed - huePanelWidth + alphaPanelHeight);\n            } else {\n                height = heightAllowed;\n            }\n\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    private int chooseWidth(int mode, int size) {\n        if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {\n            return size;\n        } else { // (mode == MeasureSpec.UNSPECIFIED)\n            return getPrefferedWidth();\n        }\n    }\n\n    private int chooseHeight(int mode, int size) {\n        if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {\n            return size;\n        } else { // (mode == MeasureSpec.UNSPECIFIED)\n            return getPrefferedHeight();\n        }\n    }\n\n    private int getPrefferedWidth() {\n\n        int width = getPrefferedHeight();\n\n        if (mShowAlphaPanel) {\n            width -= (panelSpacing + alphaPanelHeight);\n        }\n\n        return (int) (width + huePanelWidth + panelSpacing);\n\n    }\n\n    private int getPrefferedHeight() {\n\n        int height = (int) (200 * mDensity);\n\n        if (mShowAlphaPanel) {\n            height += panelSpacing + alphaPanelHeight;\n        }\n\n        return height;\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n\n        mDrawingRect = new RectF();\n        mDrawingRect.left = mDrawingOffset + getPaddingLeft();\n        mDrawingRect.right = w - mDrawingOffset - getPaddingRight();\n        mDrawingRect.top = mDrawingOffset + getPaddingTop();\n        mDrawingRect.bottom = h - mDrawingOffset - getPaddingBottom();\n\n        setUpSatValRect();\n        setUpHueRect();\n        setUpAlphaRect();\n    }\n\n    private void setUpSatValRect() {\n\n        final RectF dRect = mDrawingRect;\n        float panelSide = dRect.height() - BORDER_WIDTH_PX * 2;\n\n        if (mShowAlphaPanel) {\n            panelSide -= panelSpacing + alphaPanelHeight;\n        }\n\n        float left = dRect.left + BORDER_WIDTH_PX;\n        float top = dRect.top + BORDER_WIDTH_PX;\n        float bottom = top + panelSide;\n        float right = left + panelSide;\n\n        mSatValRect = new RectF(left, top, right, bottom);\n    }\n\n    private void setUpHueRect() {\n        final RectF dRect = mDrawingRect;\n\n        float left = dRect.right - huePanelWidth + BORDER_WIDTH_PX;\n        float top = dRect.top + BORDER_WIDTH_PX;\n        float bottom = dRect.bottom - BORDER_WIDTH_PX - (mShowAlphaPanel ? (panelSpacing\n                + alphaPanelHeight) : 0);\n        float right = dRect.right - BORDER_WIDTH_PX;\n\n        mHueRect = new RectF(left, top, right, bottom);\n    }\n\n    private void setUpAlphaRect() {\n\n        if (!mShowAlphaPanel) {\n            return;\n        }\n\n        final RectF dRect = mDrawingRect;\n\n        float left = dRect.left + BORDER_WIDTH_PX;\n        float top = dRect.bottom - alphaPanelHeight + BORDER_WIDTH_PX;\n        float bottom = dRect.bottom - BORDER_WIDTH_PX;\n        float right = dRect.right - BORDER_WIDTH_PX;\n\n        mAlphaRect = new RectF(left, top, right, bottom);\n\n        mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity));\n        mAlphaPattern.setBounds(\n                Math.round(mAlphaRect.left),\n                Math.round(mAlphaRect.top),\n                Math.round(mAlphaRect.right),\n                Math.round(mAlphaRect.bottom)\n        );\n\n    }\n\n    /**\n     * Set a OnColorChangedListener to get notified when the color\n     * selected by the user has changed.\n     */\n    public void setOnColorChangedListener(OnColorChangedListener listener) {\n        mListener = listener;\n    }\n\n    /**\n     * Get the color of the border surrounding all panels.\n     */\n    public int getBorderColor() {\n        return mBorderColor;\n    }\n\n    /**\n     * Set the color of the border surrounding all panels.\n     */\n    public void setBorderColor(int color) {\n        mBorderColor = color;\n        invalidate();\n    }\n\n    /**\n     * Get the current color this view is showing.\n     *\n     * @return the current color.\n     */\n    public int getColor() {\n        return Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal});\n    }\n\n    /**\n     * Set the color the view should show.\n     *\n     * @param color The color that should be selected.\n     */\n    public void setColor(int color) {\n        setColor(color, false);\n    }\n\n    /**\n     * Set the color this view should show.\n     *\n     * @param color    The color that should be selected.\n     * @param callback If you want to get a callback to\n     *                 your OnColorChangedListener.\n     */\n    public void setColor(int color, boolean callback) {\n\n        int alpha = Color.alpha(color);\n        int red = Color.red(color);\n        int blue = Color.blue(color);\n        int green = Color.green(color);\n\n        float[] hsv = new float[3];\n\n        Color.RGBToHSV(red, green, blue, hsv);\n\n        mAlpha = alpha;\n        mHue = hsv[0];\n        mSat = hsv[1];\n        mVal = hsv[2];\n\n        if (callback && mListener != null) {\n            mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));\n        }\n\n        invalidate();\n    }\n\n    /**\n     * Get the drawing offset of the color picker view.\n     * The drawing offset is the distance from the side of\n     * a panel to the side of the view minus the padding.\n     * Useful if you want to have your own panel below showing\n     * the currently selected color and want to align it perfectly.\n     *\n     * @return The offset in pixels.\n     */\n    public float getDrawingOffset() {\n        return mDrawingOffset;\n    }\n\n    /**\n     * Set if the user is allowed to adjust the alpha panel. Default is false.\n     * If it is set to false no alpha will be set.\n     */\n    public void setAlphaSliderVisible(boolean visible) {\n\n        if (mShowAlphaPanel != visible) {\n            mShowAlphaPanel = visible;\n\n            /*\n                         * Reset all shader to force a recreation.\n             * Otherwise they will not look right after\n             * the size of the view has changed.\n             */\n            mValShader = null;\n            mSatShader = null;\n            mHueShader = null;\n            mAlphaShader = null;\n\n            requestLayout();\n        }\n\n    }\n\n    public int getSliderTrackerColor() {\n        return mSliderTrackerColor;\n    }\n\n    public void setSliderTrackerColor(int color) {\n        mSliderTrackerColor = color;\n\n        mHueTrackerPaint.setColor(mSliderTrackerColor);\n\n        invalidate();\n    }\n\n    /**\n     * Set the text that should be shown in the\n     * alpha slider. Set to null to disable text.\n     *\n     * @param res string resource id.\n     */\n    public void setAlphaSliderText(int res) {\n        String text = getContext().getString(res);\n        setAlphaSliderText(text);\n    }\n\n    /**\n     * Get the current value of the text\n     * that will be shown in the alpha\n     * slider.\n     */\n    public String getAlphaSliderText() {\n        return mAlphaSliderText;\n    }\n\n    /**\n     * Set the text that should be shown in the\n     * alpha slider. Set to null to disable text.\n     *\n     * @param text Text that should be shown.\n     */\n    public void setAlphaSliderText(String text) {\n        mAlphaSliderText = text;\n        invalidate();\n    }\n\n    public interface OnColorChangedListener {\n\n        void onColorChanged(int color);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/net/sf/andhsli/hotspotlogin/SimpleCrypto.java",
    "content": "/*\n * Copyright (c) 2009 Ferenc Hechler - ferenc_hechler@users.sourceforge.net\n * http://www.androidsnippets.org/snippets/39/index.html\n */\n\npackage net.sf.andhsli.hotspotlogin;\n\nimport com.liato.bankdroid.utils.StringUtils;\n\nimport java.security.SecureRandom;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\n\n/**\n * Usage:\n * <pre>\n * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext)\n * ...\n * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto)\n * </pre>\n *\n * @deprecated <a href=\"http://android-developers.blogspot.se/2016/06/security-crypto-provider-deprecated-in.html\">Broken\n * on Android Nougat</a>,\n * <a href=\"https://android.googlesource.com/platform/tools/base/+/2d252fc75960a3eaf7297c7a7713baf0c60b6aed/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CipherGetInstanceDetector.java#44\">considered\n * broken by Android Lint even before then</a>.\n *\n * @author ferenc.hechler\n */\npublic class SimpleCrypto {\n    public static String decrypt(String seed, String encrypted) throws Exception {\n        byte[] rawKey = getRawKey(StringUtils.getBytes(seed));\n        byte[] enc = toByte(encrypted);\n        byte[] result = decrypt(rawKey, enc);\n        return StringUtils.toString(result);\n    }\n\n    private static byte[] getRawKey(byte[] seed) throws Exception {\n        KeyGenerator kgen = KeyGenerator.getInstance(\"AES\");\n        SecureRandom sr;\n        if (android.os.Build.VERSION.SDK_INT >= 17) {\n            sr = SecureRandom.getInstance(\"SHA1PRNG\", \"Crypto\");\n        } else {\n            sr = SecureRandom.getInstance(\"SHA1PRNG\");\n        }\n        sr.setSeed(seed);\n        kgen.init(128, sr); // 192 and 256 bits may not be available\n        SecretKey skey = kgen.generateKey();\n        byte[] raw = skey.getEncoded();\n        return raw;\n    }\n\n    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {\n        SecretKeySpec skeySpec = new SecretKeySpec(raw, \"AES\");\n        Cipher cipher = Cipher.getInstance(\"AES\");\n        cipher.init(Cipher.DECRYPT_MODE, skeySpec);\n        byte[] decrypted = cipher.doFinal(encrypted);\n        return decrypted;\n    }\n\n    private static byte[] toByte(String hexString) {\n        int len = hexString.length() / 2;\n        byte[] result = new byte[len];\n        for (int i = 0; i < len; i++) {\n            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/anim/grow_from_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"0.3\" android:toXScale=\"1.0\"\n\t\tandroid:fromYScale=\"0.3\" android:toYScale=\"1.0\"\n\t\tandroid:pivotX=\"50%\" android:pivotY=\"100%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/decelerate_interpolator\"\n\t\tandroid:fromAlpha=\"0.0\" android:toAlpha=\"1.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/grow_from_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"0.3\" android:toXScale=\"1.0\"\n\t\tandroid:fromYScale=\"0.3\" android:toYScale=\"1.0\"\n\t\tandroid:pivotX=\"50%\" android:pivotY=\"0%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/decelerate_interpolator\"\n\t\tandroid:fromAlpha=\"0.0\" android:toAlpha=\"1.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/grow_from_topleft_to_bottomright.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"0.3\" android:toXScale=\"1.0\"\n\t\tandroid:fromYScale=\"0.3\" android:toYScale=\"1.0\"\n\t\tandroid:pivotX=\"0%\" android:pivotY=\"0%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/decelerate_interpolator\"\n\t\tandroid:fromAlpha=\"0.0\" android:toAlpha=\"1.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/shrink_from_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"1.0\" android:toXScale=\"0.3\"\n\t\tandroid:fromYScale=\"1.0\" android:toYScale=\"0.3\"\n\t\tandroid:pivotX=\"50%\" android:pivotY=\"0%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/accelerate_interpolator\"\n\t\tandroid:fromAlpha=\"1.0\" android:toAlpha=\"0.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/shrink_from_bottomright_to_topleft.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"1.0\" android:toXScale=\"0.3\"\n\t\tandroid:fromYScale=\"1.0\" android:toYScale=\"0.3\"\n\t\tandroid:pivotX=\"0%\" android:pivotY=\"0%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/accelerate_interpolator\"\n\t\tandroid:fromAlpha=\"1.0\" android:toAlpha=\"0.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/shrink_from_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<scale\n\t\tandroid:fromXScale=\"1.0\" android:toXScale=\"0.3\"\n\t\tandroid:fromYScale=\"1.0\" android:toYScale=\"0.3\"\n\t\tandroid:pivotX=\"50%\" android:pivotY=\"100%\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n\t<alpha\n\t\tandroid:interpolator=\"@android:anim/accelerate_interpolator\"\n\t\tandroid:fromAlpha=\"1.0\" android:toAlpha=\"0.0\"\n\t\tandroid:duration=\"@android:integer/config_shortAnimTime\"\n\t/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/zoom_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** Copyright 2009, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n-->\n\n<!-- Special window zoom animation: this is the element that enters the screen,\n     it starts at 200% and scales down.  Goes with zoom_exit.xml. -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:interpolator=\"@android:anim/decelerate_interpolator\">\n    <scale android:fromXScale=\"2.0\" android:toXScale=\"1.0\"\n           android:fromYScale=\"2.0\" android:toYScale=\"1.0\"\n           android:pivotX=\"50%p\" android:pivotY=\"50%p\"\n           android:duration=\"@android:integer/config_mediumAnimTime\" />\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/zoom_exit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** Copyright 2009, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n-->\n\n<!-- Special window zoom animation: this is the element that exits the\n     screen, it is forced above the entering element and starts at its\n     normal size (filling the screen) and scales down while fading out.\n     This goes with zoom_enter.xml. -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:interpolator=\"@android:anim/decelerate_interpolator\"\n        android:zAdjustment=\"top\">\n    <scale android:fromXScale=\"1.0\" android:toXScale=\".5\"\n           android:fromYScale=\"1.0\" android:toYScale=\".5\"\n           android:pivotX=\"50%p\" android:pivotY=\"50%p\"\n           android:duration=\"@android:integer/config_mediumAnimTime\" />\n    <alpha android:fromAlpha=\"1.0\" android:toAlpha=\"0\"\n            android:duration=\"@android:integer/config_mediumAnimTime\"/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/drawable/btn_check.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector\n\txmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<!-- Enabled states -->\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_window_focused=\"false\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_window_focused=\"false\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_off\" />\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_pressed=\"true\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on_pressed\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_pressed=\"true\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_off_pressed\" />\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_focused=\"true\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on_selected\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_focused=\"true\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_off_selected\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_off\" />\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_enabled=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on\" />\n\n\t<!-- Disabled states -->\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_window_focused=\"false\"\n\t\tandroid:drawable=\"@drawable/btn_check_on_disable\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_window_focused=\"false\"\n\t\tandroid:drawable=\"@drawable/btn_check_off_disable\" />\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:state_focused=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on_disable_focused\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:state_focused=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_off_disable_focused\" />\n\t<item\n\t\tandroid:state_checked=\"false\"\n\t\tandroid:drawable=\"@drawable/btn_check_off_disable\" />\n\t<item\n\t\tandroid:state_checked=\"true\"\n\t\tandroid:drawable=\"@drawable/btn_check_on_disable\" />\n</selector>\n\n "
  },
  {
    "path": "app/src/main/res/drawable/lock_anim.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** Copyright 2008, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\");\n** you may not use this file except in compliance with the License.\n** You may obtain a copy of the License at\n**\n**     http://www.apache.org/licenses/LICENSE-2.0\n**\n** Unless required by applicable law or agreed to in writing, software\n** distributed under the License is distributed on an \"AS IS\" BASIS,\n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n** See the License for the specific language governing permissions and\n** limitations under the License.\n*/\n-->\n<animation-list\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:oneshot=\"false\">\n    <item android:drawable=\"@drawable/lock_anim_00\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_02\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_04\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_06\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_08\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_10\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_12\" android:duration=\"400\" />\n    <item android:drawable=\"@drawable/lock_anim_14\" android:duration=\"400\" />\n</animation-list>\n"
  },
  {
    "path": "app/src/main/res/drawable/menu_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector\n\txmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<item\n\t\tandroid:state_pressed=\"true\"\n\t\tandroid:drawable=\"@drawable/button_bg_pressed\">\n\t</item>\n\n\t<item\n\t\tandroid:state_focused=\"true\"\n\t\tandroid:drawable=\"@drawable/button_bg_pressed\">\n\t</item>\n\n\t<item\n\t\tandroid:drawable=\"@drawable/button_bg\">\n\t</item>\n</selector>\n"
  },
  {
    "path": "app/src/main/res/drawable/popup_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\"\n        android:drawable=\"@drawable/popup_bg_selected\" >\n    </item>\n\n    <item android:state_focused=\"true\"\n        android:drawable=\"@drawable/popup_bg_selected\" >\n    </item>\n\n    <item \n        android:drawable=\"@drawable/popup_bg_regular\" >\n    </item>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/widget_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:oneshot=\"false\">\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_1\"\n\t\tandroid:duration=\"200\" />\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_2\"\n\t\tandroid:duration=\"200\" />\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_3\"\n\t\tandroid:duration=\"200\" />\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_4\"\n\t\tandroid:duration=\"200\" />\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_3\"\n\t\tandroid:duration=\"200\" />\n\t<item\n\t\tandroid:drawable=\"@drawable/widget_progress_2\"\n\t\tandroid:duration=\"200\" />\n</animation-list>\n"
  },
  {
    "path": "app/src/main/res/layout/about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:orientation=\"vertical\"\n\tandroid:layout_height=\"fill_parent\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:paddingBottom=\"20dp\">\n    <include layout=\"@layout/toolbar\" />\n\t<ScrollView\n\t\tandroid:fillViewport=\"true\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"fill_parent\"\n\t\tandroid:layout_weight=\"1\">\n\t\t<LinearLayout\n\t\t\t\tandroid:orientation=\"vertical\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:paddingLeft=\"20dp\"\n\t\t\tandroid:paddingRight=\"20dp\" android:layout_width=\"fill_parent\">\n\t\t\t<RelativeLayout\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_marginBottom=\"20dp\" android:layout_width=\"fill_parent\">\n\t\t\t<ImageView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:src=\"@drawable/logo_text_big\"\n\t\t\t\tandroid:adjustViewBounds=\"true\"\n\t\t\t\tandroid:id=\"@+id/imgTextLogo\"\n\t\t\t\tandroid:layout_marginTop=\"20dp\" android:scaleType=\"fitXY\" android:layout_width=\"wrap_content\" android:layout_centerHorizontal=\"true\"></ImageView>\n\t\t\t<ImageView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:layout_below=\"@+id/imgTextLogo\" android:id=\"@+id/imgNullbyteLogo\" android:src=\"@drawable/nullbyte_logo\" android:layout_alignRight=\"@+id/imgTextLogo\" android:layout_alignBottom=\"@+id/txtVersion\"></ImageView>\n\t\t\t<TextView android:layout_width=\"fill_parent\" android:layout_height=\"wrap_content\" android:id=\"@+id/txtVersion\" android:text=\"@string/version\" android:textSize=\"15sp\" android:layout_below=\"@+id/imgTextLogo\" android:gravity=\"right\" android:textColor=\"#78ffffff\" android:layout_toLeftOf=\"@+id/imgNullbyteLogo\" android:layout_marginRight=\"4dp\"></TextView>\n</RelativeLayout>\n\t\t\t<TextView\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:text=\"@string/thanks_to\"\n\t\t\t\tandroid:textStyle=\"bold\"\n\t\t\t\tandroid:layout_marginTop=\"10dp\"\n\t\t\t\tandroid:layout_width=\"fill_parent\" android:textSize=\"20sp\"></TextView>\n\t\t\t<TextView\n\t\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:text=\"@string/thanks\"\n\t\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\t\tandroid:paddingLeft=\"10dp\"\n\t\t\t\tandroid:typeface=\"serif\"\n\t\t\t\tandroid:textSize=\"12sp\" android:layout_marginBottom=\"10dp\"></TextView>\n\n\t\t</LinearLayout>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t</ScrollView>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bank.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:background=\"@drawable/background_repeat\">\n\n    <include\n        android:id=\"@+id/toolbar\"\n        layout=\"@layout/toolbar\" />\n\n    <ScrollView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:layout_above=\"@+id/TableLayout01\"\n        android:layout_below=\"@id/toolbar\"\n        android:fillViewport=\"true\">\n\n        <LinearLayout\n            android:id=\"@+id/LinearLayout01\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_below=\"@+id/txtErrorDesc\"\n            android:orientation=\"vertical\"\n            android:padding=\"10dp\">\n\n            <TextView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/bank\"/>\n\n            <Spinner\n                android:id=\"@+id/spnBankeditBanklist\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"></Spinner>\n\n            <LinearLayout\n                    android:orientation=\"vertical\"\n                    android:id=\"@+id/layoutBankConfiguration\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"></LinearLayout>\n\n            <TextView\n                android:id=\"@+id/txtErrorDesc\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:drawableLeft=\"@drawable/indicator_input_error\"\n                android:drawablePadding=\"5dp\"\n                android:text=\"@string/error_desc\"\n                android:textSize=\"12sp\"\n                android:visibility=\"invisible\"></TextView>\n        </LinearLayout>\n    </ScrollView>\n\n    <TableLayout\n        android:id=\"@+id/TableLayout01\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_below=\"@+id/LinearLayout01\"\n        android:gravity=\"bottom\"\n        android:stretchColumns=\"0,2\">\n\n        <TableRow\n                android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|center_horizontal\"\n            android:gravity=\"center_vertical|center_horizontal\">\n\n            <Button\n                android:id=\"@+id/btnSettingsCancel\"\n                style=\"@style/Menu_Button\"\n                android:drawableLeft=\"@drawable/button_cancel\"\n                android:text=\"@android:string/cancel\"></Button>\n\n            <ImageView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:adjustViewBounds=\"true\"\n                android:focusable=\"false\"\n                android:maxWidth=\"3dp\"\n                android:minWidth=\"3dp\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/menu_separator\"></ImageView>\n\n            <Button\n                android:id=\"@+id/btnSettingsOk\"\n                style=\"@style/Menu_Button\"\n                android:drawableLeft=\"@drawable/button_save\"\n                android:text=\"@string/save\"></Button>\n        </TableRow>\n    </TableLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bank_spinner_dropdown_item.xml",
    "content": "<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tstyle=\"?android:attr/spinnerItemStyle\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"fill_parent\">\n\t<ImageView\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:src=\"@drawable/ic_launcher\"\n\t\tandroid:id=\"@+id/imgBank\"\n\t\tandroid:adjustViewBounds=\"true\"\n\t\tandroid:maxHeight=\"40dp\"\n\t\tandroid:maxWidth=\"40dp\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:layout_marginRight=\"4dp\"\n\t\tandroid:layout_marginLeft=\"4dp\"></ImageView>\n\t<CheckedTextView\n\t\tstyle=\"?android:attr/spinnerDropDownItemStyle\"\n\t\tandroid:lines=\"1\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"?android:attr/listPreferredItemHeight\"\n\t\tandroid:ellipsize=\"marquee\"\n\t\tandroid:id=\"@+id/txtBank\"\n\t\tandroid:layout_gravity=\"center\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bank_spinner_item.xml",
    "content": "<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tstyle=\"?android:attr/spinnerItemStyle\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"fill_parent\">\n\t<ImageView\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:src=\"@drawable/ic_launcher\"\n\t\tandroid:id=\"@+id/imgBank\"\n\t\tandroid:adjustViewBounds=\"true\"\n\t\tandroid:maxHeight=\"30dp\"\n\t\tandroid:maxWidth=\"30dp\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:layout_marginRight=\"2dp\"></ImageView>\n\t<TextView\n\t\tstyle=\"?android:attr/spinnerItemStyle\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:ellipsize=\"marquee\"\n\t\tandroid:lines=\"1\"\n\t\tandroid:id=\"@+id/txtBank\"\n\t\tandroid:layout_gravity=\"center\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/choose_lock_pattern.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/topLayout\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"fill_parent\" android:background=\"#00000000\">\n\n    <TextView android:id=\"@+id/headerText\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:textSize=\"18sp\"/>\n\n    <View\n         android:background=\"@drawable/code_lock_top\"\n         android:layout_width=\"fill_parent\"\n         android:layout_height=\"2dip\" />\n    <com.liato.bankdroid.lockpattern.LockPatternView android:id=\"@+id/lockPattern\"\n         android:layout_width=\"wrap_content\"\n         android:layout_height=\"wrap_content\" />\n    <View\n         android:background=\"@drawable/code_lock_bottom\"\n         android:layout_width=\"fill_parent\"\n         android:layout_height=\"8dip\" />\n\n    <!-- message just above the button bar -->\n    <TextView android:id=\"@+id/footerText\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:textSize=\"14sp\"/>\n\n    <!-- confirm / restart buttons -->\n    <LinearLayout style=\"@android:style/ButtonBar\"\n        android:orientation=\"horizontal\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <!-- left button: skip, or retry -->\n        <Button android:id=\"@+id/footerLeftButton\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"140dip\"\n                android:ellipsize=\"marquee\"\n                android:text=\"@string/lockpattern_restart_button_text\"\n                android:maxLines=\"1\"/>\n\n        <!-- Placeholder to get blank space between the two buttons -->\n        <View\n            android:visibility=\"invisible\"\n            android:layout_height=\"0dip\"\n            android:layout_width=\"1dip\"\n            android:layout_weight=\"1\" />\n\n        <!-- right button: confirm or ok -->\n        <Button android:id=\"@+id/footerRightButton\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"140dip\"\n                android:ellipsize=\"marquee\"\n                android:drawableRight=\"@drawable/ic_btn_next\"\n                android:drawablePadding=\"3dip\"\n                android:text=\"@string/lockpattern_confirm_button_text\"\n                android:maxLines=\"1\"/>\n\n    </LinearLayout>\n\n</com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient>\n"
  },
  {
    "path": "app/src/main/res/layout/choose_lock_pattern_example.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_height=\"fill_parent\"\n    android:layout_width=\"fill_parent\">\n\n    <ScrollView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:layout_weight=\"1\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_height=\"fill_parent\"\n            android:layout_width=\"fill_parent\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/lock_example_title\"\n                android:gravity=\"center_horizontal\"\n                style=\"?android:attr/textAppearanceLarge\"\n            />\n\n            <ImageView android:id=\"@+id/lock_anim\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"11dip\"\n                android:layout_gravity=\"center_horizontal\"\n                android:focusable=\"false\"\n                android:clickable=\"false\"\n            />\n\n            <TextView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dip\"\n                android:text=\"@string/lock_example_message\"\n                android:layout_gravity=\"left\"\n                style=\"?android:attr/textAppearanceMedium\"\n            />\n\n        </LinearLayout>\n\n    </ScrollView>\n\n    <LinearLayout style=\"@android:style/ButtonBar\"\n        android:orientation=\"horizontal\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <Button android:id=\"@+id/skip_button\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"140dip\"\n            android:ellipsize=\"marquee\"\n                android:text=\"@string/skip_button_label\"\n                android:maxLines=\"1\"/>\n\n        <!-- Placeholder to get blank space between the two buttons -->\n        <View\n            android:visibility=\"invisible\"\n            android:layout_height=\"0dip\"\n            android:layout_width=\"1dip\"\n            android:layout_weight=\"1\" />\n\n        <Button android:id=\"@+id/next_button\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"140dip\"\n            android:ellipsize=\"marquee\"\n                android:drawableRight=\"@drawable/ic_btn_next\"\n            android:drawablePadding=\"3dip\"\n            android:text=\"@string/next_button_label\"\n                android:maxLines=\"1\"/>\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/choose_lock_pattern_tutorial.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_height=\"fill_parent\"\n    android:layout_width=\"fill_parent\">\n\n    <ScrollView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1\">\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:text=\"@string/lock_title\"\n                android:paddingBottom=\"10dip\"\n                android:layout_marginTop=\"3dip\"\n                style=\"?android:attr/textAppearanceLarge\"\n            />\n\n            <TextView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:layout_marginTop=\"10dip\"\n                android:text=\"@string/lock_intro_message\"\n            />\n\n        </LinearLayout>\n\n    </ScrollView>\n\n    <LinearLayout style=\"@android:style/ButtonBar\"\n        android:orientation=\"horizontal\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <Button android:id=\"@+id/skip_button\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"140dip\"\n            android:ellipsize=\"marquee\"\n                android:text=\"@string/skip_button_label\"\n                android:maxLines=\"1\"/>\n\n        <!-- Placeholder to get blank space between the two buttons -->\n        <View\n            android:visibility=\"invisible\"\n            android:layout_height=\"0dip\"\n            android:layout_width=\"1dip\"\n            android:layout_weight=\"1\" />\n\n        <Button android:id=\"@+id/next_button\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"140dip\"\n            android:drawableRight=\"@drawable/ic_btn_next\"\n            android:drawablePadding=\"3dip\"\n            android:ellipsize=\"marquee\"\n                android:text=\"@string/next_button_label\"\n                android:maxLines=\"1\"/>\n\n    </LinearLayout>\n\n</LinearLayout >\n"
  },
  {
    "path": "app/src/main/res/layout/confirm_lock_pattern.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/topLayout\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"fill_parent\" android:background=\"#00000000\">\n\n    <TextView android:id=\"@+id/headerText\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1.0\"\n        android:gravity=\"center\"\n        android:textSize=\"18sp\"/>\n\n    <View\n         android:background=\"@drawable/code_lock_top\"\n         android:layout_width=\"fill_parent\"\n         android:layout_height=\"2dip\" />\n    <com.liato.bankdroid.lockpattern.LockPatternView android:id=\"@+id/lockPattern\"\n         android:layout_width=\"wrap_content\"\n         android:layout_height=\"wrap_content\" />\n    <!-- <View\n         android:background=\"@*android:drawable/code_lock_bottom\"\n         android:layout_width=\"fill_parent\"\n         android:layout_height=\"8dip\" /> -->\n\n    <TextView android:id=\"@+id/footerText\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dip\"\n        android:layout_weight=\"1.0\"\n        android:gravity=\"center\"\n        android:textSize=\"14sp\"/>\n\n\n</com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_color_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2010 Daniel Nilsson\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:paddingLeft=\"5dp\"\n    android:paddingRight=\"5dp\"\n    android:orientation=\"vertical\">\n\n\t<net.margaritov.preference.colorpicker.ColorPickerView\n\t\tandroid:id=\"@+id/color_picker_view\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_centerHorizontal=\"true\"\n\t\tandroid:tag=\"portrait\"\n\t/>\n\n\t<TextView\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:text=\"@string/press_color_to_apply\"\n\t\tandroid:gravity=\"left\"\n\t\tandroid:layout_marginLeft=\"6dp\"\n\t\tandroid:layout_marginRight=\"6dp\"\n\t\tandroid:layout_marginBottom=\"5dp\"\n\t\tandroid:textAppearance=\"?android:attr/textAppearanceSmall\"\n\t/>\n\n\t<LinearLayout\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"40dp\"\n\t\tandroid:orientation=\"horizontal\"\n\t\tandroid:layout_below=\"@id/color_picker_view\"\n\t\tandroid:layout_marginBottom=\"10dp\">\n\n\t\t<net.margaritov.preference.colorpicker.ColorPickerPanelView\n\t\t\tandroid:id=\"@+id/old_color_panel\"\n\t\t\tandroid:layout_width=\"0px\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:layout_weight=\"0.5\"\n\t\t/>\n\n\t\t<TextView\n\t\t\ttools:ignore=\"HardcodedText\"\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:text=\"→\"\n\t\t\tandroid:textSize=\"20sp\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:layout_marginLeft=\"10dp\"\n\t\t\tandroid:layout_marginRight=\"10dp\"\n\t\t/>\n\n\t\t<net.margaritov.preference.colorpicker.ColorPickerPanelView\n\t\t\tandroid:id=\"@+id/new_color_panel\"\n\t\t\tandroid:layout_width=\"0px\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_weight=\"0.5\"\n\t\t/>\n\n\t</LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/empty.xml",
    "content": "<LinearLayout android:id=\"@+id/LinearLayout01\" android:layout_width=\"fill_parent\" xmlns:android=\"http://schemas.android.com/apk/res/android\" android:layout_height=\"wrap_content\"></LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/listitem_accounts_group.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    >\n\n    <RelativeLayout\n        android:id=\"@+id/layBankHeader\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"62dp\"\n        android:background=\"@drawable/group_bg\"\n        android:paddingBottom=\"5dp\"\n        android:paddingLeft=\"5dp\"\n        android:paddingRight=\"10dp\"\n        android:paddingTop=\"5dp\"\n        >\n\n        <ImageView\n            android:id=\"@+id/imgListitemAccountsGroup\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"fill_parent\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_marginLeft=\"0dp\"\n            android:layout_marginRight=\"2dp\"\n            android:maxHeight=\"48dp\"\n            android:maxWidth=\"48dp\"\n            android:minHeight=\"48dp\"\n            android:minWidth=\"48dp\"\n            android:padding=\"0dp\"\n            android:src=\"@drawable/ic_launcher\"\n            />\n\n        <TextView\n            android:id=\"@+id/txtListitemAccountsGroupBankname\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"21dip\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentRight=\"false\"\n            android:layout_marginRight=\"4dp\"\n            android:layout_toLeftOf=\"@+id/txtListitemAccountsGroupTotal\"\n            android:layout_toRightOf=\"@id/imgListitemAccountsGroup\"\n            android:ellipsize=\"marquee\"\n            android:gravity=\"top\"\n            android:text=\"Banknamn\"\n            android:textColor=\"#000\"\n            tools:ignore=\"HardcodedText\"\n            android:maxLines=\"1\"\n            />\n\n        <TextView\n            android:id=\"@+id/txtListitemAccountsGroupAccountname\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_above=\"@id/txtListitemAccountsGroupBankname\"\n            android:layout_alignParentRight=\"false\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_alignWithParentIfMissing=\"true\"\n            android:layout_toRightOf=\"@id/imgListitemAccountsGroup\"\n            android:ellipsize=\"marquee\"\n            android:gravity=\"center_vertical\"\n            android:includeFontPadding=\"true\"\n            android:lines=\"1\"\n            android:marqueeRepeatLimit=\"marquee_forever\"\n            android:scrollHorizontally=\"true\"\n            android:shadowColor=\"#78ffffff\"\n            android:shadowDx=\"0\"\n            android:shadowDy=\"1\"\n            android:shadowRadius=\"2\"\n            android:text=\"Personnummer\"\n            android:textColor=\"#000\"\n            android:textSize=\"23sp\"\n            tools:ignore=\"HardcodedText\"\n            />\n\n        <TextView\n            android:id=\"@+id/txtListitemAccountsGroupTotal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"21dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:ellipsize=\"marquee\"\n            android:gravity=\"top\"\n            android:text=\"00000 SEK\"\n            android:textColor=\"#333\"\n            tools:ignore=\"HardcodedText\"\n            android:maxLines=\"1\"\n            />\n\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/txtDisabledWarningX\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"10dp\"\n        android:drawableLeft=\"@drawable/indicator_input_error\"\n        android:drawablePadding=\"10dp\"\n        android:text=\"@string/disabled_refresh_or_edit\"\n        android:visibility=\"visible\"\n        />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/listitem_accounts_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"35dp\"\n    android:layout_gravity=\"center_horizontal\">\n\n    <TextView\n        android:layout_alignParentBottom=\"true\"\n        android:ellipsize=\"marquee\"\n        android:gravity=\"center_vertical\"\n        android:layout_width=\"wrap_content\"\n        android:layout_alignParentRight=\"false\"\n        android:textColor=\"#fff\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentTop=\"true\"\n        android:id=\"@+id/txtListitemAccountsItemAccountname\"\n        android:inputType=\"none\"\n        android:text=\"Kontonamn\"\n        android:textStyle=\"bold\"\n        android:layout_height=\"fill_parent\"\n        android:paddingLeft=\"15dp\"\n        android:layout_toLeftOf=\"@+id/txtListitemAccountsItemBalance\"\n        tools:ignore=\"HardcodedText\"/>\n\n    <TextView\n        android:layout_alignParentBottom=\"true\"\n        android:ellipsize=\"marquee\"\n        android:text=\"00000 SEK\"\n        android:layout_width=\"wrap_content\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignParentTop=\"true\"\n        android:id=\"@+id/txtListitemAccountsItemBalance\"\n        android:inputType=\"none\"\n        android:gravity=\"right|center_vertical\"\n        android:layout_height=\"fill_parent\"\n        android:textColor=\"#fff\"\n        android:paddingRight=\"10dp\"\n        tools:ignore=\"HardcodedText\"/>\n\n    <RelativeLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:minHeight=\"1dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignWithParentIfMissing=\"true\"\n        android:layout_alignParentTop=\"false\"\n        android:layout_alignParentBottom=\"true\"\n        android:id=\"@+id/divider\"></RelativeLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"fill_parent\"\n    android:background=\"@drawable/background_repeat\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/toolbar\" />\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <CheckBox\n            android:id=\"@+id/chkTransperantBackground\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"10dp\"\n            android:text=\"@string/transparent_background\"\n            android:visibility=\"gone\" />\n\n        <TextView\n            android:id=\"@+id/txtAccountsDesc\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"10dp\"\n            android:text=\"@string/main_instructions\"\n            android:visibility=\"visible\" />\n\n        <ListView\n            android:id=\"@+id/lstAccountsList\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_above=\"@+id/layMainMenu\"\n            android:layout_alignWithParentIfMissing=\"true\"\n            android:layout_below=\"@+id/chkTransperantBackground\"\n            android:cacheColorHint=\"#00000000\"\n            android:dividerHeight=\"0dp\"\n            android:fadingEdge=\"vertical\" />\n\n        <TableLayout\n            android:id=\"@+id/layMainMenu\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:stretchColumns=\"0,2\"\n            android:visibility=\"gone\">\n\n            <TableRow\n                    android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|center_horizontal\"\n                android:gravity=\"center_vertical|center_horizontal\">\n\n                <Button\n                        style=\"@style/Menu_Button\"\n                    android:drawableLeft=\"@drawable/button_add\"\n                    android:text=\"@string/add_new_account\"></Button>\n\n                <ImageView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:adjustViewBounds=\"true\"\n                    android:focusable=\"false\"\n                    android:maxWidth=\"3dp\"\n                    android:minWidth=\"3dp\"\n                    android:scaleType=\"fitXY\"\n                    android:src=\"@drawable/menu_separator\"></ImageView>\n\n                <Button\n                        style=\"@style/Menu_Button\"\n                    android:drawableLeft=\"@drawable/button_refresh\"\n                    android:text=\"@string/refresh_balance\"></Button>\n            </TableRow>\n        </TableLayout>\n    </RelativeLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/pair_applications_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_width=\"wrap_content\"\n\tandroid:layout_height=\"fill_parent\"\n\tandroid:background=\"@drawable/background_repeat\">\n\t<LinearLayout\n\t\t\tandroid:id=\"@+id/LinearLayout01\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_below=\"@+id/txtErrorDesc\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:orientation=\"vertical\"\n\t\t\tandroid:layout_alignParentTop=\"true\"\n\t\t\tandroid:padding=\"10dp\">\n\t\t\t<TextView\n\t\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:typeface=\"sans\"\n\t\t\t\tandroid:textSize=\"16sp\"\n\t\t\t\tandroid:text=\"@string/pair_message\" />\n\n\t\t<ImageView\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:src=\"@drawable/logo_unknown_app\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:id=\"@+id/imageView1\"\n\t\t\tandroid:layout_gravity=\"center_horizontal\"\n\t\t\tandroid:paddingTop=\"40dp\"\n\t\t\t/>\n\t\t\t<TextView\n\t\t\t\tandroid:id=\"@+id/app_name\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:typeface=\"sans\"\n\t\t\t\tandroid:textSize=\"25sp\"\n\t\t\t\tandroid:layout_gravity=\"center_horizontal\"\n\t\t\t\tandroid:text=\"@string/pair_app_name\"\n\t\t\t\t/>\n\t\t</LinearLayout>\n\t<TableLayout\n\t\tandroid:id=\"@+id/TableLayout01\"\n\t\tandroid:stretchColumns=\"0,2\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_alignParentBottom=\"true\"\n\t\tandroid:layout_alignParentLeft=\"true\"\n\t\tandroid:layout_alignParentRight=\"true\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_below=\"@+id/LinearLayout01\"\n\t\tandroid:gravity=\"bottom\">\n\t\t<TableRow\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_width=\"fill_parent\">\n\t\t\t<Button\n\t\t\t\tandroid:onClick=\"cancelPairing\"\n\t\t\t\tandroid:text=\"@android:string/cancel\"\n\t\t\t\tandroid:drawableLeft=\"@drawable/button_cancel\"\n\t\t\t\tandroid:id=\"@+id/btnSettingsCancel\"\n\t\t\t\tstyle=\"@style/Menu_Button\"></Button>\n\t\t\t<ImageView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:focusable=\"false\"\n\t\t\t\tandroid:src=\"@drawable/menu_separator\"\n\t\t\t\tandroid:adjustViewBounds=\"true\"\n\t\t\t\tandroid:scaleType=\"fitXY\"\n\t\t\t\tandroid:minWidth=\"3dp\"\n\t\t\t\tandroid:maxWidth=\"3dp\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"></ImageView>\n\t\t\t<Button\n\t\t\t\tandroid:onClick=\"confirmPairing\"\n\t\t\t\tandroid:id=\"@+id/btnSettingsOk\"\n\t\t\t\tandroid:drawableLeft=\"@drawable/button_accept\"\n\t\t\t\tandroid:text=\"@string/approve\"\n\t\t\t\tstyle=\"@style/Menu_Button\"></Button>\n\t\t</TableRow>\n\t</TableLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/popup_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_height=\"wrap_content\"\n\tandroid:background=\"@drawable/popup_bg_down\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_gravity=\"fill_horizontal\"\n\tandroid:id=\"@+id/layPopupCont\">\n\t<Button style=\"@style/Popup_Button\"\n\t\tandroid:drawableTop=\"@drawable/button_hide\" android:id=\"@+id/btnHide\" android:text=\"@string/popup_hide\"></Button><Button style=\"@style/Popup_Button\"\n\t\tandroid:drawableTop=\"@drawable/button_hide\" android:id=\"@+id/btnUnhide\" android:text=\"@string/popup_unhide\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\t\t\n\t<Button\n\t\tstyle=\"@style/Popup_Button\" android:id=\"@+id/btnDisableNotifications\" android:drawableTop=\"@drawable/button_notification\" android:text=\"@string/popup_disable_notifications\"></Button><Button\n\t\tstyle=\"@style/Popup_Button\" android:drawableTop=\"@drawable/button_notification\" android:id=\"@+id/btnEnableNotifications\" android:text=\"@string/popup_enable_notifications\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\t\t\n\t\n\t\t\t\n\t\n\t\t\t\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/popup_bank.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:layout_height=\"wrap_content\"\n\tandroid:background=\"@drawable/popup_bg_down\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_gravity=\"fill_horizontal\"\n\tandroid:id=\"@+id/layPopupCont\">\n\t<Button style=\"@style/Popup_Button\"\n\t\tandroid:id=\"@+id/btnRefresh\"\n\t\tandroid:drawableTop=\"@drawable/button_refresh\" android:text=\"@string/popup_refresh\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\n\t<Button style=\"@style/Popup_Button\"\n\t\tandroid:drawableTop=\"@drawable/button_hide\" android:id=\"@+id/btnHide\" android:text=\"@string/popup_hide_a\"></Button>\n\t<Button style=\"@style/Popup_Button\"\n\t\tandroid:drawableTop=\"@drawable/button_hide\" android:id=\"@+id/btnUnhide\" android:text=\"@string/popup_unhide_a\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\n\t<Button\n\t\tandroid:id=\"@+id/btnEdit\"\n\t\tandroid:drawableTop=\"@drawable/button_edit\"\n\t\tstyle=\"@style/Popup_Button\" android:text=\"@string/popup_edit\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\t\t\n\t<Button\n\t\tandroid:id=\"@+id/btnWWW\"\n\t\tandroid:drawableTop=\"@drawable/button_www\"\n\t\tstyle=\"@style/Popup_Button\" android:text=\"@string/popup_www\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\t\t\n\t<Button\n\t\tandroid:id=\"@+id/btnRemove\"\n\t\tandroid:drawableTop=\"@drawable/button_cancel\"\n\t\tstyle=\"@style/Popup_Button\" android:text=\"@string/popup_remove\"></Button>\n\t<ImageView style=\"@style/Popup_Separator\"></ImageView>\t\t\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/toolbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/colorPrimary\"\n    android:minHeight=\"?attr/actionBarSize\"\n    app:theme=\"@style/ThemeOverlay.AppCompat.ActionBar\"\n    tools:showIn=\"@layout/main\" />"
  },
  {
    "path": "app/src/main/res/layout/transaction_date.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"fill_parent\"\n    android:paddingLeft=\"10dp\"\n    android:paddingRight=\"0dp\"\n    android:background=\"@drawable/date_bg\"\n    android:layout_height=\"wrap_content\"\n    android:clickable=\"false\"\n    android:focusable=\"false\"\n    android:focusableInTouchMode=\"false\"\n    >\n\n    <TextView\n        android:inputType=\"none\"\n        android:scrollHorizontally=\"true\"\n        android:layout_width=\"fill_parent\"\n        android:textStyle=\"bold\"\n        android:text=\"2010-11-12\"\n        android:typeface=\"sans\"\n        android:shadowColor=\"#000\"\n        android:id=\"@+id/txtDate\"\n        android:shadowDx=\"0\"\n        android:shadowDy=\"0\"\n        android:shadowRadius=\"1\"\n        android:textSize=\"16sp\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"#fff\"\n        android:layout_height=\"fill_parent\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_alignParentBottom=\"true\"\n        android:focusable=\"false\"\n        android:clickable=\"false\"\n        android:focusableInTouchMode=\"false\"\n        tools:ignore=\"HardcodedText\"\n        />\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/transaction_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"35dp\"\n\tandroid:layout_gravity=\"center_horizontal\"\n\tandroid:paddingLeft=\"10dp\" android:paddingRight=\"0dp\" android:clickable=\"true\">\n\n\t<TextView\n\t\tandroid:layout_alignParentBottom=\"true\"\n\t\tandroid:ellipsize=\"marquee\"\n\t\tandroid:gravity=\"center_vertical\"\n\t\tandroid:layout_alignParentRight=\"false\"\n\t\tandroid:textColor=\"#fff\"\n\t\tandroid:layout_alignParentLeft=\"true\"\n\t\tandroid:layout_alignParentTop=\"true\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_height=\"fill_parent\" android:id=\"@+id/txtTransaction\" android:scrollHorizontally=\"true\" android:layout_width=\"fill_parent\" android:layout_toLeftOf=\"@+id/txtAmount\"/>\n\n\n\t<TextView\n\t\tandroid:layout_alignParentBottom=\"true\"\n\t\tandroid:ellipsize=\"marquee\"\n\t\tandroid:text=\"00000 SEK\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:textColor=\"#fff\"\n\t\tandroid:layout_alignParentTop=\"true\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_toRightOf=\"@+id/txtListitemAccountsItemAccountname\"\n\t\tandroid:gravity=\"right|center_vertical\"\n\t\tandroid:layout_height=\"fill_parent\"\n\t\tandroid:layout_toLeftOf=\"@+id/imgColor\"\n        android:id=\"@+id/txtAmount\"\n        android:paddingLeft=\"5dp\"\n\t\ttools:ignore=\"HardcodedText\"/>\n\n<ImageView android:layout_height=\"wrap_content\" android:layout_width=\"wrap_content\" android:id=\"@+id/imgColor\" android:background=\"@drawable/transaction_negative\" android:layout_alignParentRight=\"true\" android:layout_marginLeft=\"5dp\"></ImageView>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/transactions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"wrap_content\"\n    android:layout_height=\"fill_parent\"\n    android:background=\"@drawable/background_repeat\">\n\n    <include\n        android:id=\"@+id/toolbar\"\n        layout=\"@layout/toolbar\" />\n\n    <include\n        android:id=\"@+id/layBankHeader\"\n        layout=\"@layout/listitem_accounts_group\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"62dp\"\n        android:layout_below=\"@id/toolbar\" />\n\n    <TextView\n        android:id=\"@+id/txtDisabledWarning\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/layBankHeader\"\n        android:layout_margin=\"10dp\"\n        android:drawableLeft=\"@drawable/indicator_input_error\"\n        android:drawablePadding=\"10dp\"\n        android:text=\"@string/disabled_refresh_or_edit\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/txtTranDesc\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/txtDisabledWarning\"\n        android:layout_margin=\"10dp\"\n        android:text=\"@string/tran_desc\"\n        android:visibility=\"visible\" />\n\n    <ListView\n        android:id=\"@+id/lstTransactionsList\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_below=\"@+id/txtTranDesc\"\n        android:background=\"@drawable/background_repeat\"\n        android:cacheColorHint=\"#00000000\"\n        android:clickable=\"false\"\n        android:fitsSystemWindows=\"true\"\n        android:footerDividersEnabled=\"true\"\n        android:scrollbarStyle=\"outsideInset\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"fill_parent\"\n\txmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<WebView\n\t\tandroid:id=\"@+id/wvBank\"\n\t\tandroid:layout_height=\"fill_parent\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:scrollbarAlwaysDrawHorizontalTrack=\"false\"\n\t\tandroid:scrollbarAlwaysDrawVerticalTrack=\"false\"\n\t\tandroid:background=\"@drawable/background_repeat\" />\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/widget.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_gravity=\"center_horizontal\"\n\tandroid:background=\"@drawable/widget_2x1\"\n\tandroid:layout_height=\"100dp\"\n\tandroid:layout_width=\"160dp\"\n\tandroid:id=\"@+id/layWidgetContainer\">\n\n\t<FrameLayout\n\t\tandroid:layout_height=\"22dp\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:id=\"@+id/hitBox\"\n\t\tandroid:focusable=\"true\"></FrameLayout>\n\t<LinearLayout\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:id=\"@+id/layWidgetRow01\"\n\t\tandroid:layout_marginTop=\"0dp\">\n\t\t<ImageView\n\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:layout_width=\"22dp\"\n\t\t\tandroid:layout_height=\"22dp\"\n\t\t\tandroid:id=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_gravity=\"center_vertical\"\n\t\t\tandroid:baselineAlignBottom=\"true\"\n\t\t\tandroid:src=\"@drawable/ic_launcher\"\n\t\t\tandroid:scaleType=\"fitXY\"></ImageView>\n\t<TextView\n\t\tandroid:id=\"@+id/txtWidgetAccountname\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:textColor=\"#a8a3a3\"\n\t\tandroid:textSize=\"11dp\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_marginLeft=\"2dp\"\n\t\tandroid:layout_marginRight=\"2dp\"\n\t\tandroid:text=\"@string/app_name\"\n\t\tandroid:lines=\"1\"\n\t\ttools:ignore=\"SpUsage\"></TextView>\n\t<TextView\n\t\tandroid:id=\"@+id/txtWidgetAccountnameBlur\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:textColor=\"#a8a3a3\"\n\t\tandroid:textSize=\"11dp\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_marginLeft=\"2dp\"\n\t\tandroid:layout_marginRight=\"2dp\"\n\t\tandroid:text=\"@string/app_name\"\n\t\tandroid:lines=\"1\"\n\t\tandroid:visibility=\"gone\"\n\t\ttools:ignore=\"SpUsage\"></TextView>\n\t</LinearLayout>\n\t<LinearLayout\n\t\tandroid:id=\"@+id/layWidgetRow02\"\n\t\tandroid:layout_below=\"@+id/layWidgetRow01\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_marginTop=\"7dp\">\n\t\t<ImageView\n\t\t\tandroid:id=\"@+id/imgBalanceblur\"\n\t\t\tandroid:src=\"@drawable/widget_small_balance_blurred\"\n\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:scaleType=\"centerInside\"\n\t\t\tandroid:adjustViewBounds=\"false\"\n\t\t\tandroid:paddingTop=\"5dp\"\n\t\t\tandroid:visibility=\"gone\"></ImageView>\n\t\t<TextView\n\t\t\tandroid:textColor=\"#fff\"\n\t\t\tandroid:inputType=\"none\"\n\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:ellipsize=\"none\"\n\t\t\tandroid:gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:textSize=\"15dp\"\n\t\t\tandroid:id=\"@+id/txtWidgetAccountbalance\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:text=\"@string/loading\"\n\t\t\ttools:ignore=\"SpUsage\"/>\n\t</LinearLayout>\n\t<LinearLayout\n\t\t\tandroid:layout_below=\"@+id/layWidgetRow02\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:gravity=\"bottom\"\n\t\tandroid:layout_alignParentBottom=\"true\"\n\t\tandroid:visibility=\"visible\">\n\n\t\t<FrameLayout\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:id=\"@+id/frmProgress\"\n\t\t\tandroid:visibility=\"invisible\">\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:indeterminateOnly=\"true\"\n\t\t\t\tandroid:indeterminateBehavior=\"repeat\"\n\t\t\t\tandroid:indeterminate=\"true\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tstyle=\"@style/Widget_Progress\"\n\t\t\t\tandroid:maxHeight=\"2dp\"\n\t\t\t\tandroid:minHeight=\"2dp\"\n\t\t\t\tandroid:minWidth=\"17dp\"\n\t\t\t\tandroid:visibility=\"visible\"></ProgressBar>\n\t\t</FrameLayout>\n\t</LinearLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/widget_large.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_gravity=\"center_horizontal\"\n\tandroid:layout_height=\"100dp\"\n\tandroid:id=\"@+id/layWidgetContainer\"\n\tandroid:layout_width=\"320dp\"\n\tandroid:background=\"@drawable/widget_4x1\">\n\n\t<RelativeLayout\n\t\tandroid:id=\"@+id/RelativeLayout02\"\n\t\tandroid:paddingLeft=\"17dp\"\n\t\tandroid:paddingTop=\"24dp\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_alignParentLeft=\"true\"\n\t\tandroid:layout_alignParentTop=\"true\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:paddingRight=\"28dp\">\n\t\t<ImageView\n\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:id=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_gravity=\"center_vertical\"\n\t\t\tandroid:baselineAlignBottom=\"true\"\n\t\t\tandroid:scaleType=\"fitXY\"\n\t\t\tandroid:layout_height=\"52dp\"\n\t\t\tandroid:layout_width=\"52dp\"\n\t\t\tandroid:src=\"@drawable/icon_large\"></ImageView>\n\t\t<RelativeLayout\n\t\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:layout_toRightOf=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_width=\"fill_parent\">\n\t\t\t<ImageView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_toLeftOf=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:id=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:src=\"@drawable/widget_large_balance_blurred\"\n\t\t\t\tandroid:paddingTop=\"8dp\"\n\t\t\t\tandroid:paddingRight=\"1dp\"\n\t\t\t\tandroid:adjustViewBounds=\"true\"\n\t\t\t\tandroid:layout_centerInParent=\"true\"\n\t\t\t\tandroid:visibility=\"gone\"></ImageView>\n\t\t\t<TextView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:textColor=\"#a8a3a3\"\n\t\t\t\tandroid:textSize=\"11dp\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:gravity=\"right\"\n\t\t\t\tandroid:paddingTop=\"37dp\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountnameBlur\"\n\t\t\t\tandroid:layout_alignRight=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:layout_alignTop=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\ttools:ignore=\"SpUsage\"></TextView>\n\t\t\t<TextView\n\t\t\t\tandroid:textColor=\"#fff\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\t\tandroid:ellipsize=\"none\"\n\t\t\t\tandroid:gravity=\"center_vertical|center_horizontal\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_toRightOf=\"@+id/imgWidgetIcon\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_centerInParent=\"false\"\n\t\t\t\tandroid:layout_centerHorizontal=\"true\"\n\t\t\t\tandroid:text=\"@string/loading\"\n\t\t\t\tandroid:textSize=\"27dp\"\n\t\t\t\tandroid:paddingRight=\"1dp\"\n\t\t\t\tandroid:paddingTop=\"8dp\"\n\t\t\t\ttools:ignore=\"SpUsage\"/>\n\t\t\t<TextView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountname\"\n\t\t\t\tandroid:textColor=\"#a8a3a3\"\n\t\t\t\tandroid:textSize=\"11dp\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:layout_alignRight=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:gravity=\"right\"\n\t\t\t\tandroid:layout_alignTop=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:paddingTop=\"37dp\"\n\t\t\t\ttools:ignore=\"SpUsage\"></TextView>\n\n</RelativeLayout>\n\t</RelativeLayout>\n\t<RelativeLayout\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_alignTop=\"@+id/RelativeLayout02\"\n\t\tandroid:paddingTop=\"75dp\"\n\t\tandroid:paddingLeft=\"34dp\"\n\t\tandroid:id=\"@+id/hitBox\">\n\t\t<FrameLayout\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:id=\"@+id/frmProgress\"\n\t\t\tandroid:visibility=\"invisible\">\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:indeterminateOnly=\"true\"\n\t\t\t\tandroid:indeterminateBehavior=\"repeat\"\n\t\t\t\tandroid:indeterminate=\"true\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tstyle=\"@style/Widget_Progress\"\n\t\t\t\tandroid:minWidth=\"17dp\"\n\t\t\t\tandroid:visibility=\"visible\"\n\t\t\t\tandroid:minHeight=\"6dp\"\n\t\t\t\tandroid:maxHeight=\"6dp\"\n\t\t\t\tandroid:layout_gravity=\"top|center_horizontal\"></ProgressBar>\n\t\t</FrameLayout>\n\t</RelativeLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/widget_large_transparent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_gravity=\"center_horizontal\"\n\tandroid:layout_height=\"100dp\"\n\tandroid:id=\"@+id/layWidgetContainer\"\n\tandroid:layout_width=\"320dp\">\n\n\t<RelativeLayout\n\t\tandroid:id=\"@+id/RelativeLayout02\"\n\t\tandroid:paddingLeft=\"17dp\"\n\t\tandroid:paddingTop=\"24dp\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_alignParentLeft=\"true\"\n\t\tandroid:layout_alignParentTop=\"true\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:paddingRight=\"28dp\">\n\t\t<ImageView\n\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:id=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_gravity=\"center_vertical\"\n\t\t\tandroid:baselineAlignBottom=\"true\"\n\t\t\tandroid:scaleType=\"fitXY\"\n\t\t\tandroid:layout_height=\"52dp\"\n\t\t\tandroid:layout_width=\"52dp\"\n\t\t\tandroid:src=\"@drawable/icon_large\"></ImageView>\n\t\t<RelativeLayout\n\t\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:layout_toRightOf=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:layout_width=\"fill_parent\">\n\t\t\t<ImageView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_toLeftOf=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:id=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:src=\"@drawable/widget_large_balance_blurred\"\n\t\t\t\tandroid:paddingTop=\"8dp\"\n\t\t\t\tandroid:paddingRight=\"1dp\"\n\t\t\t\tandroid:adjustViewBounds=\"true\"\n\t\t\t\tandroid:layout_centerInParent=\"true\"\n\t\t\t\tandroid:visibility=\"gone\"></ImageView>\n\t\t\t<TextView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:textColor=\"#a8a3a3\"\n\t\t\t\tandroid:textSize=\"11dp\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:gravity=\"right\"\n\t\t\t\tandroid:paddingTop=\"37dp\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountnameBlur\"\n\t\t\t\tandroid:layout_alignRight=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:layout_alignTop=\"@+id/imgBalanceblur\"\n\t\t\t\tandroid:visibility=\"gone\"\n\t\t\t\ttools:ignore=\"SpUsage\"/>\n\t\t\t<TextView\n\t\t\t\tandroid:textColor=\"#fff\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\t\tandroid:ellipsize=\"none\"\n\t\t\t\tandroid:gravity=\"center_vertical|center_horizontal\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_toRightOf=\"@+id/imgWidgetIcon\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_centerInParent=\"false\"\n\t\t\t\tandroid:layout_centerHorizontal=\"true\"\n\t\t\t\tandroid:text=\"@string/loading\"\n\t\t\t\tandroid:textSize=\"27dp\"\n\t\t\t\tandroid:paddingRight=\"1dp\"\n\t\t\t\tandroid:paddingTop=\"8dp\"\n\t\t\t\ttools:ignore=\"SpUsage\"/>\n\t\t\t<TextView\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:id=\"@+id/txtWidgetAccountname\"\n\t\t\t\tandroid:textColor=\"#a8a3a3\"\n\t\t\t\tandroid:textSize=\"11dp\"\n\t\t\t\tandroid:inputType=\"none\"\n\t\t\t\tandroid:layout_alignRight=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:gravity=\"right\"\n\t\t\t\tandroid:layout_alignTop=\"@+id/txtWidgetAccountbalance\"\n\t\t\t\tandroid:paddingTop=\"37dp\"\n\t\t\t\ttools:ignore=\"SpUsage\"></TextView>\n\t\t</RelativeLayout>\n\t</RelativeLayout>\n\t<RelativeLayout\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_alignTop=\"@+id/RelativeLayout02\"\n\t\tandroid:paddingTop=\"75dp\"\n\t\tandroid:paddingLeft=\"34dp\"\n\t\tandroid:id=\"@+id/hitBox\">\n\t\t<FrameLayout\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:id=\"@+id/frmProgress\"\n\t\t\tandroid:visibility=\"invisible\">\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:indeterminateOnly=\"true\"\n\t\t\t\tandroid:indeterminateBehavior=\"repeat\"\n\t\t\t\tandroid:indeterminate=\"true\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tstyle=\"@style/Widget_Progress\"\n\t\t\t\tandroid:minWidth=\"17dp\"\n\t\t\t\tandroid:visibility=\"visible\"\n\t\t\t\tandroid:minHeight=\"6dp\"\n\t\t\t\tandroid:maxHeight=\"6dp\"\n\t\t\t\tandroid:layout_gravity=\"top|center_horizontal\"></ProgressBar>\n\t\t</FrameLayout>\n\t</RelativeLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/widget_transparent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_gravity=\"center_horizontal\"\n\n\tandroid:layout_height=\"100dp\"\n\tandroid:layout_width=\"160dp\"\n\tandroid:id=\"@+id/layWidgetContainer\"\n\tandroid:paddingTop=\"22dp\"\n\tandroid:paddingLeft=\"19dp\"\n\tandroid:paddingRight=\"18dp\"\n\tandroid:paddingBottom=\"20dp\">\n\n\t<FrameLayout\n\t\tandroid:layout_height=\"22dp\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:id=\"@+id/hitBox\"\n\t\tandroid:focusable=\"true\"/>\n\t<LinearLayout\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:id=\"@+id/layWidgetRow01\"\n\t\tandroid:layout_marginTop=\"0dp\">\n\t\t<ImageView\n\t\t\tandroid:layout_above=\"@+id/txtListitemAccountsItemAccountname\"\n\t\t\tandroid:layout_width=\"22dp\"\n\t\t\tandroid:layout_height=\"22dp\"\n\t\t\tandroid:id=\"@+id/imgWidgetIcon\"\n\t\t\tandroid:layout_gravity=\"center_vertical\"\n\t\t\tandroid:baselineAlignBottom=\"true\"\n\t\t\tandroid:src=\"@drawable/ic_launcher\"\n\t\t\tandroid:scaleType=\"fitXY\"/>\n\t<TextView\n\t\tandroid:id=\"@+id/txtWidgetAccountname\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:textColor=\"#a8a3a3\"\n\t\tandroid:textSize=\"11dp\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_marginLeft=\"2dp\"\n\t\tandroid:layout_marginRight=\"2dp\"\n\t\tandroid:text=\"@string/app_name\"\n\t\tandroid:lines=\"1\"\n\t\ttools:ignore=\"SpUsage\"/>\n\t<TextView\n\t\tandroid:id=\"@+id/txtWidgetAccountnameBlur\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_gravity=\"center_vertical\"\n\t\tandroid:textColor=\"#a8a3a3\"\n\t\tandroid:textSize=\"11dp\"\n\t\tandroid:inputType=\"none\"\n\t\tandroid:layout_marginLeft=\"2dp\"\n\t\tandroid:layout_marginRight=\"2dp\"\n\t\tandroid:text=\"@string/app_name\"\n\t\tandroid:lines=\"1\"\n\t\tandroid:visibility=\"gone\"\n\t\ttools:ignore=\"SpUsage\"/>\n\t</LinearLayout>\n\t<LinearLayout\n\t\tandroid:id=\"@+id/layWidgetRow02\"\n\t\tandroid:layout_below=\"@+id/layWidgetRow01\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:layout_marginTop=\"7dp\">\n\t\t<ImageView\n\t\t\tandroid:id=\"@+id/imgBalanceblur\"\n\t\t\tandroid:src=\"@drawable/widget_small_balance_blurred\"\n\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:scaleType=\"centerInside\"\n\t\t\tandroid:adjustViewBounds=\"false\"\n\t\t\tandroid:paddingTop=\"5dp\"\n\t\t\tandroid:visibility=\"gone\"/>\n\t\t<TextView\n\n\t\t\tandroid:textColor=\"#fff\"\n\t\t\tandroid:inputType=\"none\"\n\t\t\tandroid:layout_gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:ellipsize=\"none\"\n\t\t\tandroid:gravity=\"center_vertical|center_horizontal\"\n\t\t\tandroid:textSize=\"15dp\"\n\t\t\tandroid:id=\"@+id/txtWidgetAccountbalance\"\n\t\t\tandroid:layout_height=\"fill_parent\"\n\t\t\tandroid:text=\"@string/loading\"\n\t\t\ttools:ignore=\"SpUsage\"/>\n\t</LinearLayout>\n\t<LinearLayout\n\t\t\tandroid:layout_below=\"@+id/layWidgetRow02\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:gravity=\"bottom\"\n\t\tandroid:layout_alignParentBottom=\"true\"\n\t\tandroid:visibility=\"visible\">\n\n\t\t<FrameLayout\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:id=\"@+id/frmProgress\"\n\t\t\tandroid:visibility=\"invisible\">\n\t\t\t<ProgressBar\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:indeterminateOnly=\"true\"\n\t\t\t\tandroid:indeterminateBehavior=\"repeat\"\n\t\t\t\tandroid:indeterminate=\"true\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tstyle=\"@style/Widget_Progress\"\n\t\t\t\tandroid:maxHeight=\"2dp\"\n\t\t\t\tandroid:minHeight=\"2dp\"\n\t\t\t\tandroid:minWidth=\"17dp\"\n\t\t\t\tandroid:visibility=\"visible\"/>\n\t\t</FrameLayout>\n\t</LinearLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout-land/choose_lock_pattern.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the\n\tApache License, Version 2.0 (the \"License\"); you may not use this file except\n\tin compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n\tUnless required by applicable law or agreed to in writing, software distributed\n\tunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES\n\tOR CONDITIONS OF ANY KIND, either express or implied. See the License for\n\tthe specific language governing permissions and limitations under the License. -->\n\n<com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/topLayout\"\n\tandroid:orientation=\"horizontal\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"fill_parent\"\n\tandroid:background=\"@color/black\">\n\n\t<!-- left side: instructions and messages -->\n\t<LinearLayout\n\t\tandroid:orientation=\"vertical\"\n\t\tandroid:layout_width=\"0dip\"\n\t\tandroid:layout_height=\"fill_parent\"\n\t\tandroid:layout_weight=\"1.0\">\n\n\t\t<!-- header message -->\n\t\t<TextView\n\t\t\tandroid:id=\"@+id/headerText\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:textSize=\"18sp\" />\n\n\t\t<!-- footer can show a message, or confirm / restart buttons -->\n\t\t<RelativeLayout\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"0dip\"\n\t\t\tandroid:layout_weight=\"1.0\">\n\n\t\t\t<!-- right / bottom button: confirm or ok -->\n\t\t\t<Button\n\t\t\t\tandroid:id=\"@+id/footerRightButton\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"140dip\"\n\t\t\t\tandroid:layout_alignParentBottom=\"true\"\n\t\t\t\tandroid:layout_centerHorizontal=\"true\"\n\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\tandroid:drawableRight=\"@drawable/ic_btn_next\"\n\t\t\t\tandroid:drawablePadding=\"3dip\"\n\t\t\t\tandroid:text=\"@string/lockpattern_confirm_button_text\"\n\t\t\t\tandroid:maxLines=\"1\"/>\n\n\n\t\t\t<!-- left / top button: skip, or re-try -->\n\t\t\t<Button\n\t\t\t\tandroid:id=\"@+id/footerLeftButton\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_width=\"140dip\"\n\t\t\t\tandroid:layout_above=\"@id/footerRightButton\"\n\t\t\t\tandroid:layout_centerHorizontal=\"true\"\n\t\t\t\tandroid:ellipsize=\"marquee\"\n\t\t\t\tandroid:text=\"@string/lockpattern_restart_button_text\"\n\t\t\t\tandroid:maxLines=\"1\"/>\n\n\n\t\t\t<!-- message above buttons -->\n\t\t\t<TextView\n\t\t\t\tandroid:id=\"@+id/footerText\"\n\t\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\t\tandroid:layout_above=\"@+id/footerLeftButton\"\n\t\t\t\tandroid:layout_centerHorizontal=\"true\"\n\t\t\t\tandroid:layout_marginBottom=\"4dip\"\n\t\t\t\tandroid:textSize=\"14sp\" />\n\t\t</RelativeLayout>\n\t</LinearLayout>\n\n\t<View\n\t\tandroid:background=\"@drawable/code_lock_left\"\n\t\tandroid:layout_width=\"2dip\"\n\t\tandroid:layout_height=\"fill_parent\" />\n\t<!-- right side: lock pattern -->\n\t<com.liato.bankdroid.lockpattern.LockPatternView\n\t\tandroid:id=\"@+id/lockPattern\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\" />\n\n\n</com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient>\n\n"
  },
  {
    "path": "app/src/main/res/layout-land/confirm_lock_pattern.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the \n\tApache License, Version 2.0 (the \"License\"); you may not use this file except \n\tin compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 \n\tUnless required by applicable law or agreed to in writing, software distributed \n\tunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES \n\tOR CONDITIONS OF ANY KIND, either express or implied. See the License for \n\tthe specific language governing permissions and limitations under the License. -->\n\n<com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid:id=\"@+id/topLayout\"\n\tandroid:orientation=\"horizontal\"\n\tandroid:layout_width=\"fill_parent\"\n\tandroid:layout_height=\"fill_parent\"\n\tandroid:background=\"@color/black\">\n\n\t<!-- left side: instructions and messages -->\n\t<LinearLayout\n\t\tandroid:orientation=\"vertical\"\n\t\tandroid:layout_width=\"0dip\"\n\t\tandroid:layout_height=\"fill_parent\"\n\t\tandroid:layout_weight=\"1.0\">\n\n\t\t<!-- header message -->\n\t\t<TextView\n\t\t\tandroid:id=\"@+id/headerText\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:textSize=\"18sp\" />\n\n\t\t<!-- fill space between header and button below -->\n\t\t<View\n\t\t\tandroid:layout_weight=\"1.0\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"0dip\" />\n\n\t\t<!-- footer message -->\n\t\t<TextView\n\t\t\tandroid:id=\"@+id/footerText\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:textSize=\"14sp\" />\n\t</LinearLayout>\n\n\t<View\n\t\tandroid:background=\"@drawable/code_lock_left\"\n\t\tandroid:layout_width=\"2dip\"\n\t\tandroid:layout_height=\"fill_parent\" />\n\t<!-- right side: lock pattern -->\n\t<com.liato.bankdroid.lockpattern.LockPatternView\n\t\tandroid:id=\"@+id/lockPattern\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\" />\n\n\n</com.liato.bankdroid.lockpattern.LinearLayoutWithDefaultTouchRecepient>\n\n"
  },
  {
    "path": "app/src/main/res/layout-land/dialog_color_picker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2010 Daniel Nilsson\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<LinearLayout\n\txmlns:android=\"http://schemas.android.com/apk/res/android\"\n\txmlns:tools=\"http://schemas.android.com/tools\"\n\tandroid:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:paddingLeft=\"5dp\"\n    android:paddingRight=\"5dp\"\n    android:orientation=\"horizontal\">\n\n\t<net.margaritov.preference.colorpicker.ColorPickerView\n\t\tandroid:id=\"@+id/color_picker_view\"\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:tag=\"landscape\"\n\t/>\n\n\t<LinearLayout\n\t\tandroid:layout_width=\"wrap_content\"\n\t\tandroid:layout_height=\"wrap_content\"\n\t\tandroid:orientation=\"vertical\"\n\t\tandroid:layout_marginBottom=\"10dp\">\n\n\t\t<TextView\n\t\t\tandroid:layout_width=\"wrap_content\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:text=\"@string/press_color_to_apply\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:layout_marginTop=\"6dp\"\n\t\t\tandroid:layout_marginLeft=\"6dp\"\n\t\t\tandroid:layout_marginRight=\"6dp\"\n\t\t\tandroid:layout_marginBottom=\"5dp\"\n\t\t\tandroid:textAppearance=\"?android:attr/textAppearanceSmall\"\n\t\t/>\n\n\t\t<net.margaritov.preference.colorpicker.ColorPickerPanelView\n\t\t\tandroid:id=\"@+id/old_color_panel\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"40dp\"\n\t\t\tandroid:layout_weight=\"0.5\"\n\t\t/>\n\n\t\t<TextView\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"wrap_content\"\n\t\t\tandroid:text=\"↓\"\n\t\t\tandroid:textSize=\"20sp\"\n\t\t\tandroid:gravity=\"center\"\n\t\t\tandroid:layout_marginTop=\"10dp\"\n\t\t\tandroid:layout_marginBottom=\"10dp\"\n\t\t\ttools:ignore=\"HardcodedText\"/>\n\n\t\t<net.margaritov.preference.colorpicker.ColorPickerPanelView\n\t\t\tandroid:id=\"@+id/new_color_panel\"\n\t\t\tandroid:layout_width=\"fill_parent\"\n\t\t\tandroid:layout_height=\"40dp\"\n\t\t\tandroid:layout_weight=\"0.5\"\n\t\t/>\n\n\t</LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/menu/about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_web\"\n        android:icon=\"@drawable/ic_menu_web\"\n        android:showAsAction=\"always\"\n        android:title=\"@string/popup_www\"\n        app:showAsAction=\"always\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_refresh\"\n        android:icon=\"@drawable/ic_menu_refresh\"\n        android:showAsAction=\"always\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/action_add\"\n        android:title=\"@string/add_account\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_settings\"\n        android:title=\"@string/settings\"\n        app:showAsAction=\"never\" />\n    <item\n        android:id=\"@+id/action_toggle_hidden\"\n        android:title=\"@string/menu_show_hidden\"\n        app:showAsAction=\"never\" />\n    <item\n        android:id=\"@+id/action_about\"\n        android:title=\"@string/about\"\n        app:showAsAction=\"never\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/values/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string-array\n\t\tname=\"refreshrateNames\">\n\t\t<item>15 minutes</item>\n\t\t<item>30 minutes</item>\n\t\t<item>1 hour</item>\n\t\t<item>2 hour</item>\n\t\t<item>4 hour</item>\n\t\t<item>8 hours</item>\n\t\t<item>16 hours</item>\n\t\t<item>Daily</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"refreshrateValues\">\n\t\t<item>15</item>\n\t\t<item>30</item>\n\t\t<item>60</item>\n\t\t<item>120</item>\n\t\t<item>240</item>\n\t\t<item>480</item>\n\t\t<item>960</item>\n\t\t<item>1440</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"unblurTimeoutNames\">\n\t\t<item>1 second</item>\n\t\t<item>2 seconds</item>\n\t\t<item>3 seconds</item>\n\t\t<item>4 seconds</item>\n\t\t<item>5 seconds</item>\n\t\t<item>10 seconds</item>\n\t\t<item>15 seconds</item>\n\t\t<item>20 seconds</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"unblurTimeoutValues\">\n\t\t<item>1</item>\n\t\t<item>2</item>\n\t\t<item>3</item>\n\t\t<item>4</item>\n\t\t<item>5</item>\n\t\t<item>10</item>\n\t\t<item>15</item>\n\t\t<item>20</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"numNotificationsNames\">\n\t\t<item>One</item>\n   \t\t<item>One per bank</item>\n\t\t<item>One per account</item>\n\t\t<item>One per change</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"numNotificationsValues\">\n\t\t<item>total</item>\n\t\t<item>bank</item>\n\t\t<item>account</item>\n\t\t<item>change</item>\n\t</string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2007 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<resources>\n    <color name=\"black\">#000</color>\n    <color name=\"colorPrimary\">#212121</color>\n    <color name=\"colorPrimaryDark\">#212121</color>\n</resources>\n\n"
  },
  {
    "path": "app/src/main/res/values/config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"default_led_color\">#ff0000ff</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources  xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"version\">Version $version by</string>\n    <string name=\"app_name\" translatable=\"false\">Bankdroid</string>\n    <string name=\"widget_name_small\">Bankdroid (Small)</string>\n    <string name=\"widget_name_large\">Bankdroid (Large)</string>\n    <string name=\"about\">About</string>\n    <string name=\"accounts_were_not_updated\">Balance for the following accounts could not be updated</string>\n    <string name=\"updating_account_balance\">Refreshing account balance…</string>\n    <string name=\"errors_when_updating\">Errors while refreshing</string>\n    <string name=\"logging_in\">Signing in…</string>\n    <string name=\"could_not_create_account\">Could not create account</string>\n\t<string name=\"transparent_background\">Transparent background</string>\n    <string name=\"settings\">Settings</string>\n    <string name=\"refresh\">Refresh</string>\n    <string name=\"add_account\">Add account</string>\n\t<string name=\"loading\">Loading…</string>\n\n\n    <string name=\"optional_field\">(optional)</string>\n\n    <string name=\"bank\">Bank</string>\n    <string name=\"error_desc\">The last update was unsuccessful and updates for this account have been disabled. Make sure you\\'ve entered your username and password correctly and press the save button.</string>\n\n    <string name=\"save\">SAVE</string>\n\n\t<string name=\"add_new_account\">ADD BANK</string>\n\n\t<string name=\"main_instructions\">You have not added any bank accounts yet, press the “Accounts” button in the menu to add a new account.</string>\n\t<string name=\"refresh_balance\">REFRESH</string>\n\n\t<string name=\"choose_an_account\">Choose an account</string>\n\n\n\t<!--  Settings  -->\n\t<string name=\"security_and_privacy\">Security and Privacy</string>\n\t<string name=\"enable_patternlock_title\">Enable Pattern Lock</string>\n\t<string name=\"enable_patternlock_summary\">Lock the app and widgets with a pattern lock</string>\n\t<string name=\"change_patternlock_title\">Change lock pattern</string>\n\t<string name=\"change_patternlock_summary\">Change your current lock pattern</string>\n\t<string name=\"blur_widget_title\">Blur widget balance</string>\n\t<string name=\"blur_widget_summary\">Blur the balance on the widget, click widget to unblur for a few seconds</string>\n\t<string name=\"unblur_widget_timeout_title\">Unblur timeout</string>\n\t<string name=\"unblur_widget_timeout_summary\">Blur the balance again after this many seconds</string>\n\t<string name=\"automatic_updates_title\">Automatic Updates</string>\n\t<string name=\"autoupdates_enabled_title\">Enable</string>\n\t<string name=\"autoupdates_enabled_summary\">Enable automatic updates</string>\n    <string name=\"roaming\">Roaming</string>\n    <string name=\"disable_during_roaming\">Disable automatic updates if roaming</string>\n\t<string name=\"update_frequency_title\">Update frequency</string>\n\t<string name=\"update_start_title\">Update start time</string>\n\t<string name=\"update_stop_title\">Update end time</string>\n\t<string name=\"update_transaction_history_title\">Update transaction history</string>\n\t<string name=\"update_transaction_history_summary\">Update transaction history when updating automatically</string>\n\t<string name=\"number_of_notifications_title\">Number of notifications</string>\n\t<string name=\"number_of_notifications_summary\">Number of notifications to display simultaneously</string>\n\t<string name=\"appearance_title\">Appearance</string>\n\t<string name=\"widgets_title\">Widgets</string>\n\t<string name=\"round_widget_balance_title\">Round widget balance</string>\n\t<string name=\"round_widget_balance_summary\">Display the balance on widgets without decimals</string>\n\t<string name=\"round_balance_title\">Round balance</string>\n\t<string name=\"round_balance_summary\">Display the balance without decimals</string>\n\t<string name=\"notify_min_delta_title\">Minimum change</string>\n\t<string name=\"notify_min_delta_summary\">Only display a notification if the change is at least this big</string>\n\t<string name=\"widget_opens_transactions_title\">Widget click opens transactions</string>\n\t<string name=\"widget_opens_transactions_summary\">If unchecked the main screen is shown</string>\n\t<string name=\"widget_updates_transactions_title\">Update transactions from widget</string>\n\t<string name=\"widget_updates_transactions_summary\">Updates from widgets will update both the balance and the transaction history</string>\n\t<string name=\"notifications_title\">Notifications</string>\n\t<string name=\"enable_notifications_title\">Enable notifications</string>\n\t<string name=\"enable_notifications_summary\">Notify on account changes</string>\n\t<string name=\"vibrate_title\">Vibrate</string>\n\t<string name=\"vibrate_summary\">Vibrate on account changes</string>\n\t<string name=\"led_title\">Flash LED</string>\n\t<string name=\"led_summary\">Flash the LED on account changes (not supported by all devices)</string>\n\t<string name=\"led_color_title\">LED color</string>\n   \t<string name=\"notification_sound_title\">Notification sound</string>\n\t<string name=\"notification_sound_summary\">Select notification sound</string>\n\t<string name=\"notification_sound_name\">Select sound</string>\n\t<string name=\"notify_delta_only_title\">Display change only</string>\n\t<string name=\"notify_delta_only_summary\">Don\\'t display the account balance in the notification</string>\n\t<string name=\"account_types_title\">Account types</string>\n\t<string name=\"account_types_summary\">Only show notifications for selected account types</string>\n\t<string name=\"remote_notifier_title\">Remote Notifier Integration</string>\n\t<string name=\"remote_notifier_enable_title\">Enable</string>\n\t<string name=\"remote_notifier_enable_summary\">Enable Remote Notifier integration</string>\n\t<string name=\"remote_notifier_help_title\">What is Remote Notifier?</string>\n\t<string name=\"remote_notifier_help_summary\">Read more about Remote Notifier on their website</string>\n\t<string name=\"openwatch_title\">OpenWatch Integration</string>\n\t<string name=\"openwatch_enable_title\">Enable</string>\n\t<string name=\"openwatch_enable_summary\">Enable OpenWatch integration</string>\n\t<string name=\"openwatch_vibrate_title\">Vibrate</string>\n\t<string name=\"openwatch_vibrate_summary\">Vibrate the OpenWatch device</string>\n\t<string name=\"openwatch_help_title\">What is OpenWatch?</string>\n\t<string name=\"openwatch_help_summary\">Read more about OpenWatch on their website</string>\n\t<string name=\"liveview_title\">LiveView Integration</string>\n\t<string name=\"liveview_enable_title\">Enable</string>\n\t<string name=\"liveview_enable_summary\">Enable Sony Ericsson LiveView integration</string>\n\t<string name=\"liveview_help_title\">What is LiveView?</string>\n\t<string name=\"liveview_help_summary\">Read more about LiveView on Sony Ericsson\\'s website</string>\n\t<string name=\"share_data_title\">Share data</string>\n\t<string name=\"share_data_enable_title\">Enable data sharing</string>\n\t<string name=\"share_data_enable_summary\">Grant other installed apps access to your transaction history</string>\n\t<string name=\"api_key_title\">API Key</string>\n\t<string name=\"api_key_summary\">Use this key to allow access for trusted applications</string>\n\n\t<string name=\"funds\">Funds</string>\n\t<string name=\"ccards\">Credit cards</string>\n\t<string name=\"loans\">Loans</string>\n\t<string name=\"deposit_account\">Deposit accounts</string>\n\t<string name=\"other\">Other</string>\n\t<!--  /Settings  -->\n\n\n\t<string name=\"popup_refresh\">Refresh</string>\n    <string name=\"popup_edit\">Edit</string>\n    <string name=\"popup_www\">WWW</string>\n    <string name=\"popup_remove\">Remove</string>\n\n    <string name=\"popup_hide\">Hide</string>\n    <string name=\"popup_unhide\">Unhide</string>\n    <string name=\"popup_hide_a\">Hide\\naccounts</string>\n    <string name=\"popup_unhide_a\">Unhide\\naccounts</string>\n    <string name=\"popup_enable_notifications\">Enable notifications</string>\n    <string name=\"popup_disable_notifications\">Disable notifications</string>\n\n    <string name=\"remove_bank_msg\">Are you sure you want to remove this bank?</string>\n    <string name=\"remove_bank_title\">Remove bank?</string>\n    <string name=\"yes\">Yes</string>\n    <string name=\"no\">No</string>\n\n    <string name=\"menu_show_hidden\">Show hidden accounts</string>\n    <string name=\"menu_hide_hidden\">Hide hidden accounts</string>\n\n    <string name=\"tran_desc\">No transaction history available for this account.</string>\n\t<string name=\"disabled_refresh_or_edit\">Our last connection attempt to this bank failed and further updates for this bank have been disabled. Manually refresh the bank to try again or open the settings for this bank and check your credentials.</string>\n\n    <string name=\"thanks_to\">Thanks to</string>\n    <string name=\"thanks\" translatable=\"false\">\n    Wendell Fernandes (Icon)\n    \\nKingcool (ICA Banken &amp; SEB)\n    \\ngrief (Länsförsäkringar)\n    \\neinand (Länsförsäkringar)\n    \\nAnders Widén (Länsförsäkringar)\n    \\nHund (Handelsbanken)\n    \\nTravolta (Coop)\n    \\nDaniel Malmgren (Coop)\n    \\nisocron (ICA)\n    \\nDustin (ICA)\n    \\ndimaZ (Statoil)\n    \\nOxygen (Statoil &amp; Nordea)\n\t\\nOzzy (Avanza)\n\t\\nasperon (Transparent widget)\n\t\\nDEGE (Handelsbanken)\n\t\\ncola (OKQ8)\n\t\\nRikko (FirstCard)\n\t\\nNihplod (Eurocard)\n\t\\nDaniel (Avanza)\n\t\\nRadioman62 (Coop)\n\t\\ns3 (Steam Wallet)\n\t\\nVarazir (Jojo Reskassa)\n\t\\nJohan (Länsförsäkringar)\n\t\\nRadioman62 (Handelsbanken)\n\t\\nLibodido (Coop)\n\t\\ngust (Handelsbanken)\n\t\\nbernard (Diners Club)\n\t\\npilang (Länsförsäkringar)\n\t\\nMidde (Ikano Bank)\n\t\\nweppe (Coop)\n\t\\nmagnusart (Content Provider)\n\t\\nPMC (Rikslunchen)\n\t\\nmhagander (Diners Club &amp; SAS EuroBonus Mastercard)\n\t\\nfiretech (Hemköp Kundkort)\n\t\\nebjsv (PayPal)\n\t\\nHenrik (SEB)\n\t\\nMicke (American Express)\n\t\\nsjoch (Handelsbanken Finans &amp; Resurs Bank &amp; CSN)\n\t\\nThomas (Sevenday)\n\t\\nKalle (Nordnet)\n\t\\ncork (Volvofinans)\n\t\\nmarijo (Eurocard)\n\t\\nd98rolb (Osuuspankki)\n\t\\nAndreas Gunnerås (Everydaycard)\n\t\\nEmil Andersson (Chalmrest)\n\t\\Richard Ginzburg (Forex Bank)\n     </string>\n\n\n    <!-- Lock Pattern settings -->\n    <!-- Unlock header -->\n    <string name=\"patternlock_header\">Draw pattern to unlock Bankdroid</string>\n    <!-- Security & location settings screen, header -->\n\t<!-- Security & location settings screen, setting option name -->\n\t<!-- Security & location settings screen, change unlock pattern screen instruction when the user chooses \"Change unlock pattern\".  We first ask the user toe nter the current pattern, and this is the message seen -->\n    <string name=\"lockpattern_need_to_unlock\">Confirm saved pattern</string>\n    <!-- Do not translate. -->\n    <string name=\"lockpattern_need_to_unlock_footer\"></string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction if user draws incorrect pattern -->\n    <string name=\"lockpattern_need_to_unlock_wrong\">Sorry, try again:</string>\n    <!-- Do not translate. -->\n    <string name=\"lockpattern_need_to_unlock_wrong_footer\"></string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen.  This si when they are supposed to draw a new unlock pattern (for example, if they are changing their unlock patterns)..-->\n    <string name=\"lockpattern_recording_intro_header\">Draw an unlock pattern</string>\n    <!-- Security & location settings screen, change unlock pattern screen hint on bottom of screen.  We are telling them to press the menu button to see more options or help. -->\n    <string name=\"lockpattern_recording_intro_footer\">Press Menu for help.</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen while drawing pattern -->\n    <string name=\"lockpattern_recording_inprogress\">Release finger when done.</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen if user doesn't connect enough dots -->\n    <string name=\"lockpattern_recording_incorrect_too_short\">Connect at least <xliff:g id=\"number\">%d</xliff:g> dots. Try again:</string>\n    <!-- Security & location settings screen, change unlock pattern screen message on top of screen after drawing pattern -->\n    <string name=\"lockpattern_pattern_entered_header\">Pattern recorded!</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen to confirm pattern -->\n    <string name=\"lockpattern_need_to_confirm\">Draw pattern again to confirm:</string>\n    <string name=\"lockpattern_pattern_confirmed_header\">Your new unlock pattern:</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen.  After they draw a pattern and release their finger, we display the pattern so they remember.  When they are ready to draw it once again to confirm it, they press this button. -->\n    <string name=\"lockpattern_confirm_button_text\">Confirm</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen.  After they draw a pattern and release their finger, we display the pattern so they remember.  If they are nto satisfied with this pattern, they click this button to redraw the pattern. -->\n    <string name=\"lockpattern_restart_button_text\">Redraw</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen. If they are supposed to enter their current pattern before being able to draw another one, and they screw up, they hit this button to try again -->\n    <string name=\"lockpattern_retry_button_text\">Retry</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen. Once they draw a new pattern and confirm it by drawing it again, they press this button to exit -->\n    <string name=\"lockpattern_continue_button_text\">Continue</string>\n    <!-- Security & location settings screen, unlock screen activity title -->\n\t<!-- Security & location settings screen, setting check box title if the unlock pattern MUST be drawn everytime they turn on the screen -->\n\t<!-- Security & location settings screen, setting summary for the checkbox \"Require pattern\" -->\n\t<!-- Security & location settings screen, setting check box title. This setting controls whether a visible green line is drawn as the user moves his finger around while drawing the unlock pattern.  If checked, this line is drawn.  If unchecked, there is nothing drawn so the user does not reveal his pattern while he unlocks the phone.-->\n    <string name=\"lockpattern_settings_enable_visible_pattern_title\">Use visible pattern</string>\n    <!-- Security & location settings screen, setting check box title. This setting controls whether tactile feedback will be produced when the user draws the pattern.-->\n    <string name=\"lockpattern_settings_enable_tactile_feedback_title\">Use tactile feedback</string>\n    <!-- Security & location settings screen, setting option name when user has never set an unlock pattern -->\n\t<!-- Security & location settings screen, setting option name when user has previously set an unlock pattern and wants to change to a new pattern -->\n\t<!-- Security & location settings screen, the help instructions (an animation) caption -->\n    <string name=\"lockpattern_settings_help_how_to_record\">How to draw an unlock pattern</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen after too many incorrect attempts -->\n    <string name=\"lockpattern_too_many_failed_confirmation_attempts_header\">Too many incorrect attempts!</string>\n    <!-- Security & location settings screen, change unlock pattern screen countdown hint on bottom of screen after too many incorrect attempts -->\n    <string name=\"lockpattern_too_many_failed_confirmation_attempts_footer\">Try again in <xliff:g id=\"number\">%d</xliff:g> seconds.</string>\n\n    <!-- ChooseLockPatternTutorial --> <skip />\n    <!-- ChooseLockPatternTutorial, button labels: This is to cancel the tutorial -->\n    <string name=\"skip_button_label\">Cancel</string>\n    <!-- ChooseLockPatternTutorial, button labels: Continue to the next page of the tutorial -->\n    <string name=\"next_button_label\">Next</string>\n    <!-- ChooseLockPatternTutorial, tutorial screen title -->\n    <string name=\"lock_title\">Securing your phone</string>\n    <!-- ChooseLockPatternTutorial, tutorial screen text -->\n    <string name=\"lock_intro_message\"><font size=\"17\">Protect your phone from unauthorized use by creating a personal screen unlock pattern.\n        \\n<font height=\"17\">\\n</font><b>1</b>\\u00A0 On the next screen, watch while an example pattern is drawn.\n        \\n<font height=\"17\">\\n</font><b>2</b>\\u00A0 When ready, draw your own personal unlock pattern. Experiment with different patterns but connect at least four dots.\n        \\n<font height=\"17\">\\n</font><b>3</b>\\u00A0 Redraw your pattern to confirm.\n        \\n<font height=\"17\">\\n</font><b>Ready to start? Select \\u201CNext\\u201D</b>.\n        \\n<font height=\"3\">\\n</font>To leave your phone unprotected, select \\u201CCancel\\u201D.</font>\n    </string>\n\n    <!-- ChooseLockPatternExample --> <skip />\n    <!-- ChooseLockPatternExample, screen title that shows an example pattern -->\n    <string name=\"lock_example_title\">Example pattern</string>\n    <!-- ChooseLockPatternExample, screen hint text at bottom of screen. These are instructions and rules for drawing a good patttern -->\n    <string name=\"lock_example_message\">Connect at least four dots.\\n\n        \\nSelect \\u201CNext\\u201D when you\\u2019re ready to draw your own pattern.\n    </string>\n\n\t<string name=\"permission_provider_label\">Basic account information and the transaction history</string>\n\t<string name=\"permission_provider_desc\">Allows the application to access what banks and accounts are configured in BankDroids. Your Bank credentials are not exposed. Transaction history can also be accessed.</string>\n\n\t<string name=\"select_a_bank\">Select a bank</string>\n\t<string name=\"invalid_integer\">%1$s is not a valid positive integer, please try again.</string>\n\t<string name=\"pair_message\">The Application below wants to access account types and transaction data from BankDroid.</string>\n\t<string name=\"approve\">APPROVE</string>\n\t<string name=\"pair_app_name\">Unknown application</string>\n\n    <!-- Color Picker -->\n    <string name=\"dialog_color_picker\">Color Picker</string>\n    <string name=\"press_color_to_apply\">Press on Color to apply</string>\n\n    <!-- Error messages -->\n    <string name=\"error_bank_not_found\">The chosen bank could not be found.</string>\n    <string name=\"error_account_not_found\">The chosen account could not be found.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\t<style\n\t\tname=\"Widget_Progress\">\n\t\t<item\n\t\t\tname=\"android:indeterminateDrawable\">@drawable/widget_progress</item>\n\t\t<item\n\t\t\tname=\"android:minWidth\">17dip</item>\n\t\t<item\n\t\t\tname=\"android:maxWidth\">17dip</item>\n\t\t<item\n\t\t\tname=\"android:minHeight\">2dip</item>\n\t\t<item\n\t\t\tname=\"android:maxHeight\">2dip</item>\n\t</style>\n  <style name=\"Menu_Button\" parent=\"@android:style/Widget.Button\">\n\t<item name=\"android:layout_height\">wrap_content</item>\n\t<item name=\"android:paddingTop\">10dp</item>\n\t<item name=\"android:paddingBottom\">4dp</item>\n\t<item name=\"android:paddingLeft\">5dp</item>\n\t<item name=\"android:textColor\">#fff</item>\n\t<item name=\"android:background\">@drawable/menu_button</item>\n\t<item name=\"android:gravity\">center_vertical|center_horizontal</item>\n\t<item name=\"android:drawablePadding\">0dp</item>\n\t<item name=\"android:layout_width\">fill_parent</item>\n  </style>\n  <style name=\"Popup_Button\" parent=\"@android:style/Widget.Button\">\n\t<item name=\"android:layout_width\">wrap_content</item>\n\t<item name=\"android:layout_height\">fill_parent</item>\n\t<item name=\"android:paddingTop\">4dp</item>\n\t<item name=\"android:paddingBottom\">4dp</item>\n\t<item name=\"android:paddingLeft\">4dp</item>\n\t<item name=\"android:paddingRight\">4dp</item>\n\t<item name=\"android:textColor\">#fff</item>\n\t<item name=\"android:textSize\">12sp</item>\n\t<item name=\"android:minWidth\">50dp</item>\n\t<item name=\"android:background\">@drawable/popup_button</item>\n\t<item name=\"android:gravity\">center_vertical|center_horizontal</item>\n  </style>\n  <style name=\"Popup_Separator\">\n\t\t<item name=\"android:layout_width\">wrap_content</item>\n\t\t<item name=\"android:background\">@drawable/popup_separator</item>\n\t\t<item name=\"android:layout_height\">fill_parent</item>\n  </style>\n\n\t<style name=\"Animations\" />\n\n\t<style name=\"Animations.GrowFromBottom\">\n\t\t<item name=\"@android:windowEnterAnimation\">@anim/grow_from_bottom</item>\n\t\t<item name=\"@android:windowExitAnimation\">@anim/shrink_from_top</item>\n\t</style>\n\n\t<style name=\"Animations.GrowFromTop\">\n\t\t<item name=\"@android:windowEnterAnimation\">@anim/grow_from_top</item>\n\t\t<item name=\"@android:windowExitAnimation\">@anim/shrink_from_bottom</item>\n\t</style>\n\n\t<style name=\"Animations.PopDownMenu\">\n\t\t<item name=\"@android:windowEnterAnimation\">@anim/grow_from_topleft_to_bottomright</item>\n\t\t<item name=\"@android:windowExitAnimation\">@anim/shrink_from_bottomright_to_topleft</item>\n\t</style>\n\n\t<style name=\"listViewStyle\" parent=\"@android:style/Widget.ListView\">\n    \t<item name=\"android:cacheColorHint\">@android:color/transparent</item>\n    </style>\n    <style name=\"checkBoxStyle\" parent=\"@android:style/Widget.CompoundButton.CheckBox\">\n    \t<item name=\"android:button\">@drawable/btn_check</item>\n    \t<item name=\"android:background\">@drawable/btn_check_label_background</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!--<style name=\"BankdroidTheme\" parent=\"android:Theme.Black\">-->\n        <!--<item name=\"android:windowTitleSize\">40dp</item>-->\n        <!--<item name=\"android:windowTitleBackgroundStyle\">@style/WindowTitleBackground</item>-->\n    <!--</style>-->\n\n\n        <style name=\"BankdroidTheme\" parent=\"BaseTheme\"/>\n\n        <style name=\"BaseTheme\" parent=\"Theme.AppCompat.NoActionBar\">\n            <item name=\"colorPrimary\">@color/colorPrimary</item>\n            <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n            <item name=\"android:windowNoTitle\">true</item>\n            <item name=\"windowActionBar\">false</item>\n            <item name=\"android:windowBackground\">@drawable/background_repeat</item>\n            <item name=\"android:listViewStyle\">@style/listViewStyle</item>\n            <!--<item name=\"android:checkboxStyle\">@style/checkBoxStyle</item>-->\n        </style>\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values-sv/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<string-array\n\t\tname=\"refreshrateNames\">\n\t\t<item>15 minuter</item>\n\t\t<item>30 minuter</item>\n\t\t<item>1 timme</item>\n\t\t<item>2 timmar</item>\n\t\t<item>4 timmar</item>\n\t\t<item>8 timmar</item>\n\t\t<item>16 timmar</item>\n\t\t<item>Dagligen</item>\n\t</string-array>\n\t<string-array\n\t\tname=\"unblurTimeoutNames\">\n\t\t<item>1 sekund</item>\n\t\t<item>2 sekunder</item>\n\t\t<item>3 sekunder</item>\n\t\t<item>4 sekunder</item>\n\t\t<item>5 sekunder</item>\n\t\t<item>10 sekunder</item>\n\t\t<item>15 sekunder</item>\n\t\t<item>20 sekunder</item>\n\t</string-array>\t\n\t<string-array\n\t\tname=\"numNotificationsNames\">\n\t\t<item>En</item>\n   \t\t<item>En per bank</item>\n\t\t<item>En per konto</item>\n\t\t<item>En per kontoändring</item>\n\t</string-array>\t\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n\n    <string name=\"about\">Om</string>\n    <string name=\"version\">Version $version av</string>\n    <string name=\"widget_name_small\">Bankdroid (Liten)</string>\n    <string name=\"widget_name_large\">Bankdroid (Stor)</string>\n    <string name=\"accounts_were_not_updated\">Saldon för följande konton har ej uppdaterats</string>\n    <string name=\"updating_account_balance\">Uppdaterar saldoinformation…</string>\n    <string name=\"errors_when_updating\">Fel vid uppdatering</string>\n    <string name=\"logging_in\">Loggar in…</string>\n    <string name=\"could_not_create_account\">Kunde ej skapa konto</string>\n\t<string name=\"transparent_background\">Transparent bakgrund</string>\n    <string name=\"settings\">Inställningar</string>\n    <string name=\"refresh\">Uppdatera</string>\n    <string name=\"add_account\">Lägg till konto</string>\n\n    <string name=\"bank\">Bank</string>\n    <string name=\"optional_field\">(frivilligt)</string>\n    <string name=\"error_desc\">Senaste uppdateringsförsöket misslyckades och uppdateringar för detta konto har inaktiverats. Se till att lösenord och användarnamn är korrekt angivet och tryck på spara-knappen.</string>\n\n    <string name=\"save\">SPARA</string>\n\n\t<string name=\"add_new_account\">LÄGG TILL BANK</string>\n\n\t<string name=\"main_instructions\">Du har inte lagt till någon bank ännu, gå till menyn och tryck på konton för att lägga till ett nytt bankkonto.</string>\n\t<string name=\"refresh_balance\">UPPDATERA</string>\n\n\t<string name=\"choose_an_account\">Välj ett konto</string>\n\n\t<!--  Settings  -->\n\t<string name=\"security_and_privacy\">Säkerhet</string>\n\t<string name=\"enable_patternlock_title\">Aktivera grafiskt lösenord</string>\n\t<string name=\"enable_patternlock_summary\">Skydda appen och widgets med ett grafiskt lösenord</string>\n\t<string name=\"change_patternlock_title\">Ändra grafiskt lösenord</string>\n\t<string name=\"change_patternlock_summary\">Ändra ditt nuvarande grafiska lösenord</string>\n\t<string name=\"blur_widget_title\">Dölj widgetsaldo</string>\n\t<string name=\"blur_widget_summary\">Saldot på widgeten visas endast då du klickat på den</string>\n\t<string name=\"unblur_widget_timeout_title\">Dölj saldot efter</string>\n\t<string name=\"unblur_widget_timeout_summary\">Dölj saldot igen efter angiven tid</string>\n\t<string name=\"automatic_updates_title\">Automatiska Uppdateringar</string>\n\t<string name=\"autoupdates_enabled_title\">Aktivera</string>\n\t<string name=\"autoupdates_enabled_summary\">Aktivera automatiska uppdateringar</string>\n    <string name=\"roaming\">Roaming</string>\n    <string name=\"disable_during_roaming\">Avaktivera automatiska uppdateringar vid roaming</string>\n    <string name=\"update_frequency_title\">Uppdateringsfrekvens</string>\n\t<string name=\"update_start_title\">Starttid uppdatering</string>\n\t<string name=\"update_stop_title\">Sluttid uppdatering</string>\n\t<string name=\"update_transaction_history_title\">Uppdatera kontoutdrag</string>\n\t<string name=\"update_transaction_history_summary\">Uppdatera kontoutdrag vid automatiska uppdateringar</string>\n\t<string name=\"number_of_notifications_title\">Antal notifieringar</string>\n\t<string name=\"number_of_notifications_summary\">Antal notifieringar som visas samtidigt</string>\n\t<string name=\"appearance_title\">Utseende</string>\n\t<string name=\"widgets_title\">Widgets</string>\n\t<string name=\"round_widget_balance_title\">Avrunda saldo på widgets</string>\n\t<string name=\"round_widget_balance_summary\">Visa saldot på widgets utan decimaler</string>\n\t<string name=\"round_balance_title\">Avrunda saldo</string>\n\t<string name=\"round_balance_summary\">Visa saldot på banker och konton utan decimaler</string>\n\t<string name=\"notify_min_delta_title\">Minsta förändring</string>\n\t<string name=\"notify_min_delta_summary\">Visa endast notifiering om saldoförändringar är minst så här stor</string>\n\t<string name=\"widget_opens_transactions_title\">Widget-klick öppnar kontoutdrag</string>\n\t<string name=\"widget_opens_transactions_summary\">Öppna kontoutdraget för kontot när du klickar på en widget</string>\n\t<string name=\"widget_updates_transactions_title\">Uppdatera kontoutdrag från widget</string>\n\t<string name=\"widget_updates_transactions_summary\">Uppdatering från widget uppdaterar både saldo och kontoutdrag</string>\n\t<string name=\"notifications_title\">Notifieringar</string>\n\t<string name=\"enable_notifications_title\">Aktivera notifieringar</string>\n\t<string name=\"enable_notifications_summary\">Notifiera vid kontoförändringar</string>\n\t<string name=\"vibrate_title\">Vibrera</string>\n\t<string name=\"vibrate_summary\">Vibrera vid kontoförändringar</string>\n\t<string name=\"led_title\">Blinka LED:en</string>\n\t<string name=\"led_summary\">Blinka LED:en vid kontoförändringar (fungerar ej på alla enheter)</string>\n\t<string name=\"led_color_title\">LED-färg</string>\n   \t<string name=\"notification_sound_title\">Notifieringsljud</string>\n\t<string name=\"notification_sound_summary\">Välj ett notifieringsljud</string>\n\t<string name=\"notification_sound_name\">Välj ljud</string>\n\t<string name=\"notify_delta_only_title\">Visa endast ändring</string>\n\t<string name=\"notify_delta_only_summary\">Visa inte kontosaldo i notifiering</string>\n\t<string name=\"account_types_title\">Kontotyper</string>\n\t<string name=\"account_types_summary\">Visa endast notifieringar för valda kontotyper</string>\n\t<string name=\"remote_notifier_title\">Remote Notifier-integrering</string>\n\t<string name=\"remote_notifier_enable_title\">Aktivera</string>\n\t<string name=\"remote_notifier_enable_summary\">Aktivera Remote Notifier-integrering</string>\n\t<string name=\"remote_notifier_help_title\">Vad är Remote Notifier?</string>\n\t<string name=\"remote_notifier_help_summary\">Läs mer om Remote Notifier på deras webbsida</string>\n\t<string name=\"openwatch_title\">OpenWatch-integrering</string>\n\t<string name=\"openwatch_enable_title\">Aktivera</string>\n\t<string name=\"openwatch_enable_summary\">Aktivera OpenWatch-integrering</string>\n\t<string name=\"openwatch_vibrate_title\">Vibrera</string>\n\t<string name=\"openwatch_vibrate_summary\">Vibrera OpenWatch-enheten</string>\n\t<string name=\"openwatch_help_title\">Vad är OpenWatch?</string>\n\t<string name=\"openwatch_help_summary\">Läs mer om OpenWatch på deras webbsida</string>\n\t<string name=\"liveview_title\">LiveView-integrering</string>\n\t<string name=\"liveview_enable_title\">Aktivera</string>\n\t<string name=\"liveview_enable_summary\">Aktivera Sony Ericssson LiveView-integrering</string>\n\t<string name=\"liveview_help_title\">Vad är LiveView?</string>\n\t<string name=\"liveview_help_summary\">Läs mer om LiveView på Sony Ericssons webbsida</string>\n\t<string name=\"share_data_title\">Dela ut data</string>\n\t<string name=\"share_data_enable_title\">Aktivera utdelning av data</string>\n\t<string name=\"share_data_enable_summary\">Medge andra installerade applikationer åtkomst till kontoutdrag</string>\n\t<string name=\"api_key_title\">API-nyckel</string>\n\t<string name=\"api_key_summary\">Använd denna nyckel för för att komma åt kontoutdrag från andra applikationer</string>\n\n\t<string name=\"funds\">Fonder</string>\n\t<string name=\"ccards\">Kreditkort</string>\n\t<string name=\"loans\">Lån</string>\n\t<string name=\"deposit_account\">Transaktionskonto</string>\n\t<string name=\"other\">Andra</string>\n\t<!--  /Settings  -->\n\n\t<string name=\"popup_refresh\">Uppdatera</string>\n    <string name=\"popup_edit\">Redigera</string>\n    <string name=\"popup_www\">WWW</string>\n    <string name=\"popup_remove\">Radera</string>\n\n    <string name=\"popup_hide\">Dölj</string>\n    <string name=\"popup_unhide\">Visa</string>\n    <string name=\"popup_hide_a\">Dölj\\nkonton</string>\n    <string name=\"popup_unhide_a\">Visa\\nkonton</string>\n    <string name=\"popup_enable_notifications\">Aktivera notifieringar</string>\n    <string name=\"popup_disable_notifications\">Inaktivera notifieringar</string>\n\n    <string name=\"remove_bank_msg\">Är du säker på att du vill ta bort denna bank?</string>\n    <string name=\"remove_bank_title\">Radera bank?</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"no\">Nej</string>\n\n    <string name=\"menu_show_hidden\">Visa dolda konton</string>\n    <string name=\"menu_hide_hidden\">Göm dolda konton</string>\n\n    <string name=\"tran_desc\">Inget kontoutdrag tillgängligt för detta konto.</string>\n\n    <string name=\"thanks_to\">Tack till</string>\n\n\t<!-- Lock Pattern settings -->\n    <!-- Unlock header -->\n    <string name=\"patternlock_header\">Rita ditt grafiska lösenord för att låsa upp Bankdroid</string>\n    <!-- Security & location settings screen, header -->\n\t<!-- Security & location settings screen, setting option name -->\n\t<!-- Security & location settings screen, change unlock pattern screen instruction when the user chooses \"Change unlock pattern\".  We first ask the user toe nter the current pattern, and this is the message seen -->\n    <string name=\"lockpattern_need_to_unlock\">Bekräfta sparat grafiskt lösenord</string>\n    <!-- Do not translate. -->\n    <string name=\"lockpattern_need_to_unlock_footer\"></string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction if user draws incorrect pattern -->\n    <string name=\"lockpattern_need_to_unlock_wrong\">Försök igen:</string>\n    <!-- Do not translate. -->\n    <string name=\"lockpattern_need_to_unlock_wrong_footer\"></string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen.  This si when they are supposed to draw a new unlock pattern (for example, if they are changing their unlock patterns)..-->\n    <string name=\"lockpattern_recording_intro_header\">Rita ett grafiskt lösenord</string>\n    <!-- Security & location settings screen, change unlock pattern screen hint on bottom of screen.  We are telling them to press the menu button to see more options or help. -->\n    <string name=\"lockpattern_recording_intro_footer\">Tryck på Meny om du vill ha hjälp.</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen while drawing pattern -->\n    <string name=\"lockpattern_recording_inprogress\">Lyft fingret när du är klar.</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen if user doesn't connect enough dots -->\n    <string name=\"lockpattern_recording_incorrect_too_short\">Anslut minst <xliff:g id=\"number\">%d</xliff:g> punkter. Försök igen:</string>\n    <!-- Security & location settings screen, change unlock pattern screen message on top of screen after drawing pattern -->\n    <string name=\"lockpattern_pattern_entered_header\">Det grafiska lösenordet har registrerats!</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen to confirm pattern -->\n    <string name=\"lockpattern_need_to_confirm\">Rita ditt grafiska lösenord igen för att bekräfta:</string>\n    <string name=\"lockpattern_pattern_confirmed_header\">Ditt nya grafiska lösenord:</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen.  After they draw a pattern and release their finger, we display the pattern so they remember.  When they are ready to draw it once again to confirm it, they press this button. -->\n    <string name=\"lockpattern_confirm_button_text\">Bekräfta</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen.  After they draw a pattern and release their finger, we display the pattern so they remember.  If they are nto satisfied with this pattern, they click this button to redraw the pattern. -->\n    <string name=\"lockpattern_restart_button_text\">Rita igen</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen. If they are supposed to enter their current pattern before being able to draw another one, and they screw up, they hit this button to try again -->\n    <string name=\"lockpattern_retry_button_text\">Försök igen</string>\n    <!-- Security & location settings screen, change unlock pattern screen button, on bottom of screen. Once they draw a new pattern and confirm it by drawing it again, they press this button to exit -->\n    <string name=\"lockpattern_continue_button_text\">Fortsätt</string>\n    <!-- Security & location settings screen, unlock screen activity title -->\n\t<!-- Security & location settings screen, setting check box title if the unlock pattern MUST be drawn everytime they turn on the screen -->\n\t<!-- Security & location settings screen, setting summary for the checkbox \"Require pattern\" -->\n\t<!-- Security & location settings screen, setting check box title. This setting controls whether a visible green line is drawn as the user moves his finger around while drawing the unlock pattern.  If checked, this line is drawn.  If unchecked, there is nothing drawn so the user does not reveal his pattern while he unlocks the phone.-->\n    <string name=\"lockpattern_settings_enable_visible_pattern_title\">Anv. synligt graf. lös.</string>\n    <!-- Security & location settings screen, setting check box title. This setting controls whether tactile feedback will be produced when the user draws the pattern.-->\n    <string name=\"lockpattern_settings_enable_tactile_feedback_title\">Använd känslig feedback</string>\n    <!-- Security & location settings screen, setting option name when user has never set an unlock pattern -->\n\t<!-- Security & location settings screen, setting option name when user has previously set an unlock pattern and wants to change to a new pattern -->\n\t<!-- Security & location settings screen, the help instructions (an animation) caption -->\n    <string name=\"lockpattern_settings_help_how_to_record\">Så här ritar du ett grafiskt lösenord</string>\n    <!-- Security & location settings screen, change unlock pattern screen instruction on top of screen after too many incorrect attempts -->\n    <string name=\"lockpattern_too_many_failed_confirmation_attempts_header\">För många felaktiga försök!</string>\n    <!-- Security & location settings screen, change unlock pattern screen countdown hint on bottom of screen after too many incorrect attempts -->\n    <string name=\"lockpattern_too_many_failed_confirmation_attempts_footer\">Försök igen om <xliff:g id=\"number\">%d</xliff:g> sekunder.</string>\n\n    <!-- ChooseLockPatternTutorial --> <skip />\n    <!-- ChooseLockPatternTutorial, button labels: This is to cancel the tutorial -->\n    <string name=\"skip_button_label\">Avbryt</string>\n    <!-- ChooseLockPatternTutorial, button labels: Continue to the next page of the tutorial -->\n    <string name=\"next_button_label\">Nästa</string>\n    <!-- ChooseLockPatternTutorial, tutorial screen title -->\n    <string name=\"lock_title\">Skydda din telefon</string>\n    <!-- ChooseLockPatternTutorial, tutorial screen text -->\n    <string name=\"lock_intro_message\">><font size=\"17\">Skydda din telefon från obehörig användning genom att skapa ett personligt grafiskt lösenord på skärmen.\n\t\t\\n<font height=\"17\">\\n</font><b>1</b>\\u00A0 Se hur ett grafiskt lösenord ritas på nästa skärm.\n\t\t\\n<font height=\"17\">\\n</font><b>2</b>\\u00A0 Rita ditt eget grafiska lösenord. Experimentera med olika grafiska lösenord men anslut minst fyra punkter.\n\t\t\\n<font height=\"17\">\\n</font><b>3</b>\\u00A0 Rita ditt grafiska lösenord igen för att bekräfta.\n\t\t\\n<font height=\"17\">\\n</font><b>Är du redo att börja? Välj \\u201CNästa\\u201D</b>.\n\t\t\\n<font height=\"3\">\\n</font>\"Välj \\u201CAvbryt\\u201D om du vill lämna telefonen oskyddad.</font>\n\n\t</string>\n    <!-- ChooseLockPatternExample --> <skip />\n    <!-- ChooseLockPatternExample, screen title that shows an example pattern -->\n    <string name=\"lock_example_title\">Exempel på grafiskt lösenord</string>\n    <!-- ChooseLockPatternExample, screen hint text at bottom of screen. These are instructions and rules for drawing a good patttern -->\n    <string name=\"lock_example_message\">Anslut minst fyra punkter.\n    \\n\\nVälj \\u201CNästa\\u201D när du vill rita ditt eget grafiska lösenord.\n    </string>\n\n\t<string name=\"select_a_bank\">Välj en bank</string>\n\t<string name=\"invalid_integer\">%1$s är inte ett giltigt positivt heltal, var god försök igen.</string>\n\t<string name=\"pair_message\">Applikationen nedan vill ta del av kontotyp och transaktionsdata från BankDroid.</string>\n\t<string name=\"approve\">GODKÄNN</string>\n\t<string name=\"pair_app_name\">Okänd applikation</string>\n\n    <!-- Color Picker -->\n    <string name=\"dialog_color_picker\">Färgväljare</string>\n    <string name=\"press_color_to_apply\">Tryck på färgen för att välja</string>\n\n    <!-- Error messages -->\n    <string name=\"error_bank_not_found\">Den valda banken kunde inte hittas.</string>\n    <string name=\"error_account_not_found\">Det valda kontot kunde inte hittas.</string>\n\t<string name=\"disabled_refresh_or_edit\">Senaste anslutningsförsöket till den här banken misslyckades och vi har slutat uppdatera denna bank automatiskt. Uppdatera banken manuellt för att försöka igen eller öppna inställningarna för denna bank och kontrollera dina inloggningsuppgifter.</string>\n\t<string name=\"loading\">Laddar…</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v21/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"BankdroidTheme\" parent=\"BaseTheme\">\n        <item name=\"android:windowContentTransitions\">true</item>\n        <item name=\"android:windowAllowEnterTransitionOverlap\">true</item>\n        <item name=\"android:windowAllowReturnTransitionOverlap\">true</item>\n        <item name=\"android:windowSharedElementEnterTransition\">@android:transition/move</item>\n        <item name=\"android:windowSharedElementExitTransition\">@android:transition/move</item>\n    </style>\n</resources>"
  },
  {
    "path": "app/src/main/res/xml/appwidget_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:minWidth=\"110dp\"\n    android:minHeight=\"40dp\"\n    android:updatePeriodMillis=\"0\"\n    android:initialLayout=\"@layout/widget\"\n    android:configure=\"com.liato.bankdroid.appwidget.WidgetConfigureActivity\" >\n</appwidget-provider>"
  },
  {
    "path": "app/src/main/res/xml/appwidget_info_large.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:minWidth=\"250dp\"\n    android:minHeight=\"40dp\"\n    android:updatePeriodMillis=\"0\"\n    android:initialLayout=\"@layout/widget_large\"\n    android:configure=\"com.liato.bankdroid.appwidget.WidgetConfigureActivity\" >\n</appwidget-provider>"
  },
  {
    "path": "app/src/main/res/xml/settings.xml",
    "content": "<PreferenceScreen\n\txmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/security_and_privacy\">\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"patternlock_enabled\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/enable_patternlock_title\"\n\t\t\tandroid:summary=\"@string/enable_patternlock_summary\" />\n\t\t<Preference\n\t\t\tandroid:title=\"@string/change_patternlock_title\"\n\t\t\tandroid:summary=\"@string/change_patternlock_summary\"\n\t\t\tandroid:key=\"patternlock_change\"\n\t\t\tandroid:dependency=\"patternlock_enabled\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"patternlock_visible_pattern\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/lockpattern_settings_enable_visible_pattern_title\"\n\t\t\tandroid:dependency=\"patternlock_enabled\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"patternlock_tactile_feedback\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/lockpattern_settings_enable_tactile_feedback_title\"\n\t\t\tandroid:dependency=\"patternlock_enabled\" />\n\t</PreferenceCategory>\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/appearance_title\">\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"round_balance\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/round_balance_title\"\n\t\t\tandroid:summary=\"@string/round_balance_summary\" />\n\t</PreferenceCategory>\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/widgets_title\">\t\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"widget_blur_balance\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/blur_widget_title\"\n\t\t\tandroid:summary=\"@string/blur_widget_summary\" />\n\t\t<ListPreference\n\t\t\tandroid:title=\"@string/unblur_widget_timeout_title\"\n\t\t\tandroid:key=\"widget_blur_balance_timeout\"\n\t\t\tandroid:defaultValue=\"5\"\n\t\t\tandroid:entries=\"@array/unblurTimeoutNames\"\n\t\t\tandroid:entryValues=\"@array/unblurTimeoutValues\"\n\t\t\tandroid:summary=\"@string/unblur_widget_timeout_summary\"\n\t\t\tandroid:dependency=\"widget_blur_balance\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"round_widget_balance\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/round_widget_balance_title\"\n\t\t\tandroid:summary=\"@string/round_widget_balance_summary\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"widget_opens_transactions\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/widget_opens_transactions_title\"\n\t\t\tandroid:summary=\"@string/widget_opens_transactions_summary\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"widget_updates_transactions\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/widget_updates_transactions_title\"\n\t\t\tandroid:summary=\"@string/widget_updates_transactions_summary\" />\n\t</PreferenceCategory>\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/automatic_updates_title\">\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"autoupdates_enabled\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/autoupdates_enabled_title\"\n\t\t\tandroid:summary=\"@string/autoupdates_enabled_summary\" />\n        <CheckBoxPreference\n            android:key=\"disable_during_roaming\"\n            android:defaultValue=\"false\"\n            android:title=\"@string/roaming\"\n            android:summary=\"@string/disable_during_roaming\" />\n\t\t<ListPreference\n\t\t\tandroid:title=\"@string/update_frequency_title\"\n\t\t\tandroid:key=\"refresh_rate\"\n\t\t\tandroid:defaultValue=\"60\"\n\t\t\tandroid:entries=\"@array/refreshrateNames\"\n\t\t\tandroid:entryValues=\"@array/refreshrateValues\"\n\t\t\tandroid:dependency=\"autoupdates_enabled\" />\n\t\t<com.liato.bankdroid.TimePreference\n\t\t\tandroid:title=\"@string/update_start_title\"\n\t\t\tandroid:key=\"refresh_start_minutes\"\n\t\t\tandroid:defaultValue=\"0\"\n\t\t\tandroid:dependency=\"autoupdates_enabled\" />\n\t\t<com.liato.bankdroid.TimePreference\n\t\t\tandroid:title=\"@string/update_stop_title\"\n\t\t\tandroid:key=\"refresh_stop_minutes\"\n\t\t\tandroid:defaultValue=\"0\"\n\t\t\tandroid:dependency=\"autoupdates_enabled\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"autoupdates_transactions_enabled\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/update_transaction_history_title\"\n\t\t\tandroid:summary=\"@string/update_transaction_history_summary\" />\n\t</PreferenceCategory>\t\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/notifications_title\">\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"notify_on_change\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/enable_notifications_title\"\n\t\t\tandroid:summary=\"@string/enable_notifications_summary\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"notify_with_vibration\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/vibrate_title\"\n\t\t\tandroid:summary=\"@string/vibrate_summary\"\n\t\t\tandroid:dependency=\"notify_on_change\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"notify_with_led\"\n\t\t\tandroid:defaultValue=\"true\"\n\t\t\tandroid:title=\"@string/led_title\"\n\t\t\tandroid:summary=\"@string/led_summary\"\n\t\t\tandroid:dependency=\"notify_on_change\" />\n\t\t<net.margaritov.preference.colorpicker.ColorPickerPreference\n\t\t    android:key=\"notify_with_led_color\"\n\t\t    android:title=\"@string/led_color_title\"\n\t\t    android:defaultValue=\"@color/default_led_color\"\n\t\t    android:dependency=\"notify_with_led\"\n\t\t/>\n\t\t<ListPreference\n\t\t\tandroid:title=\"@string/number_of_notifications_title\"\n\t\t\tandroid:summary=\"@string/number_of_notifications_summary\"\n\t\t\tandroid:key=\"num_notifications\"\n\t\t\tandroid:defaultValue=\"total\"\n\t\t\tandroid:entries=\"@array/numNotificationsNames\"\n\t\t\tandroid:entryValues=\"@array/numNotificationsValues\"\n\t\t\tandroid:dependency=\"notify_on_change\" />\n\t\t<CheckBoxPreference\n\t\t\tandroid:key=\"notify_delta_only\"\n\t\t\tandroid:defaultValue=\"false\"\n\t\t\tandroid:title=\"@string/notify_delta_only_title\"\n\t\t\tandroid:summary=\"@string/notify_delta_only_summary\"\n\t\t\tandroid:dependency=\"notify_on_change\" />\n\t\t<EditTextPreference\n\t\t\tandroid:key=\"notify_min_delta\"\n\t\t\tandroid:defaultValue=\"0\"\n\t\t\tandroid:title=\"@string/notify_min_delta_title\"\n\t\t\tandroid:summary=\"@string/notify_min_delta_summary\"\n\t\t\tandroid:dependency=\"notify_on_change\" />\n\t\t<RingtonePreference\n\t\t\tandroid:key=\"notification_sound\"\n\t\t\tandroid:title=\"@string/notification_sound_title\"\n\t\t\tandroid:summary=\"@string/notification_sound_summary\"\n\t\t\tandroid:ringtoneType=\"notification\"\n\t\t\tandroid:showDefault=\"true\"\n\t\t\tandroid:showSilent=\"true\"\n\t\t\tandroid:dependency=\"notify_on_change\" android:name=\"@string/notification_sound_name\"/>\n\t\t<PreferenceScreen\n\t\t\tandroid:key=\"account_types_screen\"\n\t\t\tandroid:title=\"@string/account_types_title\"\n\t\t\tandroid:summary=\"@string/account_types_summary\"\n\t\t\tandroid:dependency=\"notify_on_change\">\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_for_deposit\"\n\t\t\t\tandroid:defaultValue=\"true\"\n\t\t\t\tandroid:title=\"@string/deposit_account\" />\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_for_funds\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/loans\" />\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_for_loans\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/funds\" />\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_for_ccards\"\n\t\t\t\tandroid:defaultValue=\"true\"\n\t\t\t\tandroid:title=\"@string/ccards\" />\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_for_other\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/other\" />\n\t\t</PreferenceScreen>\n\t\t<PreferenceScreen\n\t\t\tandroid:key=\"remotenotifier_screen\"\n\t\t\tandroid:title=\"@string/remote_notifier_title\"\n\t\t\tandroid:dependency=\"notify_on_change\">\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_remotenotifier\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/remote_notifier_enable_title\"\n\t\t\t\tandroid:summary=\"@string/remote_notifier_enable_summary\" />\n\t\t\t<Preference\n\t\t\t\tandroid:title=\"@string/remote_notifier_help_title\"\n\t\t\t\tandroid:summary=\"@string/remote_notifier_help_summary\"\n\t\t\t\tandroid:key=\"remotenotifier_help\" />\n\t\t</PreferenceScreen>\n\t\t<PreferenceScreen\n\t\t\tandroid:key=\"openwatch_screen\"\n\t\t\tandroid:title=\"@string/openwatch_title\"\n\t\t\tandroid:dependency=\"notify_on_change\">\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_openwatch\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/openwatch_enable_title\"\n\t\t\t\tandroid:summary=\"@string/openwatch_enable_summary\" />\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_openwatch_vibrate\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/openwatch_vibrate_title\"\n\t\t\t\tandroid:summary=\"@string/openwatch_vibrate_summary\" />\n\t\t\t<Preference\n\t\t\t\tandroid:title=\"@string/openwatch_help_title\"\n\t\t\t\tandroid:summary=\"@string/openwatch_help_summary\"\n\t\t\t\tandroid:key=\"openwatch_help\" />\n\t\t</PreferenceScreen>\n\t\t<PreferenceScreen\n\t\t\tandroid:key=\"liveview_screen\"\n\t\t\tandroid:title=\"@string/liveview_title\"\n\t\t\tandroid:dependency=\"notify_on_change\">\n\t\t\t<CheckBoxPreference\n\t\t\t\tandroid:key=\"notify_liveview\"\n\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\tandroid:title=\"@string/liveview_enable_title\"\n\t\t\t\tandroid:summary=\"@string/liveview_enable_summary\" />\n\t\t\t<Preference\n\t\t\t\tandroid:title=\"@string/liveview_help_title\"\n\t\t\t\tandroid:summary=\"@string/liveview_help_summary\"\n\t\t\t\tandroid:key=\"liveview_help\" />\n\t\t</PreferenceScreen>\n\t</PreferenceCategory>\n\t<PreferenceCategory\n\t\tandroid:title=\"@string/share_data_title\">\n\t<CheckBoxPreference\n\t\tandroid:title=\"@string/share_data_enable_title\"\n\t\tandroid:summary=\"@string/share_data_enable_summary\"\n\t\tandroid:key=\"content_provider_enabled\" />\n\t<EditTextPreference\n\t\tandroid:title=\"@string/api_key_title\"\n\t\tandroid:key=\"content_provider_api_key\"\n\t\tandroid:dependency=\"content_provider_enabled\"\n\t\tandroid:summary=\"@string/api_key_summary\" />\n</PreferenceCategory>\n\t<PreferenceCategory\n\t\tandroid:title=\"Debug\">\n\t\t<PreferenceScreen\n\t\t\tandroid:key=\"debug_screen_pre\"\n\t\t\tandroid:title=\"Debug Settings\"\n\t\t\tandroid:summary=\"Don't touch if you don't know what you're doing\">\n\t\t\t<PreferenceScreen\n\t\t\t\tandroid:key=\"debug_screen\"\n\t\t\t\tandroid:title=\"Seriously\"\n\t\t\t\tandroid:summary=\"You might break things\">\n\t\t\t\t<CheckBoxPreference\n\t\t\t\t\tandroid:key=\"debug_mode\"\n\t\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\t\tandroid:title=\"Enable\"\n\t\t\t\t\tandroid:summary=\"Enable debug mode\" />\n\t\t\t\t<CheckBoxPreference\n\t\t\t\t\tandroid:key=\"debug_refreshrate_in_seconds\"\n\t\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\t\tandroid:title=\"Update freq. in sec.\"\n\t\t\t\t\tandroid:summary=\"Update frequency is given in seconds instead of minutes\"\n\t\t\t\t\tandroid:dependency=\"debug_mode\" />\n                <CheckBoxPreference\n                    android:key=\"debug_only_testbank\"\n                    android:defaultValue=\"false\"\n                    android:title=\"Testbank only\"\n                    android:summary=\"Only auto update 'Testbank' banks\"\n                    android:dependency=\"debug_mode\" />\n                <CheckBoxPreference\n                    android:key=\"no_cert_pinning\"\n                    android:defaultValue=\"false\"\n                    android:title=\"Don't use certificate pinning\"\n                    android:summary=\"Use the system trust store\"\n                    android:dependency=\"debug_mode\" />\n\t\t\t\t<!-- <CheckBoxPreference\n\t\t\t\t\tandroid:key=\"debug_coop_sendmail\"\n\t\t\t\t\tandroid:defaultValue=\"false\"\n\t\t\t\t\tandroid:title=\"Coop - Mail on error\"\n\t\t\t\t\tandroid:summary=\"Open your email client with the html response when Bankdroid fails to login to your Coop account.\"\n\t\t\t\t\tandroid:dependency=\"debug_mode\" /> -->\n\t\t\t<Preference\n\t\t\t\tandroid:title=\"Test notification\"\n\t\t\t\tandroid:summary=\"A demo notification\"\n\t\t\t\tandroid:key=\"test_notification\" />\t\t\t\t\t\t\t\t\n\t\t\t</PreferenceScreen>\n\t\t</PreferenceScreen>\n\t</PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/test/java/com/liato/bankdroid/DataRetrieverTaskTest.java",
    "content": "package com.liato.bankdroid;\n\nimport com.liato.bankdroid.banking.Bank;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.mockito.Mockito;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class DataRetrieverTaskTest {\n    // Any positive number would do here\n    private static final int BANK_ID = 5;\n\n    private static class TestableDataRetrieverTask extends DataRetrieverTask {\n        private final Bank[] banks;\n        private final ProgressDialog dialog;\n\n        @Override\n        protected void publishProgress(int zeroBasedBankNumber, Bank bank) {\n            // This method intentionally left blank\n        }\n\n        @Override\n        protected Bank getBankFromDb(long bankId, Context parent) {\n            Assert.assertEquals(BANK_ID, bankId);\n            return banks[0];\n        }\n\n        @Override\n        protected List<Bank> getBanksFromDb(Context parent) {\n            return Arrays.asList(banks);\n        }\n\n        @Override\n        protected void saveBank(Bank bank, Context context) {\n            // This method intentionally left blank\n        }\n\n        @Override\n        protected boolean isContentProviderEnabled() {\n            return false;\n        }\n\n        @NonNull\n        @Override\n        protected ProgressDialog getDialog() {\n            return dialog;\n        }\n\n        /**\n         * Constructor for testing a specific bank\n         */\n        public TestableDataRetrieverTask(Bank bank) {\n            super(Mockito.mock(MainActivity.class), BANK_ID);\n\n            this.banks = new Bank[] { bank };\n            this.dialog = Mockito.mock(ProgressDialog.class);\n        }\n\n        /**\n         * Constructor for testing all banks\n         */\n        public TestableDataRetrieverTask(Bank[] allBanks) {\n            super(Mockito.mock(MainActivity.class));\n\n            this.banks = allBanks;\n            this.dialog = Mockito.mock(ProgressDialog.class);\n        }\n    }\n\n    @Test\n    public void testUpdateSingleDisabledBank() throws Exception {\n        Bank bank = Mockito.mock(Bank.class);\n        Mockito.when(bank.isDisabled()).thenReturn(true);\n\n        TestableDataRetrieverTask testMe = new TestableDataRetrieverTask(bank);\n        testMe.doInBackground();\n\n        // Single disabled bank should be updated\n        Mockito.verify(bank, Mockito.atLeastOnce()).update();\n\n        // At least at the time of writing this (2016oct2) updating the bank\n        // implicitly enables it. Of course having a test for that would be\n        // better than not having one, but we don't right now.\n    }\n\n    @Test\n    public void testUpdateSingleEnabledBank() throws Exception {\n        Bank bank = Mockito.mock(Bank.class);\n        Mockito.when(bank.isDisabled()).thenReturn(false);\n\n        TestableDataRetrieverTask testMe = new TestableDataRetrieverTask(bank);\n        testMe.doInBackground();\n\n        // Single enabled bank should be updated\n        Mockito.verify(bank, Mockito.atLeastOnce()).update();\n    }\n\n    @Test\n    public void testUpdateMultiDisabledBank() throws Exception {\n        Bank bank = Mockito.mock(Bank.class);\n        Mockito.when(bank.isDisabled()).thenReturn(true);\n\n        TestableDataRetrieverTask testMe = new TestableDataRetrieverTask(new Bank[]{bank});\n        testMe.doInBackground();\n\n        // When doing all banks, disabled ones shouldn't update\n        Mockito.verify(bank, Mockito.never()).update();\n    }\n\n    @Test\n    public void testUpdateMultiEnabledBank() throws Exception {\n        Bank bank = Mockito.mock(Bank.class);\n        Mockito.when(bank.isDisabled()).thenReturn(false);\n\n        TestableDataRetrieverTask testMe = new TestableDataRetrieverTask(new Bank[]{bank});\n        testMe.doInBackground();\n\n        // When doing all banks, enabled ones should update\n        Mockito.verify(bank, Mockito.atLeastOnce()).update();\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/com/liato/bankdroid/appwidget/DataRetrieverTaskTest.java",
    "content": "package com.liato.bankdroid.appwidget;\n\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.db.DBAdapter;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.mockito.Mockito;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.support.annotation.NonNull;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class DataRetrieverTaskTest {\n    private static class TestableBank extends Bank {\n        private final int balanceBeforeUpdate;\n        private final int balanceAfterUpdate;\n        private boolean hasUpdated = false;\n\n        public TestableBank(int balanceBeforeUpdate, int balanceAfterUpdate) {\n            super(Mockito.mock(Context.class), 0);\n\n            this.balanceBeforeUpdate = balanceBeforeUpdate;\n            this.balanceAfterUpdate = balanceAfterUpdate;\n        }\n\n        @Override\n        public void update() {\n            hasUpdated = true;\n        }\n\n        @Override\n        public ArrayList<Account> getAccounts() {\n            int balance;\n            if (hasUpdated) {\n                balance = balanceAfterUpdate;\n            } else {\n                balance = balanceBeforeUpdate;\n            }\n\n            Account account = Mockito.mock(Account.class);\n            Mockito.when(account.getBalance()).thenReturn(BigDecimal.valueOf(balance));\n\n            ArrayList<Account> accounts = new ArrayList<>();\n            accounts.add(account);\n\n            return accounts;\n        }\n\n        @Override\n        public BigDecimal getBalance() {\n            return getAccounts().get(0).getBalance();\n        }\n\n        @Override\n        public int getBanktypeId() {\n            return IBankTypes.TESTBANK;\n        }\n\n        @Override\n        public String getName() {\n            return \"Testbanken\";\n        }\n    }\n\n    private static class TestableDataRetrieverTask extends AutoRefreshService.DataRetrieverTask {\n        private final Bank bank;\n        private boolean hasRefreshedWidget = false;\n\n        private TestableDataRetrieverTask(\n                AutoRefreshService autoRefreshService, SharedPreferences prefs, Bank bank) {\n            super(autoRefreshService, prefs);\n\n            this.bank = bank;\n        }\n\n        @Override\n        protected List<Bank> getBanks() {\n            List<Bank> returnMe = new ArrayList<>();\n            returnMe.add(bank);\n            return returnMe;\n        }\n\n        @NonNull\n        @Override\n        protected DBAdapter getDBAdapter() {\n            return Mockito.mock(DBAdapter.class);\n        }\n\n        @Override\n        protected void sendWidgetRefresh() {\n            hasRefreshedWidget = true;\n        }\n    }\n\n    @Test\n    public void testIncreaseLessThanNotificationThreshold() throws Exception {\n        AutoRefreshService autoRefreshService = Mockito.mock(AutoRefreshService.class);\n\n        SharedPreferences prefs = Mockito.mock(SharedPreferences.class);\n        Mockito.when(prefs.getString(\"notify_min_delta\", \"0\")).thenReturn(\"300\");\n\n        TestableDataRetrieverTask testMe =\n                new TestableDataRetrieverTask(autoRefreshService, prefs, new TestableBank(100, 200));\n        testMe.doInBackground();\n\n        Assert.assertTrue(\"Widget should have been refreshed\", testMe.hasRefreshedWidget);\n    }\n\n    @Test\n    public void testNoChange() throws Exception {\n        AutoRefreshService autoRefreshService = Mockito.mock(AutoRefreshService.class);\n\n        SharedPreferences prefs = Mockito.mock(SharedPreferences.class);\n        Mockito.when(prefs.getString(\"notify_min_delta\", \"0\")).thenReturn(\"0\");\n\n        TestableDataRetrieverTask testMe =\n                new TestableDataRetrieverTask(autoRefreshService, prefs, new TestableBank(100, 100));\n        testMe.doInBackground();\n\n        Assert.assertFalse(\"Widget shouldn't have been refreshed\", testMe.hasRefreshedWidget);\n    }\n}\n"
  },
  {
    "path": "bankdroid-core/build.gradle",
    "content": "apply plugin: 'java'\napply from: '../config/quality/quality.gradle'\nsourceCompatibility = JavaVersion.VERSION_1_7\ntargetCompatibility = JavaVersion.VERSION_1_7\n\ndependencies {\n\tcompile project(':bankdroid-interface')\n}\n"
  },
  {
    "path": "bankdroid-core/src/main/java/com/liato/bankdroid/configuration/DefaultConnectionConfiguration.java",
    "content": "package com.liato.bankdroid.configuration;\n\nimport com.liato.bankdroid.api.configuration.Field;\nimport com.liato.bankdroid.api.configuration.FieldBuilder;\nimport com.liato.bankdroid.api.configuration.FieldType;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.ResourceBundle;\n\npublic class DefaultConnectionConfiguration {\n\n    public static final String NAME = \"provider.configuration.name\";\n\n    private final static List<Field> CONFIGURATION = createConfiguration();\n\n    private static List<Field> createConfiguration() {\n        List<Field> configuration = new ArrayList<>();\n        configuration.add(new FieldBuilder(NAME, ResourceBundle.getBundle(\"i18n.application\"))\n                .placeholder(\"\")\n                .fieldType(FieldType.TEXT)\n                .build());\n        return configuration;\n    }\n\n    public static List<Field> fields() {\n        return CONFIGURATION;\n    }\n}\n"
  },
  {
    "path": "bankdroid-core/src/main/resources/i18n/application.properties",
    "content": "field.provider.configuration.name.label=Custom Name\nfield.provider.configuration.username.label=Username\nfield.provider.configuration.password.label=Password\n"
  },
  {
    "path": "bankdroid-core/src/main/resources/i18n/application_sv_SE.properties",
    "content": "field.provider.configuration.name.label=Eget Namn\nfield.provider.configuration.username.label=Användarnamn\nfield.provider.configuration.password.label=Lösenord\n"
  },
  {
    "path": "bankdroid-interface/build.gradle",
    "content": "apply plugin: 'java'\napply from: '../config/quality/quality.gradle'\nsourceCompatibility = JavaVersion.VERSION_1_7\ntargetCompatibility = JavaVersion.VERSION_1_7\n\ndependencies {\n    compile 'joda-time:joda-time:2.8.2'\n    testCompile 'junit:junit:4.12'\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/Provider.java",
    "content": "package com.liato.bankdroid.api;\n\nimport com.liato.bankdroid.api.configuration.ProviderConfiguration;\n\n/**\n * Represents a provider. e.g. a bank, stock broker, bus company etc.\n */\npublic interface Provider {\n\n    /**\n     * Returns a unique identifier for the provider.\n     * @return the provider id.\n     */\n    String getId();\n\n    /**\n     * Returns the name of the provider.\n     * @return The provider's name.\n     */\n    String getName();\n\n    /**\n     * Indicates if a provider implementation is currently broken.\n     * @return {@code true} if the provider implementation is broken. Otherwise {@false}.\n     */\n    boolean isBroken();\n\n    /**\n     * Returns the configuration available for the provider.\n     * @return the provider configuration.\n     */\n    ProviderConfiguration getConfiguration();\n\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/ProviderFactory.java",
    "content": "package com.liato.bankdroid.api;\n\n/**\n * Is responsible for creating new instances of {@link Provider} objects. This should be the single\n * point of where {@link Provider} objects are created.\n */\npublic interface ProviderFactory {\n\n    /**\n     * Create a new {@link Provider} instance.\n     * @return a new instance of a {@link Provider}.\n     */\n    Provider create();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/Entry.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\npublic class Entry {\n\n    private final String mKey;\n    private final String mValue;\n\n    public Entry(String key, String value) {\n        if (key == null || key.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"key cannot be null or empty.\");\n        }\n        mKey = key;\n        mValue = value;\n    }\n\n    public String getKey() {\n        return mKey;\n    }\n\n    public String getValue() {\n        return mValue;\n    }\n\n    @Override\n    public String toString() {\n        return mValue;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (obj == null || obj.getClass() != this.getClass()) {\n            return false;\n        }\n        Entry other = (Entry) obj;\n        return mKey.equals(other.mKey);\n    }\n\n    @Override\n    public int hashCode() {\n        return mKey.hashCode();\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/Field.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\nimport java.util.List;\n\n/**\n * Represent an input field that is rendered for the user.\n */\npublic interface Field {\n\n    /**\n     * Returns the reference to this field. This value needs to be unique per configuration.\n     *\n     * @return the reference to this field.\n     */\n    String getReference();\n\n    /**\n     * Get the placeholder for this field.\n     * The placeholder specifies a short hint that describes the expected value of an\n     * field (e.g. a sample value or a short description of the expected format).\n     * The short hint is displayed in the input field before the user enters a value.\n     *\n     * @return the placeholder for this field.\n     */\n    String getPlaceholder();\n\n    /**\n     * Get the label for this field.\n     *\n     * @return the label for this field.\n     */\n    String getLabel();\n\n    /**\n     * Get the field type for this field.\n     *\n     * @return The field type for this field. Defaults to {@link FieldType#TEXT}.\n     */\n    FieldType getFieldType();\n\n    /**\n     * Returns {@code true} if the field is a required field.\n     *\n     * The {@link #validate(String)} will fail if this value is true and the string to be validated\n     * are empty or {@code null}.\n     * @return {@code true} if the field is a required field. Otherwise {@code false}.\n     */\n    boolean isRequired();\n\n    /**\n     * Returns {@code true} if the field should be hidden for the end user when it is rendered.\n     *\n     * @return {@code true} if the field should be hidden. Otherwise {@code false}.\n     */\n    boolean isHidden();\n\n    /**\n     * Returns {@code true} if, and only if, the field value should be treated as a secret field.\n     * Secret fields should be rendered as a password field.\n     * @return {@code true} if the field value should be encrypted before it is stored. Otherwise\n     * {@code false}.\n     */\n    boolean isSecret();\n\n    /**\n     * Returns a list of available values for this field. If this list is not empty the field\n     * should be rendered as a combo box or a radio button group.\n     * @return A list of available values for the field.\n     */\n    List<Entry> getValues();\n\n    /**\n     * Validate the user input before changes are accepted by the system. This method should\n     * at least validate the {@link #isRequired()} method.\n     *\n     * @param value The value to be validated.\n     * @throws IllegalArgumentException is thrown if the validation fails. A detailed error message\n     * is included in the exception.\n     */\n    void validate(String value) throws IllegalArgumentException;\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/FieldBuilder.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport java.util.ResourceBundle;\n\n/**\n * A builder for building {@link Field} objects.\n */\npublic class FieldBuilder {\n\n    private BasicField field;\n\n    /**\n     * Create a new {@link Field} builder without i18n support.\n     */\n    public FieldBuilder(String reference) {\n      this(reference, null);\n    }\n\n    /**\n     * Create a new {@link Field} builder with i18n support for {@link Field#getLabel()} and {@link Field#getPlaceholder()}.\n     * The following keys needs to be in the ResourceBundle:\n     * {@code field.{reference}.label} - Locale label value\n     * {@code field.{reference}.placeholder} - Locale placeholder value.\n     *\n     * Setting {@link #placeholder(String)} or {@link #label(String) specifically will override the i18n values.\n     * Otherwise they will be set to the value specified in the Locale bundle or in the default bundle if not present.\n     * If a key is not present at all in the ResourceBundle the key will will be returned.\n     * @param reference Field reference\n     * @param bundle The ResourceBundle to be used for i18n support.\n     */\n    public FieldBuilder(String reference, ResourceBundle bundle) {\n        if (reference == null || reference.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"reference must be provided.\");\n        }\n        field = new BasicField(reference, bundle);\n    }\n\n    public Field build() {\n        return field;\n    }\n\n    public FieldBuilder label(String label) {\n        field.label = label;\n        return this;\n    }\n\n    public FieldBuilder placeholder(String placeholder) {\n        field.placeholder = placeholder;\n        return this;\n    }\n\n    public FieldBuilder fieldType(FieldType fieldType) {\n        field.fieldType = fieldType;\n        return this;\n    }\n\n    public FieldBuilder required(boolean required) {\n        field.required = required;\n        return this;\n    }\n\n    public FieldBuilder hidden(boolean hidden) {\n        field.hidden = hidden;\n        return this;\n    }\n\n    public FieldBuilder secret(boolean secret) {\n        field.secret = secret;\n        return this;\n    }\n\n    public FieldBuilder values(List<Entry> values) {\n        field.values = values;\n        return this;\n    }\n\n    public FieldBuilder validator(FieldValidator validator) {\n        field.validator = validator;\n        return this;\n    }\n\n    private static class BasicField implements Field {\n\n        private ResourceBundle resourceBundle;\n\n        private String reference;\n\n        private String placeholder;\n\n        private String label;\n\n        private FieldType fieldType;\n\n        private boolean required;\n\n        private boolean hidden;\n\n        private boolean secret;\n\n        private List<Entry> values;\n\n        private FieldValidator validator;\n\n        BasicField(String reference, ResourceBundle bundle) {\n            this.reference = reference;\n            this.resourceBundle = bundle;\n        }\n\n        @Override\n        public String getReference() {\n            return reference;\n        }\n\n        @Override\n        public String getPlaceholder() {\n            return placeholder == null ? getLocaleString(\"placeholder\") : placeholder;\n        }\n\n        @Override\n        public String getLabel() {\n            return label == null ? getLocaleString(\"label\") : label;\n        }\n\n        @Override\n        public FieldType getFieldType() {\n            return fieldType;\n        }\n\n        @Override\n        public boolean isRequired() {\n            return required;\n        }\n\n        @Override\n        public boolean isHidden() {\n            return hidden;\n        }\n\n        @Override\n        public boolean isSecret() {\n            return secret;\n        }\n\n        @Override\n        public List<Entry> getValues() {\n            if (values == null) {\n                values = Collections.emptyList();\n            }\n            return values;\n        }\n\n        @Override\n        public void validate(String value) throws IllegalArgumentException {\n            if (required) {\n                if (value == null || value.trim().isEmpty()) {\n                    throw new IllegalArgumentException(String.format(\"%s is required\", getLabel()));\n                }\n                if (validator != null) {\n                    validator.validate(value);\n                }\n            }\n        }\n\n        private String getLocaleString(String key) {\n            if (!isLocale()) {\n                return null;\n            }\n            String propertyKey = String.format(\"field.%s.%s\", reference, key);\n            return resourceBundle.containsKey(propertyKey) ? resourceBundle.getString(propertyKey)\n                    : propertyKey;\n        }\n\n        private boolean isLocale() {\n            return resourceBundle != null;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/FieldType.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\npublic enum FieldType {\n    /**\n     * Represents a regular input text field.\n     */\n    TEXT,\n    /**\n     * Represents an input field that only allows numbers.\n     */\n    NUMBER,\n    /**\n     * Represents an input field that should contain a phone number.\n     */\n    PHONE,\n    /**\n     * Represents an input field that should contain an email address.\n     */\n    EMAIL,\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/FieldValidator.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\npublic interface FieldValidator {\n\n    /**\n     * Validates a field value.\n     *\n     * @param value the value to be validated.\n     * @throws IllegalArgumentException if the validation fails.\n     */\n    void validate(String value);\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/configuration/ProviderConfiguration.java",
    "content": "package com.liato.bankdroid.api.configuration;\n\nimport java.util.List;\n\n/**\n * Holds the configuration for a provider.\n */\npublic interface ProviderConfiguration {\n\n    /**\n     * Returns the fields that should be available for configuring a provider connection.\n     * @return Returns a list of available fields for provider connection configuration.\n     * If no configuration is available an empty list is returned.\n     */\n    List<Field> getConnectionConfiguration();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/ProviderConnection.java",
    "content": "package com.liato.bankdroid.api.domain;\n\nimport com.liato.bankdroid.api.domain.account.Account;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\n\n/**\n * Represents a single connection to the {@link com.liato.bankdroid.api.Provider}.\n */\npublic interface ProviderConnection {\n\n    /**\n     * Returns the name of the connection.\n     * @return The connection name.\n     */\n    String getName();\n\n    /**\n     * Returns the total balance for all accounts associated with the connection. In the case the\n     * accounts have multiple currencies, these will be converted to the currency returned by the\n     * {@link #getDefaultCurrency()}.\n     *\n     * @return The total balance for the connection.\n     */\n    BigDecimal getTotalBalance();\n\n    /**\n     * Returns the default currency for the connection.\n     * @return The default currency for the connection.\n     */\n    String getDefaultCurrency();\n\n    /**\n     * Returns a collection of all accounts associated with the connection.\n     * @return All accounts for the connection.\n     */\n    Collection<Account> getAccounts();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/Account.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.math.BigDecimal;\nimport java.util.Map;\n\n/**\n * A parent interface for all account types.\n */\npublic interface Account {\n\n    /**\n     * Returns the account id.\n     * @return Returns the account id.\n     */\n    String getId();\n\n    /**\n     * Returns the account's name.\n     * @return the account name.\n     */\n    String getName();\n\n    /**\n     * Returns the total balance for the account.\n     * @return The total balance for the account.\n     */\n    BigDecimal getBalance();\n\n    /**\n     * The ISO 4217 currency representation, when possible.\n     * @return The main currency for the account.\n     */\n    String getCurrency();\n\n    /**\n     * Returns a collection of extra attributes that can be set on an account.\n     * @return A collection of custom attributes, or an empty collection if no custom\n     * attributes exist.\n     */\n    Map<String, String> getCustomAttributes();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/CreditCardAccount.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\n\n/**\n * Represents a Credit Card Account.\n */\npublic interface CreditCardAccount extends Account {\n\n    /**\n     * Returns the credit limit for the account.\n     * @return the credit limit.\n     */\n    BigDecimal getCreditLimit();\n\n    /**\n     * Returns all transactions for the account.\n     * @return All transactions for the account.\n     */\n    Collection<Transaction> getTransactions();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/Equity.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.math.BigDecimal;\n\n/**\n * Represent a single equity, could be a share, fund etc.\n */\npublic interface Equity {\n\n    /**\n     * Returns the equity name.\n     * @return the equity name.\n     */\n    String getName();\n\n    /**\n     * The ISO 4217 currency representation, when possible.\n     * @return The equity's currency.\n     */\n    String getCurrency();\n\n    /**\n     * Returns the number of shares for this equity.\n     * @return The quantity of equities.\n     */\n    double getQuantity();\n\n    /**\n     * Returns the total cost for this equity.\n     * @return Cost for the entity.\n     */\n    BigDecimal getCost();\n\n    /**\n     * Returns the total revenue for this equity.\n     * @return Equity revenue.\n     */\n    BigDecimal getRevenue();\n\n    /**\n     * Returns the total revenue for this equity, as percentage. A value less than {@code 1} is a\n     * loss and a value greater than one is a profit. e.g. {@code 0.75} represents a 25 % loss,\n     * while {@code 1.5} is 50 % profit.\n     * @return Total revenue as percentage.\n     */\n    double getRevenueAsPercentage();\n\n    /**\n     * Returns the current balance for the equity.\n     * @return the equity's balance.\n     */\n    BigDecimal getBalance();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/EquityAccount.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\n\n/**\n * Represent an Equity Account. An equity account is a collection of shares, funds etc.\n */\npublic interface EquityAccount extends Account {\n\n    /**\n     * Returns the total cost for all equities included in the account.\n     * @return Total cost.\n     */\n    BigDecimal getCost();\n\n    /**\n     * Returns the total revenue for all equities in the account.\n     * @return Total revenue.\n     */\n    BigDecimal getRevenue();\n\n    /**\n     * Returns the total revenue for all equities in the account, in percent.\n     * @return Total revenue in percent, in 1/100.\n     */\n    double getRevenueAsPercentage();\n\n    /**\n     * Returns all equities for the account.\n     * @return All account equities.\n     */\n    Collection<Equity> getEquities();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/LiabilityAccount.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.util.Collection;\n\n/**\n * Represents a liability account. A liability can for example be a loan.\n */\npublic interface LiabilityAccount extends Account {\n\n    /**\n     * Returns the interest as a number less than 1, representing the interest in percentage.\n     * @return the interest in percent.\n     */\n    double getInterest();\n\n    /**\n     * Returns a collection of payments, could be both historical and upcoming payments.\n     * @return A collection of payments.\n     */\n    Collection<Payment> getPayments();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/Payment.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport org.joda.time.DateTime;\n\nimport java.math.BigDecimal;\n\n/**\n * Represents a Liability payment.\n */\npublic interface Payment {\n\n    /**\n     * Returns the date when the payment is due.\n     * @return the payment's due date.\n     */\n    DateTime getDueDate();\n\n    /**\n     * Returns the payment amount.\n     * @return the payment amount.\n     */\n    BigDecimal getAmount();\n\n    /**\n     * The ISO 4217 currency representation, when possible.\n     * @return The main currency for the account.\n     */\n    String getCurrency();\n\n    /**\n     * A description of the payment.\n     * @return payment description.\n     */\n    String getDescription();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/PrePaidCardAccount.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport org.joda.time.DateTime;\n\n/**\n * Represents a prepaid card. e.g. a bus card, cash card etc.\n */\npublic interface PrePaidCardAccount extends Account {\n\n    /**\n     * Returns the date when the card expired.\n     * @return the expiration date.\n     */\n    DateTime getExpirationDate();\n\n    /**\n     * Returns the date from when the card is valid.\n     * @return the valid from date.\n     */\n    DateTime getValidFrom();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/Transaction.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport org.joda.time.DateTime;\n\nimport java.math.BigDecimal;\n\n/**\n * Represents a single transaction.\n */\npublic interface Transaction {\n\n    /**\n     * Returns the transaction amount.\n     * @return the transaction amount.\n     */\n    BigDecimal getAmount();\n\n    /**\n     * Returns the currency for the transaction, conforming to ISO 4217 when possible.\n     * @return the transaction currency.\n     */\n    String getCurrency();\n\n    /**\n     * Returns a short description of the transaction.\n     * @return the transaction description.\n     */\n    String getDescription();\n\n    /**\n     * Returns the date when the transaction was initiated.\n     * @return the transaction date.\n     */\n    DateTime getTransactionDate();\n\n    /**\n     * Returns {@code true} if, and only if, the transaction is still pending.\n     * @return {@code true} if the transaction is pending, otherwise {@code false}.\n     */\n    boolean isPending();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/TransactionAccount.java",
    "content": "package com.liato.bankdroid.api.domain.account;\n\nimport java.util.Collection;\n\n/**\n * Represents a transaction account. Holds multiple transactions.\n */\npublic interface TransactionAccount extends Account {\n\n    /**\n     * Returns a collection of transaction.\n     * @return All transactions.\n     */\n    Collection<Transaction> getTransactions();\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/AbstractAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport java.math.BigDecimal;\nimport java.util.HashMap;\nimport java.util.Map;\n\nabstract class AbstractAccountBuilder<T extends AbstractAccountBuilder<T>> {\n\n    protected String mId;\n    protected String mName;\n    protected BigDecimal mBalance;\n    protected String mCurrency;\n    protected Map<String, String> mCustomAttributes;\n\n    protected AbstractAccountBuilder(String id, String name, String currency) {\n        if (id == null || id.isEmpty() || currency == null || currency.isEmpty() || name == null || name.isEmpty()) {\n            throw new IllegalArgumentException(\"Id, name and currency cannot be null or empty\");\n        }\n        mId = id;\n        mName = name;\n        mCurrency = currency;\n    }\n\n    protected abstract T self();\n\n    public T name(String name) {\n        mName = name;\n        return self();\n    }\n\n    public T balance(BigDecimal balance) {\n        mBalance = balance;\n        return self();\n    }\n\n    public T addCustomAttribute(String key, String value) {\n        if (mCustomAttributes == null) {\n            mCustomAttributes = new HashMap<>();\n        }\n        mCustomAttributes.put(key, value);\n        return self();\n    }\n\n    public T customAttributes(Map<String, String> customAttributes) {\n        mCustomAttributes = customAttributes;\n        return self();\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/AccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.Account;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class AccountBuilder extends AbstractAccountBuilder<AccountBuilder> {\n\n    public AccountBuilder(String id, String name, String currency) {\n       super(id, name, currency);\n    }\n\n    protected AccountBuilder self() {\n        return this;\n    }\n\n    public Account build() {\n        return new BasicAccount(mId, mName, mCurrency, mBalance, mCustomAttributes);\n    }\n\n    static class BasicAccount implements Account {\n\n        private String mId;\n        private String mName;\n        private BigDecimal mBalance;\n        private String mCurrency;\n        private Map<String, String> mCustomAttributes;\n\n        protected BasicAccount(String id, String name, String currency, BigDecimal balance, Map<String, String> customAttributes) {\n            mId = id;\n            mCurrency = currency;\n            mName = name;\n            mBalance = balance;\n            mCustomAttributes = customAttributes;\n        }\n\n        @Override\n        public String getId() {\n            return mId;\n        }\n\n        @Override\n        public String getName() {\n            return mName;\n        }\n\n        @Override\n        public BigDecimal getBalance() {\n            return mBalance == null ? BigDecimal.ZERO : mBalance;\n        }\n\n        @Override\n        public String getCurrency() {\n            return mCurrency;\n        }\n\n        @Override\n        public Map<String, String> getCustomAttributes() {\n            return mCustomAttributes == null ? Collections.<String, String>emptyMap() : mCustomAttributes;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/CreditCardAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.CreditCardAccount;\nimport com.liato.bankdroid.api.domain.account.Transaction;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static com.liato.bankdroid.api.domain.account.impl.AccountBuilder.BasicAccount;\n\npublic class CreditCardAccountBuilder extends AbstractAccountBuilder<CreditCardAccountBuilder> {\n\n    private BigDecimal mCreditLimit;\n\n    private Collection<Transaction> mTransactions;\n\n    public CreditCardAccountBuilder(String id, String name, String currency) {\n       super(id, name, currency);\n    }\n\n    protected CreditCardAccountBuilder self() {\n        return this;\n    }\n\n    public CreditCardAccountBuilder creditLimit(BigDecimal creditLimit) {\n        mCreditLimit = creditLimit;\n        return this;\n    }\n\n    public CreditCardAccountBuilder transactions(Collection<Transaction> transactions) {\n        mTransactions = transactions;\n        return this;\n    }\n\n    public CreditCardAccount build()   {\n        return new BasicCreditCardAccount(mId, mName, mCurrency, mBalance, mCustomAttributes,\n                mCreditLimit, mTransactions);\n    }\n\n    private class BasicCreditCardAccount extends BasicAccount implements CreditCardAccount {\n\n        private BigDecimal mCreditLimit;\n        private Collection<Transaction> mTransactions;\n\n        BasicCreditCardAccount(String id, String name, String currency, BigDecimal balance,\n                Map<String, String> customAttributes, BigDecimal creditLimit,\n                Collection<Transaction> transactions) {\n            super(id, name, currency, balance, customAttributes);\n            mCreditLimit = creditLimit;\n            mTransactions = transactions;\n        }\n\n        @Override\n        public BigDecimal getCreditLimit() {\n            return mCreditLimit == null ? BigDecimal.ZERO : mCreditLimit;\n        }\n\n        public Collection<Transaction> getTransactions() {\n            return mTransactions == null ? Collections.<Transaction>emptyList() : mTransactions;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/EquityAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.Equity;\nimport com.liato.bankdroid.api.domain.account.EquityAccount;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static com.liato.bankdroid.api.domain.account.impl.AccountBuilder.BasicAccount;\n\npublic class EquityAccountBuilder extends AbstractAccountBuilder<EquityAccountBuilder> {\n\n    private BigDecimal mCost;\n\n    private BigDecimal mRevenue;\n\n    private Collection<Equity> mEquities;\n\n    public EquityAccountBuilder(String id, String name, String currency) {\n        super(id, name, currency);\n    }\n\n    protected EquityAccountBuilder self() {\n        return this;\n    }\n\n    public EquityAccountBuilder cost(BigDecimal cost) {\n        mCost = cost;\n        return this;\n    }\n\n    public EquityAccountBuilder revenue(BigDecimal revenue) {\n        mRevenue = revenue;\n        return this;\n    }\n\n    public EquityAccountBuilder addEquity(Equity equity) {\n        if (mEquities == null) {\n            mEquities = new ArrayList<>();\n        }\n        mEquities.add(equity);\n        return this;\n    }\n\n    public EquityAccountBuilder equities(Collection<Equity> equities) {\n        mEquities = equities;\n        return this;\n    }\n\n    public EquityAccount build() {\n        return new BasicEquityAccount(mId, mName, mCurrency, mBalance, mCustomAttributes, mCost,\n                mRevenue, mEquities);\n    }\n\n    private class BasicEquityAccount extends BasicAccount implements EquityAccount {\n\n        private BigDecimal mCost;\n        private BigDecimal mRevenue;\n        private Collection<Equity> mEquities;\n\n        private BasicEquityAccount(String id, String name, String currency, BigDecimal balance,\n                Map<String, String> customAttributes, BigDecimal cost, BigDecimal revenue,\n                Collection<Equity> equities) {\n            super(id, name, currency, balance, customAttributes);\n            mCost = cost;\n            mRevenue = revenue;\n            mEquities = equities;\n        }\n\n        @Override\n        public BigDecimal getBalance() {\n            //TODO calculate balance from getCost() and getRevenue()\n            return super.getBalance();\n        }\n\n        @Override\n        public BigDecimal getCost() {\n            //TODO calculate cost by summarizing cost of equities collection.\n            return mCost == null ? BigDecimal.ZERO : mCost;\n        }\n\n        @Override\n        public BigDecimal getRevenue() {\n            //TODO calculate revenue by summarizing revenue of equities collection.\n            return mRevenue == null ? BigDecimal.ZERO : mRevenue;\n        }\n\n        @Override\n        public double getRevenueAsPercentage() {\n            return 1 + getRevenue().divide(getCost()).doubleValue();\n        }\n\n        @Override\n        public Collection<Equity> getEquities() {\n            return mEquities == null ? Collections.<Equity>emptyList() : mEquities;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/EquityBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.Equity;\nimport java.math.BigDecimal;\n\npublic class EquityBuilder {\n\n    private BasicEquity mEquity;\n\n    public EquityBuilder(BigDecimal cost, BigDecimal revenue, String currency) {\n        mEquity = new BasicEquity(cost, revenue, currency);\n    }\n\n    /**\n     *\n     * @param balance Current balance of the equity.\n     * @param revenue The revenue in percentage. A value less than 1 is a loss\n     *                       and a value greater than one is a profit. e.g. {@code 0.75} represents\n     *                       a 25 % loss, while {@code 1.5} is 50 % profit.\n     * @param currency The currency of the equity.\n     */\n    public EquityBuilder(BigDecimal balance, double revenue, String currency) {\n        mEquity = new BasicEquity(costFromBalanceAndRevenue(balance, revenue),\n                revenueFromBalanceAndRevenueAsPerecntage(balance, revenue), currency);\n    }\n\n    public EquityBuilder name(String name) {\n        mEquity.mName = name;\n        return this;\n    }\n\n    public EquityBuilder quantity(double quantity) {\n        mEquity.mQuantity = quantity;\n        return this;\n    }\n\n    public Equity build() {\n        return mEquity;\n    }\n\n    private BigDecimal costFromBalanceAndRevenue(BigDecimal balance, double revenue) {\n        return balance.divide(BigDecimal.valueOf(revenue));\n    }\n\n    private BigDecimal revenueFromBalanceAndRevenueAsPerecntage(BigDecimal balance, double revenue) {\n       return balance.subtract(balance.divide(BigDecimal.valueOf(revenue)));\n    }\n\n\n    private static class BasicEquity implements Equity {\n\n        private String mName;\n\n        private String mCurrency;\n\n        private double mQuantity;\n\n        private BigDecimal mCost;\n\n        private BigDecimal mRevenue;\n\n        private BasicEquity(BigDecimal cost, BigDecimal revenue, String currency) {\n            mCost = cost;\n            mRevenue = revenue;\n            mCurrency = currency;\n        }\n\n        @Override\n        public String getName() {\n            return mName;\n        }\n\n        @Override\n        public String getCurrency() {\n            return mCurrency;\n        }\n\n        @Override\n        public double getQuantity() {\n            return mQuantity;\n        }\n\n        @Override\n        public BigDecimal getCost() {\n            return mCost == null ? BigDecimal.ZERO : mCost;\n        }\n\n        @Override\n        public BigDecimal getRevenue() {\n            return mRevenue == null ? BigDecimal.ZERO : mRevenue;\n        }\n\n        @Override\n        public double getRevenueAsPercentage() {\n            return 1 + getRevenue().divide(getCost()).doubleValue();\n        }\n\n        @Override\n        public BigDecimal getBalance() {\n            return getCost().add(getRevenue());\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/LiabilityAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.LiabilityAccount;\nimport com.liato.bankdroid.api.domain.account.Payment;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static com.liato.bankdroid.api.domain.account.impl.AccountBuilder.BasicAccount;\n\npublic class LiabilityAccountBuilder extends AbstractAccountBuilder<LiabilityAccountBuilder> {\n\n    private double mInterest;\n    private Collection<Payment> mPayments;\n\n    public LiabilityAccountBuilder(String id, String name, String currency) {\n        super(id, name, currency);\n    }\n\n    protected LiabilityAccountBuilder self() {\n        return this;\n    }\n\n    public LiabilityAccountBuilder interest(double interest) {\n        mInterest = interest;\n        return this;\n    }\n\n    public LiabilityAccountBuilder addPayment(Payment payment) {\n        if (mPayments == null) {\n            mPayments = new ArrayList<>();\n        }\n        mPayments.add(payment);\n        return this;\n    }\n\n    public LiabilityAccountBuilder payments(Collection<Payment> payments) {\n        mPayments = payments;\n        return this;\n    }\n\n    public LiabilityAccount build() {\n        return new BasicLiabilityAccount(mId, mName, mCurrency, mBalance, mCustomAttributes,\n                mInterest, mPayments);\n    }\n\n    private static class BasicLiabilityAccount extends BasicAccount implements LiabilityAccount {\n\n        private double mInterest;\n        private Collection<Payment> mPayments;\n\n        private BasicLiabilityAccount(String id, String name, String currency, BigDecimal balance,\n                Map<String, String> customAttributes, double interest, Collection<Payment> payments) {\n            super(id, name, currency, balance, customAttributes);\n            mInterest = interest;\n            mPayments = payments;\n        }\n\n        @Override\n        public double getInterest() {\n            return mInterest;\n        }\n\n        @Override\n        public Collection<Payment> getPayments() {\n            return mPayments == null ? Collections.<Payment>emptyList() : mPayments;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/PrePaidCardAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.PrePaidCardAccount;\n\nimport org.joda.time.DateTime;\n\nimport java.math.BigDecimal;\nimport java.util.Map;\n\nimport static com.liato.bankdroid.api.domain.account.impl.AccountBuilder.BasicAccount;\n\npublic class PrePaidCardAccountBuilder extends AbstractAccountBuilder<PrePaidCardAccountBuilder> {\n\n    private DateTime mValidFrom;\n    private DateTime mExpirationDate;\n\n    public PrePaidCardAccountBuilder(String id, String name, String currency) {\n        super(id, name, currency);\n    }\n\n    protected PrePaidCardAccountBuilder self() {\n        return this;\n    }\n\n    public PrePaidCardAccountBuilder validFrom(DateTime validFrom) {\n        mValidFrom = validFrom;\n        return this;\n    }\n    public PrePaidCardAccountBuilder expirationDate(DateTime expirationDate) {\n        mExpirationDate = expirationDate;\n        return this;\n    }\n\n    public PrePaidCardAccount build() {\n        return new BasicPrePaidCardAccount(mId, mName, mCurrency, mBalance, mCustomAttributes,\n                mExpirationDate, mValidFrom);\n    }\n\n    private static class BasicPrePaidCardAccount extends BasicAccount implements PrePaidCardAccount {\n\n        private DateTime mExpirationDate;\n        private DateTime mValidFrom;\n\n        private BasicPrePaidCardAccount(String id, String name, String currency, BigDecimal balance,\n                Map<String, String> customAttributes, DateTime expirationDate, DateTime validFrom) {\n            super(id, name, currency, balance, customAttributes);\n            mExpirationDate = expirationDate;\n            mValidFrom = validFrom;\n        }\n\n        @Override\n        public DateTime getExpirationDate() {\n            return mExpirationDate;\n        }\n\n        @Override\n        public DateTime getValidFrom() {\n            return mValidFrom;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/TransactionAccountBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\nimport com.liato.bankdroid.api.domain.account.Transaction;\nimport com.liato.bankdroid.api.domain.account.TransactionAccount;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static com.liato.bankdroid.api.domain.account.impl.AccountBuilder.BasicAccount;\n\npublic class TransactionAccountBuilder extends AbstractAccountBuilder<TransactionAccountBuilder> {\n\n    private Collection<Transaction> mTransactions;\n\n    public TransactionAccountBuilder(String id, String name, String currency) {\n        super(id, name, currency);\n    }\n\n    protected TransactionAccountBuilder self() {\n        return this;\n    }\n\n    public TransactionAccountBuilder addTransaction(Transaction transaction) {\n        if (mTransactions == null) {\n            mTransactions = new ArrayList<>();\n        }\n        mTransactions.add(transaction);\n        return this;\n    }\n\n    public TransactionAccountBuilder transactions(Collection<Transaction> transactions) {\n        mTransactions = transactions;\n        return this;\n    }\n\n    public TransactionAccount build() {\n        return new BasicTransactionAccount(mId, mName, mCurrency, mBalance, mCustomAttributes,\n                mTransactions);\n    }\n\n    private static class BasicTransactionAccount extends BasicAccount implements TransactionAccount {\n\n        private Collection<Transaction> mTransactions;\n\n        private BasicTransactionAccount(String id, String name, String currency, BigDecimal balance,\n                Map<String, String> customAttributes, Collection<Transaction> transactions) {\n            super(id, name, currency, balance, customAttributes);\n            mTransactions = transactions;\n        }\n\n        @Override\n        public Collection<Transaction> getTransactions() {\n            return mTransactions == null ? Collections.<Transaction>emptyList() : mTransactions;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/domain/account/impl/TransactionBuilder.java",
    "content": "package com.liato.bankdroid.api.domain.account.impl;\n\n\nimport com.liato.bankdroid.api.domain.account.Transaction;\n\nimport org.joda.time.DateTime;\n\nimport java.math.BigDecimal;\n\npublic class TransactionBuilder {\n\n    private BasicTransaction mTransaction;\n\n    public TransactionBuilder(BigDecimal amount, String currency, DateTime transactionDate) {\n        this.mTransaction = new BasicTransaction(amount, currency, transactionDate);\n    }\n\n    public TransactionBuilder description(String description) {\n        mTransaction.description = description;\n        return this;\n    }\n\n    public TransactionBuilder pending(boolean pending) {\n        mTransaction.pending = pending;\n        return this;\n    }\n\n    public Transaction build() {\n        return mTransaction;\n    }\n\n    private static class BasicTransaction implements Transaction {\n\n        private BigDecimal amount;\n        private String description;\n        private String currency;\n        private DateTime transactionDate;\n        private boolean pending;\n\n        private BasicTransaction(BigDecimal amount, String currency, DateTime transactionDate) {\n            this.amount = amount;\n            this.currency = currency;\n            this.transactionDate = transactionDate;\n        }\n\n        @Override\n        public BigDecimal getAmount() {\n            return amount;\n        }\n\n        @Override\n        public String getDescription() {\n            return description;\n        }\n\n        @Override\n        public String getCurrency() {\n            return currency;\n        }\n\n        @Override\n        public DateTime getTransactionDate() {\n            return transactionDate;\n        }\n\n        @Override\n        public boolean isPending() {\n            return pending;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-interface/src/main/java/com/liato/bankdroid/api/service/ServiceLoader.java",
    "content": "package com.liato.bankdroid.api.service;\n\nimport com.liato.bankdroid.api.ProviderFactory;\n\nimport java.util.Set;\n\n/**\n * The service loader is responsible for loading all available {@link ProviderFactory} known to the\n * application. This is the single point of creating new {@link com.liato.bankdroid.api.ProviderFactory}s.\n */\npublic interface ServiceLoader {\n\n    /**\n     * Loads all available {@link ProviderFactory}.\n     * @return A set of all available {@link ProviderFactory} within the application.\n     */\n    Set<ProviderFactory> load();\n}\n"
  },
  {
    "path": "bankdroid-legacy/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply from: '../config/quality/quality.gradle'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.1\"\n\n    useLibrary 'org.apache.http.legacy'\n    defaultConfig {\n        minSdkVersion 9\n        targetSdkVersion 25\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_7\n        targetCompatibility JavaVersion.VERSION_1_7\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(':bankdroid-interface')\n    compile 'com.android.support:appcompat-v7:25.2.0'\n    compile 'com.jakewharton.timber:timber:4.3.1'\n    compile ('org.apache.commons:commons-io:1.3.2') {exclude module: 'commons-io'}\n    compile 'org.jsoup:jsoup:1.7.3'\n    compile 'com.fasterxml.jackson.core:jackson-core:2.1.0'\n    compile 'com.fasterxml.jackson.core:jackson-databind:2.1.0'\n    compile 'com.fasterxml.jackson.core:jackson-annotations:2.1.0'\n    compile('org.simpleframework:simple-xml:2.7.1') {\n        exclude module: 'stax'\n        exclude module: 'stax-api'\n        exclude module: 'xpp3'\n    }\n\n    testCompile 'junit:junit:4.12'\n    testCompile 'org.mockito:mockito-core:1.10.19'\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.liato.bankdroid.legacy\">\n\n    <application android:allowBackup=\"true\" android:label=\"@string/app_name\">\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/Helpers.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid;\n\nimport org.apache.http.NameValuePair;\n\nimport android.app.Activity;\nimport android.support.annotation.Nullable;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.style.StrikethroughSpan;\n\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.text.DecimalFormat;\nimport java.text.DecimalFormatSymbols;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\n\nimport timber.log.Timber;\n\npublic class Helpers {\n    private static final StrikethroughSpan STRIKE_THROUGH_SPAN = new StrikethroughSpan();\n\n    private final static String[] CURRENCIES = {\"AED\", \"AFN\", \"ALL\", \"AMD\", \"ANG\", \"AOA\", \"ARS\",\n            \"AUD\",\n            \"AWG\", \"AZN\", \"BAM\", \"BBD\", \"BDT\", \"BGN\", \"BHD\", \"BIF\",\n            \"BMD\", \"BND\", \"BOB\", \"BRL\", \"BSD\", \"BTN\", \"BWP\", \"BYR\",\n            \"BZD\", \"CAD\", \"CDF\", \"CHF\", \"CLP\", \"CNY\", \"COP\", \"CRC\",\n            \"CUP\", \"CVE\", \"CYP\", \"CZK\", \"DJF\", \"DKK\", \"DOP\", \"DZD\",\n            \"EEK\", \"EGP\", \"ERN\", \"ETB\", \"EUR\", \"FJD\", \"FKP\", \"GBP\",\n            \"GEL\", \"GGP\", \"GHS\", \"GIP\", \"GMD\", \"GNF\", \"GTQ\", \"GYD\",\n            \"HKD\", \"HNL\", \"HRK\", \"HTG\", \"HUF\", \"IDR\", \"ILS\", \"IMP\",\n            \"INR\", \"IQD\", \"IRR\", \"ISK\", \"JEP\", \"JMD\", \"JOD\", \"JPY\",\n            \"KES\", \"KGS\", \"KHR\", \"KMF\", \"KPW\", \"KRW\", \"KWD\", \"KYD\",\n            \"KZT\", \"LAK\", \"LBP\", \"LKR\", \"LRD\", \"LSL\", \"LTL\", \"LVL\",\n            \"LYD\", \"MAD\", \"MDL\", \"MGA\", \"MKD\", \"MMK\", \"MNT\", \"MOP\",\n            \"MRO\", \"MTL\", \"MUR\", \"MVR\", \"MWK\", \"MXN\", \"MYR\", \"MZN\",\n            \"NAD\", \"NGN\", \"NIO\", \"NOK\", \"NPR\", \"NZD\", \"OMR\", \"PAB\",\n            \"PEN\", \"PGK\", \"PHP\", \"PKR\", \"PLN\", \"PYG\", \"QAR\", \"RON\",\n            \"RSD\", \"RUB\", \"RWF\", \"SAR\", \"SBD\", \"SCR\", \"SDG\", \"SEK\",\n            \"SGD\", \"SHP\", \"SLL\", \"SOS\", \"SPL\", \"SRD\", \"STD\", \"SVC\",\n            \"SYP\", \"SZL\", \"THB\", \"TJS\", \"TMM\", \"TND\", \"TOP\", \"TRY\",\n            \"TTD\", \"TVD\", \"TWD\", \"TZS\", \"UAH\", \"UGX\", \"USD\", \"UYU\",\n            \"UZS\", \"VEB\", \"VEF\", \"VND\", \"VUV\", \"WST\", \"XAF\", \"XAG\",\n            \"XAU\", \"XCD\", \"XDR\", \"XOF\", \"XPD\", \"XPF\", \"XPT\", \"YER\",\n            \"ZAR\", \"ZMK\", \"ZWD\"};\n\n    private final static String[][] SYM_MAPPINGS = {{\"$U\", \"UYU\"}, {\"$b\", \"BOB\"}, {\"BZ$\", \"BZD\"},\n            {\"C$\", \"NIO\"}, {\"J$\", \"JMD\"}, {\"NT$\", \"TWD\"},\n            {\"R$\", \"BRL\"}, {\"RD$\", \"DOP\"}, {\"TT$\", \"TTD\"},\n            {\"Z$\", \"ZWD\"}, {\"$\", \"USD\"}, {\"B/.\", \"PAB\"},\n            {\"Bs\", \"VEF\"}, {\"Ft\", \"HUF\"}, {\"Gs\", \"PYG\"},\n            {\"KM\", \"BAM\"}, {\"Kč\", \"CZK\"}, {\"Lek\", \"ALL\"},\n            {\"S/.\", \"PEN\"}, {\"Ls\", \"LVL\"}, {\"Lt\", \"LTL\"},\n            {\"MT\", \"MZN\"}, {\"Php\", \"PHP\"}, {\"RM\", \"MYR\"},\n            {\"Rp\", \"IDR\"}, {\"TL\", \"TRY\"}, {\"kn\", \"HRK\"},\n            {\"kr\", \"SEK\"}, {\"lei\", \"RON\"}, {\"p.\", \"BYR\"},\n            {\"L\", \"HNL\"}, {\"S\", \"SOS\"}, {\"P\", \"BWP\"},\n            {\"Q\", \"GTQ\"}, {\"R\", \"ZAR\"}, {\"zł\", \"PLN\"},\n            {\"¢\", \"GHC\"}, {\"£\", \"GBP\"}, {\"¥\", \"JPY\"},\n            {\"ƒ\", \"ANG\"}, {\"Дин.\", \"RSD\"}, {\"ден\", \"MKD\"},\n            {\"лв\", \"BGN\"}, {\"ман\", \"AZN\"}, {\"руб\", \"RUB\"},\n            {\"؋\", \"AFN\"}, {\"฿\", \"THB\"}, {\"៛\", \"KHR\"},\n            {\"₡\", \"CRC\"}, {\"₤\", \"TRL\"}, {\"₦\", \"NGN\"},\n            {\"₨\", \"PKR\"}, {\"₩\", \"KRW\"}, {\"₪\", \"ILS\"},\n            {\"₫\", \"VND\"}, {\"€\", \"EUR\"}, {\"₭\", \"LAK\"},\n            {\"₮\", \"MNT\"}, {\"₱\", \"CUP\"}, {\"₴\", \"UAH\"},\n            {\"﷼\", \"SAR\"},\n    };\n\n    private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n    public static BigDecimal parseBalance(String balance) {\n        if (balance == null) {\n            return new BigDecimal(0);\n        }\n        balance = balance.replaceAll(\"[^0-9,.-]*\", \"\");\n        balance = balance.replace(\",\", \".\");\n        if (balance.indexOf(\".\") != balance.lastIndexOf(\".\")) {\n            String b = balance.substring(balance.lastIndexOf(\".\"));\n            balance = balance.substring(0, balance.lastIndexOf(\".\"));\n            balance = balance.replace(\".\", \"\");\n            balance = balance + b;\n        }\n        BigDecimal ret;\n        try {\n            ret = new BigDecimal(balance);\n        } catch (NumberFormatException e) {\n            Timber.e(e, \"Unable to parse balance %s \", balance);\n            ret = new BigDecimal(0);\n        }\n        return ret;\n    }\n\n    public static CharSequence formatBalance(BigDecimal balance, String curr, boolean round,\n                                             @Nullable DecimalFormat format, boolean strikethrough) {\n        DecimalFormatSymbols dfs = new DecimalFormatSymbols();\n        dfs.setDecimalSeparator(',');\n        dfs.setGroupingSeparator(' ');\n        DecimalFormat currency = format;\n        if (currency == null) {\n            if (!round) {\n                currency = new DecimalFormat(\"#,##0.00 \");\n            } else {\n                currency = new DecimalFormat(\"#,##0 \");\n            }\n        }\n        currency.setDecimalFormatSymbols(dfs);\n\n        SpannableString returnMe = new SpannableString(currency.format(balance.doubleValue()) + curr);\n        if (strikethrough) {\n            returnMe.setSpan(STRIKE_THROUGH_SPAN, 0, returnMe.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        }\n\n        return returnMe;\n    }\n\n    public static CharSequence formatBalance(BigDecimal balance, String curr) {\n        return formatBalance(balance, curr, false, null, false);\n    }\n\n    static public void setActivityAnimation(Activity activity, int in, int out) {\n        try {\n            Method method = Activity.class\n                    .getMethod(\"overridePendingTransition\", int.class, int.class);\n            method.invoke(activity, in, out);\n        } catch (Exception e) {\n            Timber.w(e, \"Can't change animation, so do nothing\");\n        }\n    }\n\n    public static String parseCurrency(String text, String def) {\n        text = text != null ? text.toLowerCase() : \"\";\n        for (String currency : CURRENCIES) {\n            if (text.contains(currency)) {\n                return currency;\n            }\n        }\n        for (String[] symCur : SYM_MAPPINGS) {\n            if (text.contains(symCur[0])) {\n                return symCur[1];\n            }\n        }\n        return def;\n    }\n\n    public static String renderForm(String action, List<NameValuePair> postData) {\n        StringBuilder form = new StringBuilder();\n        form.append(\"<form id=\\\"submitform\\\" method=\\\"POST\\\" action=\\\"\")\n                .append(action)\n                .append(\"\\\">\");\n        for (NameValuePair p : postData) {\n            form.append(\"<input type=\\\"hidden\\\" name=\\\"\")\n                    .append(p.getName())\n                    .append(\"\\\" value=\\\"\")\n                    .append(p.getValue())\n                    .append(\"\\\" />\");\n        }\n        form.append(\"</form>\");\n        return form.toString();\n\n    }\n\n\n    /**\n     * Determines what year a transaction belongs to.\n     *\n     * If the given <code>day</code> of the given <code>month</code> for the current year\n     * is in the future the transaction is probably from last year.\n     *\n     * @param month The month, where January is 1.\n     * @param day   The day of the month, starting from 1.\n     * @return An ISO 8601 formatted date.\n     */\n    public static String getTransactionDate(String month, String day) {\n        return getTransactionDate(Integer.parseInt(month), Integer.parseInt(day));\n    }\n\n    /**\n     * Determines what year a transaction belongs to.\n     *\n     * If the given <code>day</code> of the given <code>month</code> for the current year\n     * is in the future the transaction is probably from last year.\n     *\n     * @param month The month, where January is 1.\n     * @param day   The day of the month, starting from 1.\n     * @return An ISO 8601 formatted date.\n     */\n    public static String getTransactionDate(int month, int day) {\n        month--; // Java-months start at 0\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        Calendar cal = Calendar.getInstance();\n        int currentYear = cal.get(Calendar.YEAR);\n        cal.set(currentYear, month, day, 0, 0);\n        if (cal.getTime().after(Calendar.getInstance().getTime())) {\n            //If the transaction is in the future the year is probably of by +1.\n            cal.add(Calendar.YEAR, -1);\n        }\n        return sdf.format(cal.getTime());\n    }\n\n    /**\n     * Remove HTML from a string.\n     *\n     * @param text The string containing HTML.\n     * @return The same string with all HTML removed.\n     */\n    public static String removeHtml(String text) {\n        return text.replaceAll(\"<[^>]+>\", \"\");\n    }\n\n    public static String formatDate(Date date) {\n        return DATE_FORMAT.format(date);\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/Account.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking;\n\nimport com.liato.bankdroid.provider.IAccountTypes;\n\nimport android.support.annotation.Nullable;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class Account implements IAccountTypes {\n\n    private String name;\n\n    private BigDecimal balance;\n\n    private String id;\n\n    private Bank bank = null;\n\n    private long bankId = -1;\n\n    private int type = Account.REGULAR;\n\n    private boolean hidden = false;\n\n    private boolean notify = true;\n\n    private String currency;\n\n    private List<Transaction> transactions;\n\n    private String aliasfor;\n\n    public Account(final String name, final BigDecimal balance,\n            final String id, final long bankId, final int type,\n            final String currency) {\n        this.name = name;\n        this.balance = balance;\n        this.id = id;\n        this.bankId = bankId;\n        this.type = type;\n        this.currency = currency;\n    }\n\n    public Account(final String name, final BigDecimal balance,\n            final String id, final long bankId) {\n        this(name, balance, id, bankId, REGULAR, \"SEK\");\n    }\n\n    public Account(final String name, final BigDecimal balance,\n            final String id, final long bankId, final int type) {\n        this(name, balance, id, bankId, type, \"SEK\");\n    }\n\n    public Account(final String name, final BigDecimal balance, final String id) {\n        this(name, balance, id, -1L);\n    }\n\n    public Account(final String name, final BigDecimal balance,\n            final String id, final int type) {\n        this(name, balance, id, -1L, type);\n    }\n\n    public Account(final String name, final BigDecimal balance,\n            final String id, final int type, final String currency) {\n        this(name, balance, id, -1L, type, currency);\n    }\n\n    public List<Transaction> getTransactions() {\n        return transactions;\n    }\n\n    public void setTransactions(final List<Transaction> transactions) {\n        this.transactions = transactions;\n    }\n\n    public boolean isNotify() {\n        return notify;\n    }\n\n    public void setNotify(final boolean notify) {\n        this.notify = notify;\n    }\n\n    public BigDecimal getBalance() {\n        return balance;\n    }\n\n    public void setBalance(final BigDecimal balance) {\n        this.balance = balance;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(final String name) {\n        this.name = name;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    @Nullable\n    public Bank getBank() {\n        return bank;\n    }\n\n    public void setBank(final Bank bank) {\n        this.bank = bank;\n    }\n\n    public long getBankDbId() {\n        return bankId;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(final int type) {\n        this.type = type;\n    }\n\n    public boolean isHidden() {\n        return this.hidden;\n    }\n\n    public void setHidden(final boolean hidden) {\n        this.hidden = hidden;\n    }\n\n    public String getCurrency() {\n        return currency;\n    }\n\n    public void setCurrency(final String currency) {\n        this.currency = currency;\n    }\n\n    public String getAliasfor() {\n        return aliasfor;\n    }\n\n    public void setAliasfor(final String aliasfor) {\n        this.aliasfor = aliasfor;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/Bank.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.api.configuration.Field;\nimport com.liato.bankdroid.api.configuration.ProviderConfiguration;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.CookieStore;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.content.res.Resources.NotFoundException;\nimport android.support.annotation.DrawableRes;\nimport android.support.annotation.Nullable;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\npublic abstract class Bank implements Comparable<Bank>, IBankTypes {\n\n    private final ProviderConfiguration defaultConfiguration = new LegacyProviderConfiguration(this);\n\n    @DrawableRes\n    private final int logoResource;\n\n    /**\n     * URL for human-accessible web bank.\n     * <p/>\n     * Can be set to null to disable. Lots of banks don't have this any more, but have\n     * apps instead.\n     * <p/>\n     * @see #isWebViewEnabled()\n     */\n    @Nullable\n    protected String url;\n\n    protected int inputTypeUsername = InputType.TYPE_CLASS_TEXT;\n\n    protected int inputTypePassword = InputType.TYPE_CLASS_TEXT\n            | InputType.TYPE_TEXT_VARIATION_PASSWORD;\n\n    private static final int INPUT_TYPE_EXTRAS = InputType.TYPE_CLASS_TEXT;\n\n    protected String inputHintUsername = null;\n\n    private static final boolean INPUT_HIDDEN_USERNAME = false;\n\n    protected boolean inputHiddenPassword = false;\n\n    private static final boolean INPUT_HIDDEN_EXTRAS = true;\n\n    protected int inputTitletextUsername = R.string.username;\n\n    private final int INPUT_TITLETEXT_PASSWORD = R.string.password;\n\n    private final int INPUT_TITLETEXT_EXTRAS = R.string.extras_field;\n\n    protected boolean staticBalance = false;\n\n    private static final boolean BROKEN = false;\n\n    protected boolean displayDecimals = true;\n\n    /**\n     * Whether or not we support opening the web version of a bank.\n     * <p/>\n     * Lots of banks don't have this any more, but have apps instead.\n     * @see #isWebViewEnabled()\n     * @see #url\n     */\n    protected boolean webViewEnabled = true;\n\n    protected Context context;\n\n    protected Resources res;\n\n    protected String customName;\n\n    protected String currency = \"SEK\";\n\n    protected ArrayList<Account> accounts = new ArrayList<Account>();\n\n    protected HashMap<String, Account> oldAccounts;\n\n    protected BigDecimal balance = new BigDecimal(0);\n\n    protected boolean disabled = false;\n\n    protected long dbid = -1;\n\n    protected Urllib urlopen = null;\n\n    protected boolean hideAccounts = false;\n\n    private Map<String, String> properties;\n\n    public Bank(Context context, @DrawableRes int logoResource) {\n        this.context = context;\n        this.res = this.context.getResources();\n        this.logoResource = logoResource;\n    }\n\n    public boolean toggleHideAccounts() {\n        hideAccounts = !hideAccounts;\n        return hideAccounts;\n    }\n\n    public boolean getHideAccounts() {\n        return hideAccounts;\n    }\n\n    public Urllib getUrlopen() {\n        return urlopen;\n    }\n\n    public void setUrlopen(Urllib urlopen) {\n        this.urlopen = urlopen;\n    }\n\n    public void setDbid(long dbid) {\n        this.dbid = dbid;\n    }\n\n    public void update(String username, String password) throws BankException, LoginException,\n            BankChoiceException, IOException {\n        setUsername(username);\n        setPassword(password);\n        this.update();\n    }\n\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        balance = new BigDecimal(0);\n        oldAccounts = new HashMap<String, Account>();\n        for (Account account : accounts) {\n            oldAccounts.put(account.getId(), account);\n        }\n        accounts = new ArrayList<Account>();\n    }\n\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n    }\n\n    public void updateAllTransactions() throws LoginException, BankException, IOException {\n        if (urlopen == null) {\n            urlopen = login();\n        }\n        for (Account account : accounts) {\n            updateTransactions(account, urlopen);\n        }\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        return null;\n    }\n\n    public void closeConnection() {\n        if (urlopen != null) {\n            urlopen.close();\n        }\n    }\n\n    public ArrayList<Account> getAccounts() {\n        return this.accounts;\n    }\n\n    public void setAccounts(ArrayList<Account> accounts) {\n        this.accounts = accounts;\n        for (Account a : accounts) {\n            a.setBank(this);\n        }\n    }\n\n    public String getPassword() {\n        String password = getProperty(LegacyProviderConfiguration.PASSWORD);\n        return password == null ? \"\" : password;\n    }\n\n    public void setPassword(String password) {\n        getProperties().put(LegacyProviderConfiguration.PASSWORD, password);\n    }\n\n    public String getUsername() {\n        String username = getProperty(LegacyProviderConfiguration.USERNAME);\n        return username == null ? \"\" : username;\n    }\n\n    public void setUsername(String username) {\n        getProperties().put(LegacyProviderConfiguration.USERNAME, username);\n    }\n\n    public BigDecimal getBalance() {\n        if (staticBalance) {\n            return balance;\n        } else {\n            BigDecimal bal = new BigDecimal(0);\n            for (Account account : accounts) {\n                if (account.getType() == Account.REGULAR || account.getType() == Account.CCARD) {\n                    if (!account.isHidden() && (account.getAliasfor() == null\n                            || account.getAliasfor().length() == 0)\n                            && account.getBalance() != null) {\n                        bal = bal.add(account.getBalance());\n                    }\n                }\n            }\n            return bal;\n        }\n    }\n\n    public abstract int getBanktypeId();\n\n    public abstract String getName();\n\n    public String getDisplayName() {\n        if (customName != null && customName.length() > 0) {\n            return customName;\n        }\n        return getUsername();\n    }\n\n    public String getCustomName() {\n        return customName;\n    }\n\n    public void setCustomName(String customName) {\n        this.customName = customName;\n    }\n\n    public String getExtras() {\n        String extras = getProperty(LegacyProviderConfiguration.EXTRAS);\n        return extras == null ? \"\" : extras;\n    }\n\n    public void setExtras(String extras) {\n        getProperties().put(LegacyProviderConfiguration.EXTRAS, extras);\n      }\n\n    public void setData(BigDecimal balance,\n            boolean disabled, long dbid, String currency, String customName,\n            int hideAccounts) {\n        this.balance = balance;\n        this.disabled = disabled;\n        this.dbid = dbid;\n        this.currency = currency;\n        this.customName = customName;\n        this.hideAccounts = hideAccounts == 1 ? true : false;\n    }\n\n    public String getCurrency() {\n        return currency;\n    }\n\n    public void setCurrency(String currency) {\n        this.currency = currency;\n    }\n\n    public long getDbId() {\n        return dbid;\n    }\n\n    public boolean isDisabled() {\n        return disabled;\n    }\n\n    public void setDisabled(boolean disabled) {\n        this.disabled = disabled;\n    }\n\n    public String getURL() {\n        return url;\n    }\n\n    public int getInputTypeUsername() {\n        return inputTypeUsername;\n    }\n\n    public int getInputTypePassword() {\n        return inputTypePassword;\n    }\n\n    public int getInputTypeExtras() {\n        return INPUT_TYPE_EXTRAS;\n    }\n\n    public String getInputHintUsername() {\n        return inputHintUsername;\n    }\n\n    public boolean isInputUsernameHidden() {\n        return INPUT_HIDDEN_USERNAME;\n    }\n\n    public boolean isInputPasswordHidden() {\n        return inputHiddenPassword;\n    }\n\n    public boolean isInputExtrasHidden() {\n        return INPUT_HIDDEN_EXTRAS;\n    }\n\n    public int getInputTitleUsername() {\n        return inputTitletextUsername;\n    }\n\n    public int getInputTitlePassword() {\n        return INPUT_TITLETEXT_PASSWORD;\n    }\n\n    public int getInputTitleExtras() {\n        return INPUT_TITLETEXT_EXTRAS;\n    }\n\n    /**\n     * Whether or not we support opening the web version of a bank.\n     * <p/>\n     * Lots of banks don't have this any more, but have apps instead.\n     * @see #webViewEnabled\n     * @see #url\n     */\n    public boolean isWebViewEnabled() {\n        return url != null && webViewEnabled;\n    }\n\n    public Map<String, String> getProperties() {\n        if (this.properties == null) {\n            this.properties = new HashMap<>();\n        }\n        return this.properties;\n    }\n\n    public String getProperty(String name) {\n        return getProperties().get(name);\n    }\n\n    public void setProperties(Map<String, String> properties) {\n        this.properties = properties;\n    }\n\n    // Returns true if the current implementation of this bank is broken.\n    public boolean isBroken() {\n        return BROKEN;\n    }\n\n    @DrawableRes\n    public final int getImageResource() {\n        return logoResource;\n    }\n\n    public int compareTo(Bank another) {\n        return this.getName().compareToIgnoreCase(another.getName());\n    }\n\n    public List<Field> getConnectionConfiguration() {\n        return defaultConfiguration.getConnectionConfiguration();\n    }\n\n    public void updateComplete() {\n        for (Account a : this.accounts) {\n            //Preserve hidden and notify settings from old accounts\n            if (oldAccounts != null) {\n                Account oa = oldAccounts.get(a.getId());\n                if (oa != null) {\n                    a.setHidden(oa.isHidden());\n                    a.setNotify(oa.isNotify());\n                    a.setCurrency(oa.getCurrency());\n                }\n            }\n            a.setBank(this);\n        }\n    }\n\n    public SessionPackage getSessionPackage(Context context) {\n        String preloader = \"Error...\";\n        try {\n            preloader = IOUtils.toString(context.getResources().openRawResource(R.raw.loading));\n        } catch (NotFoundException | IOException e1) {\n            Timber.w(e1, \"Error getting session package\");\n        }\n\n        try {\n            LoginPackage lp = preLogin();\n            if (lp == null) {\n                throw new BankException(\n                        \"No automatic login for this bank. preLogin() is not implemented or has failed.\");\n            }\n            //TODO: Skip the form submission. Login using Bank.login(...) and transfer cookies to webview. The user is now logged in\n            //      and can me directed to any page.\n            String html = \"\";\n            if (!lp.isLoggedIn()) {\n                html = String.format(preloader,\n                        \"function go(){document.getElementById('submitform').submit(); }\",\n                        // Javascript function\n                        Helpers.renderForm(lp.getLoginTarget(), lp.getPostData())\n                                + \"<script type=\\\"text/javascript\\\">setTimeout('go()', 1000);</script>\"\n                        // HTML\n                );\n            } else {\n                html = String.format(preloader,\n                        String.format(\"function go(){window.location=\\\"%s\\\" }\",\n                                lp.getLoginTarget()), // Javascript function\n                        \"<script type=\\\"text/javascript\\\">setTimeout('go()', 100);</script>\" // HTML\n                );\n            }\n\n            CookieStore cookies = urlopen.getHttpclient().getCookieStore();\n            return new SessionPackage(html, cookies);\n        } catch (IOException | BankException e) {\n            Timber.e(e, \"Error getting session package\");\n        }\n        String html = String.format(preloader,\n                String.format(\"function go(){window.location=\\\"%s\\\" }\", this.url),\n                // Javascript function\n                \"<script type=\\\"text/javascript\\\">setTimeout('go()', 1000);</script>\" // HTML\n        );\n        return new SessionPackage(html, null);\n    }\n\n    protected LoginPackage preLogin() throws BankException, IOException {\n        return null;\n    }\n\n    public boolean getDisplayDecimals() {\n        return displayDecimals;\n    }\n\n    protected Context getContext() {\n        return context;\n    }\n\n    public DecimalFormat getDecimalFormatter() {\n        return null;\n    }\n\n    public static class SessionPackage {\n\n        private String html;\n\n        private CookieStore cookiestore;\n\n        public SessionPackage(String html, CookieStore cookiestore) {\n            this.html = html;\n            this.cookiestore = cookiestore;\n        }\n\n        public String getHtml() {\n            return html;\n        }\n\n        public CookieStore getCookiestore() {\n            return cookiestore;\n        }\n    }\n\n    public static class LoginPackage {\n\n        private String response;\n\n        private Urllib urllib;\n\n        private List<NameValuePair> postData;\n\n        private String loginTarget;\n\n        private boolean isLoggedIn = false;\n\n        public LoginPackage(Urllib urllib, List<NameValuePair> postData, String response,\n                String loginTarget) {\n            this.urllib = urllib;\n            this.postData = postData;\n            this.response = response;\n            this.loginTarget = loginTarget;\n        }\n\n        public void setIsLoggedIn(boolean loggedIn) {\n            this.isLoggedIn = loggedIn;\n        }\n\n        public String getResponse() {\n            return response;\n        }\n\n        public Urllib getUrllib() {\n            return urllib;\n        }\n\n        public List<NameValuePair> getPostData() {\n            return postData;\n        }\n\n        public String getLoginTarget() {\n            return loginTarget;\n        }\n\n        public boolean isLoggedIn() {\n            return this.isLoggedIn;\n        }\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (obj == null || obj.getClass() != this.getClass()) {\n            return false;\n        }\n        Bank bank = (Bank) obj;\n        return bank.getBanktypeId() == this.getBanktypeId();\n    }\n\n    @Override\n    public int hashCode() {\n        return getBanktypeId();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/BankChoice.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking;\n\npublic class BankChoice {\n\n    private String name;\n\n    private String id;\n\n    public BankChoice(String name, String id) {\n        this.name = name;\n        this.id = id;\n    }\n\n    /**\n     * @return the name\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * @param name the name to set\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * @return the id\n     */\n    public String getId() {\n        return id;\n    }\n\n    /**\n     * @param id the id to set\n     */\n    public void setId(String id) {\n        this.id = id;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/BasicProviderConfiguration.java",
    "content": "package com.liato.bankdroid.banking;\n\nimport com.liato.bankdroid.api.configuration.Field;\nimport com.liato.bankdroid.api.configuration.FieldBuilder;\nimport com.liato.bankdroid.api.configuration.FieldType;\nimport com.liato.bankdroid.api.configuration.ProviderConfiguration;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ResourceBundle;\n\npublic class BasicProviderConfiguration implements ProviderConfiguration {\n\n    public static final String FIELD_USERNAME = \"username\";\n    public static final String FIELD_PASSWORD = \"password\";\n\n    private static final ResourceBundle LOCALE = ResourceBundle.getBundle(\"i18n.application\");\n\n    private final List<Field> mFields;\n\n    public BasicProviderConfiguration() {\n        mFields = createConfiguration();\n    }\n\n    @Override\n    public List<Field> getConnectionConfiguration() {\n        return mFields;\n    }\n\n    private List<Field> createConfiguration() {\n\n        List<Field> fields = new LinkedList<>();\n\n        fields.add(new FieldBuilder(FIELD_USERNAME, LOCALE)\n                .fieldType(FieldType.TEXT)\n                .placeholder(\"\")\n                .required(true)\n                .build()\n        );\n\n        fields.add(new FieldBuilder(FIELD_PASSWORD, LOCALE)\n                        .fieldType(FieldType.TEXT)\n                        .placeholder(\"\")\n                        .secret(true)\n                        .required(true)\n                        .build()\n        );\n        return fields;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/LegacyBankFactory.java",
    "content": "package com.liato.bankdroid.banking;\n\nimport com.liato.bankdroid.banking.banks.AkeliusInvest;\nimport com.liato.bankdroid.banking.banks.AkeliusSpar;\nimport com.liato.bankdroid.banking.banks.americanexpress.AmericanExpress;\nimport com.liato.bankdroid.banking.banks.AppeakPoker;\nimport com.liato.bankdroid.banking.banks.BetterGlobe;\nimport com.liato.bankdroid.banking.banks.Bioklubben;\nimport com.liato.bankdroid.banking.banks.BlekingeTrafiken;\nimport com.liato.bankdroid.banking.banks.Bredband2VoIP;\nimport com.liato.bankdroid.banking.banks.BrummerKF;\nimport com.liato.bankdroid.banking.banks.CSN;\nimport com.liato.bankdroid.banking.banks.Chalmrest;\nimport com.liato.bankdroid.banking.banks.DanskeBank;\nimport com.liato.bankdroid.banking.banks.Everydaycard;\nimport com.liato.bankdroid.banking.banks.FirstCard;\nimport com.liato.bankdroid.banking.banks.Hemkop;\nimport com.liato.bankdroid.banking.banks.Hors;\nimport com.liato.bankdroid.banking.banks.IKEA;\nimport com.liato.bankdroid.banking.banks.IkanoBank;\nimport com.liato.bankdroid.banking.banks.Jojo;\nimport com.liato.bankdroid.banking.banks.McDonalds;\nimport com.liato.bankdroid.banking.banks.Meniga;\nimport com.liato.bankdroid.banking.banks.MinPension;\nimport com.liato.bankdroid.banking.banks.Nordnet;\nimport com.liato.bankdroid.banking.banks.OKQ8;\nimport com.liato.bankdroid.banking.banks.Ostgotatrafiken;\nimport com.liato.bankdroid.banking.banks.Osuuspankki;\nimport com.liato.bankdroid.banking.banks.Payson;\nimport com.liato.bankdroid.banking.banks.PlusGirot;\nimport com.liato.bankdroid.banking.banks.SevenDay;\nimport com.liato.bankdroid.banking.banks.SveaDirekt;\nimport com.liato.bankdroid.banking.banks.SvenskaSpel;\nimport com.liato.bankdroid.banking.banks.TestBank;\nimport com.liato.bankdroid.banking.banks.TicketRikskortet;\nimport com.liato.bankdroid.banking.banks.Vasttrafik;\nimport com.liato.bankdroid.banking.banks.Zidisha;\nimport com.liato.bankdroid.banking.banks.bitcoin.Bitcoin;\nimport com.liato.bankdroid.banking.banks.coop.Coop;\nimport com.liato.bankdroid.banking.banks.ica.ICA;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.Lansforsakringar;\nimport com.liato.bankdroid.banking.banks.nordea.Nordea;\nimport com.liato.bankdroid.banking.banks.rikslunchen.Rikslunchen;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.preference.PreferenceManager;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class LegacyBankFactory {\n\n    public static Bank fromBanktypeId(int id, Context context) throws BankException {\n        switch (id) {\n            case IBankTypes.TESTBANK:\n                return new TestBank(context);\n            case IBankTypes.AKELIUSINVEST:\n                return new AkeliusInvest(context);\n            case IBankTypes.AKELIUSSPAR:\n                return new AkeliusSpar(context);\n            case IBankTypes.NORDEA:\n                return new Nordea(context);\n            case IBankTypes.LANSFORSAKRINGAR:\n                return new Lansforsakringar(context);\n            case IBankTypes.COOP:\n                return new Coop(context);\n            case IBankTypes.ICA:\n                return new ICA(context);\n            case IBankTypes.OKQ8:\n                return new OKQ8(context);\n            case IBankTypes.FIRSTCARD:\n                return new FirstCard(context);\n            case IBankTypes.PAYSON:\n                return new Payson(context);\n            case IBankTypes.JOJO:\n                return new Jojo(context);\n            case IBankTypes.IKANOBANK:\n                return new IkanoBank(context);\n            case IBankTypes.RIKSLUNCHEN:\n                return new Rikslunchen(context);\n            case IBankTypes.HEMKOP:\n                return new Hemkop(context);\n            case IBankTypes.NORDNET:\n                return new Nordnet(context);\n            case IBankTypes.SEVENDAY:\n                return new SevenDay(context);\n            case IBankTypes.OSUUSPANKKI:\n                return new Osuuspankki(context);\n            case IBankTypes.CSN:\n                return new CSN(context);\n            case IBankTypes.AMERICANEXPRESS:\n                return new AmericanExpress(context);\n            case IBankTypes.MCDONALDS:\n                return new McDonalds(context);\n            case IBankTypes.PLUSGIROT:\n                return new PlusGirot(context);\n            case IBankTypes.IKEA:\n                return new IKEA(context);\n            case IBankTypes.DANSKEBANK:\n                return new DanskeBank(context);\n            case IBankTypes.VASTTRAFIK:\n                return new Vasttrafik(context);\n            case IBankTypes.EVERYDAYCARD:\n                return new Everydaycard(context);\n            case IBankTypes.MENIGA:\n                return new Meniga(context);\n            case IBankTypes.RIKSKORTET:\n                return new TicketRikskortet(context);\n            case IBankTypes.BIOKLUBBEN:\n                return new Bioklubben(context);\n            case IBankTypes.CHALMREST:\n                return new Chalmrest(context);\n            case IBankTypes.SVENSKASPEL:\n                return new SvenskaSpel(context);\n            case IBankTypes.APPEAKPOKER:\n                return new AppeakPoker(context);\n            case IBankTypes.BRUMMER_KF:\n                return new BrummerKF(context);\n            case IBankTypes.ZIDISHA:\n                return new Zidisha(context);\n            case IBankTypes.BETTERGLOBE:\n                return new BetterGlobe(context);\n            case IBankTypes.BITCOIN:\n                return new Bitcoin(context);\n            case IBankTypes.SVEADIREKT:\n                return new SveaDirekt(context);\n            case IBankTypes.BLEKINGETRAFIKEN:\n                return new BlekingeTrafiken(context);\n            case IBankTypes.OSTGOTATRAFIKEN:\n                return new Ostgotatrafiken(context);\n            case IBankTypes.BREDBAND2VOIP:\n                return new Bredband2VoIP(context);\n            case IBankTypes.MINPENSION:\n                return new MinPension(context);\n            case IBankTypes.HORS:\n                return new Hors(context);\n            default:\n                throw new BankException(\"BankType id not found: \" + id);\n        }\n    }\n\n    public static List<Bank> listBanks(Context context) {\n        List<Bank> banks = new ArrayList<>();\n        banks.add(new AkeliusInvest(context));\n        banks.add(new AkeliusSpar(context));\n        banks.add(new BrummerKF(context));\n        banks.add(new Nordea(context));\n        banks.add(new Lansforsakringar(context));\n        banks.add(new Coop(context));\n        banks.add(new ICA(context));\n        banks.add(new OKQ8(context));\n        banks.add(new FirstCard(context));\n        banks.add(new Payson(context));\n        banks.add(new Jojo(context));\n        banks.add(new IkanoBank(context));\n        banks.add(new Rikslunchen(context));\n        banks.add(new Hemkop(context));\n        banks.add(new Nordnet(context));\n        banks.add(new SevenDay(context));\n        banks.add(new Osuuspankki(context));\n        banks.add(new CSN(context));\n        banks.add(new McDonalds(context));\n        banks.add(new AmericanExpress(context));\n        banks.add(new PlusGirot(context));\n        banks.add(new IKEA(context));\n        banks.add(new Vasttrafik(context));\n        banks.add(new Everydaycard(context));\n        banks.add(new Meniga(context));\n        banks.add(new TicketRikskortet(context));\n        banks.add(new Bioklubben(context));\n        banks.add(new Chalmrest(context));\n        banks.add(new SvenskaSpel(context));\n        banks.add(new AppeakPoker(context));\n        banks.add(new Zidisha(context));\n        banks.add(new BetterGlobe(context));\n        banks.add(new Bitcoin(context));\n        banks.add(new SveaDirekt(context));\n        banks.add(new BlekingeTrafiken(context));\n        banks.add(new Ostgotatrafiken(context));\n        banks.add(new Bredband2VoIP(context));\n        banks.add(new MinPension(context));\n        banks.add(new Hors(context));\n\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        if (prefs.getBoolean(\"debug_mode\", false)) {\n            banks.add(new TestBank(context));\n        }\n        return banks;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/LegacyBankHelper.java",
    "content": "package com.liato.bankdroid.banking;\n\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport timber.log.Timber;\n\npublic class LegacyBankHelper {\n\n    private static Map<String, Integer> legacyProviderReferences;\n    private static Map<Integer, String> providerReferences;\n\n    public static String getReferenceFromLegacyId(int legacyId) {\n        if (providerReferences == null) {\n            generateLegacyProviderReferences();\n        }\n        return providerReferences.get(legacyId);\n    }\n\n    // TODO Used during refactoring. Remove before 2.0\n    public static int getLegacyIdFromReference(String reference) {\n        if (legacyProviderReferences == null) {\n            generateLegacyProviderReferences();\n        }\n        return legacyProviderReferences.get(reference);\n    }\n\n    private static void generateLegacyProviderReferences() {\n        Map<Integer, String> references = new HashMap<>();\n        Map<String, Integer> legacyIds = new HashMap<>();\n        Field[] fields = IBankTypes.class.getFields();\n        for (Field field : fields) {\n            try {\n                String reference = field.getName().toLowerCase().replaceAll(\"_\", \"-\");\n                Integer legacyId = field.getInt(new IBankTypes() {\n                });\n                references.put(legacyId, reference);\n                legacyIds.put(reference, legacyId);\n            } catch (IllegalAccessException e) {\n                Timber.e(e, \"Provider could not be mapped\");\n            }\n        }\n        legacyProviderReferences = legacyIds;\n        providerReferences = references;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/LegacyProviderConfiguration.java",
    "content": "package com.liato.bankdroid.banking;\nimport com.liato.bankdroid.api.configuration.Field;\nimport com.liato.bankdroid.api.configuration.FieldBuilder;\nimport com.liato.bankdroid.api.configuration.ProviderConfiguration;\nimport com.liato.bankdroid.utils.FieldTypeMapper;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class LegacyProviderConfiguration implements ProviderConfiguration {\n\n    public static final String USERNAME = \"legacy.username\";\n\n    public static final String PASSWORD = \"legacy.password\";\n\n    public static final String EXTRAS = \"legacy.extras\";\n\n    private List<Field> mConfiguration;\n\n    private Bank mLegacyBank;\n\n    public LegacyProviderConfiguration(Bank legacyBank) {\n        mLegacyBank = legacyBank;\n    }\n\n    @Override\n    public List<Field> getConnectionConfiguration() {\n        if (mConfiguration == null) {\n            mConfiguration = createConfiguration();\n        }\n        return mConfiguration;\n    }\n\n    private List<Field> createConfiguration() {\n        List<Field> configuration = new LinkedList<>();\n        configuration.add(new FieldBuilder(USERNAME)\n                .label(mLegacyBank.getContext().getString(mLegacyBank.getInputTitleUsername()))\n                .placeholder(mLegacyBank.getInputHintUsername())\n                .hidden(mLegacyBank.isInputUsernameHidden())\n                .required(true)\n                .fieldType(FieldTypeMapper.toFieldType(mLegacyBank.getInputTypeUsername()))\n                .build());\n\n        configuration.add(new FieldBuilder(PASSWORD)\n                .label(mLegacyBank.getContext().getString(mLegacyBank.getInputTitlePassword()))\n                .hidden(mLegacyBank.isInputPasswordHidden())\n                .secret(true)\n                .required(!mLegacyBank.isInputPasswordHidden())\n                .fieldType(FieldTypeMapper.toFieldType(mLegacyBank.getInputTypePassword()))\n                .build());\n\n        configuration.add(new FieldBuilder(EXTRAS)\n                .label(mLegacyBank.getContext().getString(mLegacyBank.getInputTitleExtras()))\n                .hidden(mLegacyBank.isInputExtrasHidden())\n                .fieldType(FieldTypeMapper.toFieldType(mLegacyBank.getInputTypeExtras()))\n                .build());\n\n        return configuration;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/Transaction.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking;\n\nimport java.math.BigDecimal;\n\npublic class Transaction implements Comparable<Transaction> {\n\n    private String date;\n\n    private String transaction;\n\n    private BigDecimal amount;\n\n    private String currency;\n\n    public Transaction(String date, String transaction, BigDecimal amount, String currency) {\n        this.date = date;\n        this.transaction = transaction;\n        this.amount = amount;\n        this.currency = currency;\n    }\n\n    public Transaction(String date, String transaction, BigDecimal amount) {\n        this(date, transaction, amount, \"SEK\");\n    }\n\n    public String getDate() {\n        return date;\n    }\n\n    public void setDate(String date) {\n        this.date = date;\n    }\n\n    public String getTransaction() {\n        return transaction;\n    }\n\n    public void setTransaction(String transaction) {\n        this.transaction = transaction;\n    }\n\n    public BigDecimal getAmount() {\n        return amount;\n    }\n\n    public void setAmount(BigDecimal amount) {\n        this.amount = amount;\n    }\n\n    public String getCurrency() {\n        return currency;\n    }\n\n    public void setCurrency(String currency) {\n        this.currency = currency;\n    }\n\n    @Override\n    public int compareTo(Transaction another) {\n        try {\n            Integer thisdate = Integer.parseInt(date.replaceAll(\"-\", \"\"));\n            Integer thatdate = Integer.parseInt((another).getDate().replaceAll(\"-\", \"\"));\n            return thatdate - thisdate;\n        } catch (NumberFormatException e) {\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/AbsIkanoPartner.java",
    "content": "/*\n *  Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.support.annotation.DrawableRes;\nimport android.text.InputType;\nimport android.text.TextUtils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic abstract class AbsIkanoPartner extends Bank {\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅÅÅMMDDXXXX\";\n\n    protected String structId;\n\n    private String response = null;\n\n    public AbsIkanoPartner(Context context, @DrawableRes int logoResource) {\n        super(context, logoResource);\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = true;\n    }\n\n    public AbsIkanoPartner(String username, String password, Context context, @DrawableRes int logoResource)\n            throws BankException, LoginException,\n            BankChoiceException, IOException {\n        this(context, logoResource);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_ikanopartner));\n        response = urlopen\n                .open(\"https://partner.ikanobank.se/web/engines/page.aspx?structid=\" + structId);\n\n        Document d = Jsoup.parse(response);\n        Element viewstate = d.getElementById(\"__VIEWSTATE\");\n        if (viewstate == null || TextUtils.isEmpty(viewstate.val())) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n\n        Element eventvalidation = d.getElementById(\"__EVENTVALIDATION\");\n        if (eventvalidation == null || TextUtils.isEmpty(eventvalidation.val())) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n\n        Element userField = d.select(\"#LoginSpan input[type=text]\").first();\n        Element passField = d.select(\"#LoginSpan input[type=password]\").first();\n        Element submitField = d.select(\"#LoginCustomerDiv input[type=submit]\").first();\n\n        if (userField == null || passField == null || submitField == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" login fields.\");\n        }\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewstate.val()));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventvalidation.val()));\n        postData.add(new BasicNameValuePair(userField.attr(\"name\"), getUsername()));\n        postData.add(new BasicNameValuePair(passField.attr(\"name\"), getPassword()));\n        postData.add(new BasicNameValuePair(submitField.attr(\"name\"), submitField.val()));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://partner.ikanobank.se/web/engines/page.aspx?structid=\" + structId);\n\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"eller personnumme\") || response.contains(\"elaktigt personnummer\")\n                || response.contains(\"ontrollera personnummer\") || response\n                .contains(\"elaktig inloggningskod\")\n                || response.contains(\"elaktig självbetjäningskod\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Document d = Jsoup.parse(response);\n        Element element = d.select(\"#primary-nav > li:eq(1) > a\").first();\n        if (element != null && element.attr(\"href\") != null) {\n            String myAccountUrl = element.attr(\"href\");\n\n            response = urlopen.open(\"https://partner.ikanobank.se/\" + myAccountUrl);\n            d = Jsoup.parse(response);\n            Elements es = d.select(\"#CustomerAccountInformationSpan > span > span\");\n            int accId = 0;\n            for (Element el : es) {\n                Element name = el.select(\"> span > span:eq(0)\").first();\n                Element currency = el.select(\"> span:eq(2)\").first();\n                Element balance = el.select(\"> span:eq(1)\").first();\n                if (name != null && balance != null && currency != null) {\n                    Account account = new Account(name.text().trim(),\n                            Helpers.parseBalance(balance.text()),\n                            Integer.toString(accId));\n                    account.setCurrency(Helpers.parseCurrency(currency.text(), \"SEK\"));\n                    if (accId > 0) {\n                        account.setAliasfor(\"0\");\n                    }\n                    accounts.add(account);\n                    accId++;\n                }\n            }\n            if (accounts.isEmpty()) {\n                throw new BankException(res.getText(R.string.no_accounts_found).toString());\n            }\n            // Use the amount from \"Kvar att handla för\" which should be the\n            // last account in the list.\n            this.balance = accounts.get(accounts.size() - 1).getBalance();\n            ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n            es = d.select(\"#ShowCustomerTransactionPurchasesInformationDiv table tr:has(td)\");\n            for (Element el : es) {\n                if (el.childNodeSize() == 6) {\n                    Transaction transaction = new Transaction(el.child(0).text().trim(),\n                            el.child(1).text().trim(),\n                            Helpers.parseBalance(el.child(2).text()));\n                    transaction\n                            .setCurrency(Helpers.parseCurrency(el.child(3).text().trim(), \"SEK\"));\n                    transactions.add(transaction);\n                }\n            }\n            accounts.get(0).setTransactions(transactions);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/AkeliusInvest.java",
    "content": "/* Copyright (C) 2012 Nullbyte <http://nullbyte.eu>, first version by Snah@Swedroid 2012-01-06\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class AkeliusInvest extends Bank {\n\n    private static final String NAME = \"Akelius Invest\";\n\n    private static final String URL = \"https://online.akeliusinvest.com/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.AKELIUSINVEST;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"XXXXXXX\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    private Pattern reLogintoken = Pattern.compile(\"logintoken\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reError = Pattern.compile(\"<label\\\\s+class=\\\"error\\\">(.+?)</label>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<tr>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+><a[^?]+\\\\?selectedaccount=([^\\\"]+)\\\">([^<]+)</a></td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    //private Pattern reBalanceDisp = Pattern.compile(\"account\\\\.aspx\\\\?id=([^\\\"]+).+?>([^<]+)</a.+?Disponibelt([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n    //private Pattern reBalanceSald = Pattern.compile(\"account\\\\.aspx\\\\?id=([^\\\"]+).+?>([^<]+)</a[^D]*Saldo([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n    // private Pattern reBalance = Pattern.compile(\"AccountStatement\\\\.mws\\\\?selectedaccount=([^\\\"]+).+?>([^<]+)</a.+?Disponibelt([0-9 .,-]+)[^<]*<br/>.+?Saldo([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE);\n    private Pattern reTransactions = Pattern\n            .compile(\"top\\\">([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n                    Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private HashMap<String, String> mIdMappings = new HashMap<String, String>();\n\n    public AkeliusInvest(Context context) {\n        super(context, R.drawable.logo_akeliusinvest);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n    }\n\n    public AkeliusInvest(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_akeliusinvest));\n        String response = urlopen.open(\"https://online.akeliusinvest.com/login.mws\");\n        Matcher matcher = reLogintoken.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" logintoken.\");\n        }\n        String strLogintoken = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"action\", \"login\"));\n        postData.add(new BasicNameValuePair(\"logintoken\", strLogintoken));\n        postData.add(new BasicNameValuePair(\"df_username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"df_password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"Language\", \"SV\"));\n        postData.add(new BasicNameValuePair(\"IdleTime\", \"900\"));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"https://online.akeliusinvest.com/login.mws\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        String response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        Matcher matcher = reError.matcher(response);\n        if (matcher.find()) {\n            String errormsg = Html.fromHtml(matcher.group(1).trim()).toString();\n            if (errormsg.contains(\"ord eller personnummer\") || errormsg.contains(\"et alternativ\")\n                    || errormsg.contains(\"fyra siffror\")) {\n                throw new LoginException(errormsg);\n            } else {\n                throw new BankException(errormsg);\n            }\n        }\n        return urlopen;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        String response = urlopen.open(\"https://online.akeliusinvest.com/AccountPortfolio.mws\");\n        Matcher matcher = reAccounts.matcher(response);\n        int accId = 0;\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                ICA                    AKELIUSINVEST\n             * 1: ID                0000000000            Kontonamn\n             * 2: Name              ICA KONTO            KontoID\n             * 3: Disponibelt       00.000,00            Kontonummer\n             * 4: Saldo             1.655,71            Valuta\n             * 5:                                         Tillgängligt belopp\n             * 6:                                         Saldo\n             */\n//            Försök att lösa problemet med för långa, icke radbrytande kontonamn:\n//                if (matcher.group(1).length() > 24)  {\n//                    matcher.group(1).replaceFirst(\"(\", \"(\\n\");\n//                }\n\n            mIdMappings.put(Integer.toString(accId), matcher.group(2).trim());\n            accounts.add(new Account(\n                    Html.fromHtml(matcher.group(1)).toString().trim() + \" (Tillgängligt belopp)\",\n                    Helpers.parseBalance(matcher.group(5).trim()), Integer.toString(accId)));\n            Account account = new Account(\n                    Html.fromHtml(matcher.group(1)).toString().trim() + \" (Saldo)\",\n                    Helpers.parseBalance(matcher.group(6).trim()), \"a:\" + accId);\n            account.setAliasfor(matcher.group(1).trim());\n            accounts.add(account);\n\n            balance = balance.add(Helpers.parseBalance(matcher.group(5)));\n            accId++;\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        if (account.getId().startsWith(\"a:\") || !mIdMappings.containsKey(account.getId())) {\n            return; // No transactions for \"saldo\"-accounts\n        }\n        String accountId = mIdMappings.get(account.getId());\n        String response = null;\n        Matcher matcher;\n        response = urlopen\n                .open(\"https://online.akeliusinvest.com/AccountStatement.mws?selectedaccount=\"\n                        + accountId);\n        matcher = reTransactions.matcher(response);\n                /*                 ICA-banken    Akelius Invest\n         * Beskrivning    1            2\n         * Datum        2            1\n         * Belopp        3            3\n         */\n\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/AkeliusSpar.java",
    "content": "/* Copyright (C) 2012 Nullbyte <http://nullbyte.eu>, first version by Snah@Swedroid 2012-01-06\n * Modified for Akelius Spar by Per Wigren <per.wigren@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class AkeliusSpar extends Bank {\n\n    private static final String NAME = \"Akelius Spar\";\n\n    private static final String URL = \"https://www.online.akeliusspar.se/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.AKELIUSSPAR;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"YYYYMMDDNNNN\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    private Pattern reLogintoken = Pattern.compile(\"logintoken\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reError = Pattern.compile(\"<label\\\\s+class=\\\"error\\\">(.+?)</label>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<tr>\\\\s*<td[^>]*>([^<]+)</td>\\\\s*<td[^>]*><a[^?]+\\\\?selectedaccount=([^\\\"]+)\\\"[^>]*>([^<]+)</a></td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    //private Pattern reBalanceDisp = Pattern.compile(\"account\\\\.aspx\\\\?id=([^\\\"]+).+?>([^<]+)</a.+?Disponibelt([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n    //private Pattern reBalanceSald = Pattern.compile(\"account\\\\.aspx\\\\?id=([^\\\"]+).+?>([^<]+)</a[^D]*Saldo([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n    // private Pattern reBalance = Pattern.compile(\"AccountStatement\\\\.mws\\\\?selectedaccount=([^\\\"]+).+?>([^<]+)</a.+?Disponibelt([0-9 .,-]+)[^<]*<br/>.+?Saldo([0-9 .,-]+)\", Pattern.CASE_INSENSITIVE);\n    private Pattern reTransactions = Pattern\n            .compile(\"top\\\">([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n                    Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private HashMap<String, String> mIdMappings = new HashMap<String, String>();\n\n    public AkeliusSpar(Context context) {\n        super(context, R.drawable.logo_akeliusspar);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public AkeliusSpar(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_akeliusspar));\n        String response = urlopen.open(\"https://www.online.akeliusspar.se/login.mws\");\n        Matcher matcher = reLogintoken.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" logintoken.\");\n        }\n        String strLogintoken = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"action\", \"login\"));\n        postData.add(new BasicNameValuePair(\"logintoken\", strLogintoken));\n        postData.add(new BasicNameValuePair(\"df_username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"df_password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"Language\", \"SV\"));\n        postData.add(new BasicNameValuePair(\"IdleTime\", \"900\"));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.online.akeliusspar.se/login.mws\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n\n        LoginPackage lp = preLogin();\n        String response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        Matcher matcher = reError.matcher(response);\n        if (matcher.find()) {\n            String errormsg = Html.fromHtml(matcher.group(1).trim()).toString();\n            if (errormsg.contains(\"ord eller personnummer\") || errormsg.contains(\"et alternativ\")\n                    || errormsg.contains(\"fyra siffror\")) {\n                throw new LoginException(errormsg);\n            } else {\n                throw new BankException(errormsg);\n            }\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        String response = urlopen.open(\"https://www.online.akeliusspar.se/AccountPortfolio.mws\");\n        Matcher matcher = reAccounts.matcher(response);\n        int accId = 0;\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                ICA                    AKELIUSINVEST\n             * 1: ID                0000000000            Kontonamn\n             * 2: Name              ICA KONTO            KontoID\n             * 3: Disponibelt       00.000,00            Kontonummer\n             * 4: Saldo             1.655,71            Valuta\n             * 5:                                         Tillgängligt belopp\n             * 6:                                         Saldo\n             */\n//            Försök att lösa problemet med för långa, icke radbrytande kontonamn:\n//                if (matcher.group(1).length() > 24)  {\n//                    matcher.group(1).replaceFirst(\"(\", \"(\\n\");\n//                }\n\n            mIdMappings.put(Integer.toString(accId), matcher.group(2).trim());\n            accounts.add(new Account(\n                    Html.fromHtml(matcher.group(1)).toString().trim() + \" (Tillgängligt belopp)\",\n                    Helpers.parseBalance(matcher.group(5).trim()), Integer.toString(accId)));\n            Account account = new Account(\n                    Html.fromHtml(matcher.group(1)).toString().trim() + \" (Saldo)\",\n                    Helpers.parseBalance(matcher.group(6).trim()), \"a:\" + accId);\n            account.setAliasfor(matcher.group(1).trim());\n\n            accounts.add(account);\n            balance = balance.add(Helpers.parseBalance(matcher.group(5)));\n            accId++;\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        if (account.getId().startsWith(\"a:\") || !mIdMappings.containsKey(account.getId())) {\n            return; // No transactions for \"saldo\"-accounts\n        }\n        String accountId = mIdMappings.get(account.getId());\n        String response = null;\n        Matcher matcher;\n\n        response = urlopen\n                .open(\"https://www.online.akeliusspar.se/AccountStatement.mws?selectedaccount=\"\n                        + accountId);\n        matcher = reTransactions.matcher(response);\n                /*                 ICA-banken    Akelius Invest\n         * Beskrivning    1            2\n         * Datum        2            1\n         * Belopp        3            3\n         */\n\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/AppeakPoker.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n * Contributors: PMC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.NameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class AppeakPoker extends Bank {\n\n    private static final String NAME = \"Appeak Poker\";\n\n    private static final String URL = \"http://poker.appeak.se/\";\n\n    private static final int BANKTYPE_ID = Bank.APPEAKPOKER;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT;\n\n    private static final boolean INPUT_HIDDEN_PASSWORD = true;\n\n    private String mChips = null;\n\n    public AppeakPoker(Context context) {\n        super(context, R.drawable.logo_appeakpoker);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHiddenPassword = INPUT_HIDDEN_PASSWORD;\n        super.displayDecimals = false;\n        currency = \"chips\";\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public AppeakPoker(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context);\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        return new LoginPackage(urlopen, postData, \"\",\n                String.format(\"http://poker.appeak.se/playerInfo/?username=%s\", getUsername()));\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        String response = urlopen.open(lp.getLoginTarget());\n        Document d = Jsoup.parse(response);\n        Element e = d.select(\"#content > table tr:eq(2) td:eq(1)\").first();\n        if (e == null) {\n            throw new LoginException(res.getText(R.string.invalid_username).toString());\n        } else {\n            mChips = e.html();\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_card_number).toString());\n        }\n        login();\n        if (mChips != null) {\n            Account account = new Account(\"Chips\",\n                    Helpers.parseBalance(mChips.replaceAll(\"\\\\D\", \"\")), \"1\");\n            account.setCurrency(\"chips\");\n            balance = account.getBalance();\n            accounts.add(account);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/BetterGlobe.java",
    "content": "/* Copyright (C) 2012 Nullbyte <http://nullbyte.eu>\n * BetterGlobe support by Per Wigren <per.wigren@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class BetterGlobe extends Bank {\n\n    private static final String NAME = \"Better Globe\";\n\n    private static final String URL = \"http://betterglobe.com\";\n\n    private static final int BANKTYPE_ID = IBankTypes.BETTERGLOBE;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"AID code\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    private Pattern reBalance = Pattern.compile(\"Totalt på BG-kontot\\\\s*([^<]+)\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reForecast = Pattern.compile(\n            \"Din totala bruttovinst:.*?€([^<]+).*Köpekostnader:.*?€([^<]+).*Din totala nettovinst:.*?€([^<]+)\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reTrees = Pattern.compile(\"Totalt? antal ägda träd:</td>\\\\s*<td.*?>(\\\\d+)</td>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    public BetterGlobe(Context context) {\n        super(context, R.drawable.logo_betterglobe);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n        super.currency = \"EUR\";\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public BetterGlobe(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context);\n        urlopen.setAllowCircularRedirects(true);\n        HashMap<String, String> headers = urlopen.getHeaders();\n        headers.put(\"Referer\", \"http://betterglobe.com/login.aspx?lang=sv-SE\");\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"btnLogin\", \"\"));\n        return new LoginPackage(urlopen, postData, \"\",\n                \"http://betterglobe.com/Login.aspx?rememberMe=False\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        String response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher;\n        String response = urlopen.open(\"http://betterglobe.com/bgaccount.aspx/report\");\n        matcher = reBalance.matcher(response);\n\n        while (matcher.find()) {\n            Account tillgangligt = new Account(\"Tillgängligt\",\n                    Helpers.parseBalance(matcher.group(1)), \"tillgangligt\");\n            tillgangligt.setCurrency(\"EUR\");\n            accounts.add(tillgangligt);\n            balance = balance.add(Helpers.parseBalance(matcher.group(1)));\n        }\n\n        response = urlopen.open(\"http://betterglobe.com/mytrees.aspx/Valueforecast\");\n        matcher = reForecast.matcher(response);\n\n        while (matcher.find()) {\n            Account inkop = new Account(\"Inköp\", Helpers.parseBalance(matcher.group(2)), \"inkop\");\n            Account netto = new Account(\"Beräknad vinst\", Helpers.parseBalance(matcher.group(3)),\n                    \"netto\");\n            Account brutto = new Account(\"Beräknat slutvärde\",\n                    Helpers.parseBalance(matcher.group(1)), \"brutto\");\n            inkop.setCurrency(\"EUR\");\n            brutto.setCurrency(\"EUR\");\n            netto.setCurrency(\"EUR\");\n            accounts.add(inkop);\n            accounts.add(brutto);\n            accounts.add(netto);\n            balance = balance.add(Helpers.parseBalance(matcher.group(2)));\n        }\n\n        response = urlopen.open(\"http://betterglobe.com/mytrees.aspx\");\n        matcher = reTrees.matcher(response);\n\n        while (matcher.find()) {\n            Account trees = new Account(\"Innehav\", Helpers.parseBalance(matcher.group(1)), \"trees\");\n            trees.setCurrency(\"träd\");\n            accounts.add(trees);\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Bioklubben.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Bioklubben extends Bank {\n\n    private static final String NAME = \"Bioklubben\";\n\n    private static final String URL = \"https://bioklubben.sf.se/Start.aspx\";\n\n    private static final int BANKTYPE_ID = Bank.BIOKLUBBEN;\n\n    private static final boolean DISPLAY_DECIMALS = false;\n\n    private String response = null;\n\n    public Bioklubben(Context context) {\n        super(context, R.drawable.logo_bioklubben);\n        super.url = URL;\n        super.displayDecimals = DISPLAY_DECIMALS;\n        super.inputTypeUsername = InputType.TYPE_CLASS_TEXT\n                | +InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n        super.inputHintUsername = context.getString(R.string.email);\n        currency = context.getString(R.string.points);\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Bioklubben(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_bioklubben));\n        urlopen.setAllowCircularRedirects(true);\n        response = urlopen.open(URL);\n\n        Document d = Jsoup.parse(response);\n        Element e = d.getElementById(\"__VIEWSTATE\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String viewState = e.attr(\"value\");\n\n        e = d.getElementById(\"__EVENTVALIDATION\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String eventValidation = e.attr(\"value\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\",\n                \"ctl00$ContentPlaceHolder1$LoginUserControl$LogonButton\"));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewState));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventValidation));\n        postData.add(new BasicNameValuePair(\"ctl00_toolkitscriptmanager_HiddenField\", \"\"));\n        postData.add(new BasicNameValuePair(\"ctl00$toolkitscriptmanager\",\n                \"ctl00$UpdatePanel|ctl00$ContentPlaceHolder1$LoginUserControl$LogonButton\"));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$ContentPlaceHolder1$LoginUserControl$LoginNameTextBox\", getUsername()));\n        postData.add(\n                new BasicNameValuePair(\"ctl00$ContentPlaceHolder1$LoginUserControl$PasswordTextBox\",\n                        getPassword()));\n        return new LoginPackage(urlopen, postData, response, URL);\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Felaktigt anv\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        Document d = Jsoup.parse(urlopen.open(\n                \"https://bioklubben.sf.se/MyPurchases.aspx?ParentTreeID=1&TreeID=1\"));\n        Element e = d.getElementById(\"ctl00_ContentPlaceHolder1_BonusPointsLabel\");\n        if (e == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" points element.\");\n        }\n        BigDecimal b = Helpers.parseBalance(e.text());\n        Account a = new Account(\"Poäng\", b, \"1\");\n        a.setCurrency(context.getString(R.string.points));\n        accounts.add(a);\n        balance = balance.add(a.getBalance());\n\n        Elements es = d.select(\".GridViewStd_Item,.GridViewStd_ItemAlt\");\n        List<Transaction> transactions = new ArrayList<Transaction>();\n        if (es != null) {\n            for (Element el : es) {\n                transactions.add(\n                        new Transaction(el.child(0).text().trim(), el.child(1).text().trim(),\n                                Helpers.parseBalance(el.child(2).text())));\n            }\n        }\n        a.setTransactions(transactions);\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/BlekingeTrafiken.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.util.EntityUtils;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class BlekingeTrafiken extends Bank {\n\n    private static final String NAME = \"Blekingetrafiken\";\n\n    private static final String URL = \"https://www.blekingetrafiken.se\";\n\n    private static final int BANKTYPE_ID = IBankTypes.BLEKINGETRAFIKEN;\n\n    private String response = null;\n\n    public BlekingeTrafiken(Context context) {\n        super(context, R.drawable.logo_blekingetrafiken);\n        super.url = URL;\n        super.inputTypeUsername = InputType.TYPE_CLASS_PHONE;\n        super.inputHintUsername = \"XXXXXXXXXX\";\n        super.inputTitletextUsername = R.string.card_number;\n        super.inputHiddenPassword = true;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public BlekingeTrafiken(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException,\n            IOException {\n        urlopen = new Urllib(context);\n        LoginPackage lp = new LoginPackage(urlopen, null, null, URL);\n        lp.setIsLoggedIn(true); //Well we don't support logging in ATM.\n        return lp;\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        urlopen.addHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n        urlopen.addHeader(\"Accept\", \"application/json\");\n        HttpResponse httpResponse = urlopen.openAsHttpResponse(URL + \"/webshop/card/balance/\",\n                new StringEntity(\"{\\\"cardnr\\\":\\\"\" + getUsername() + \"\\\"}\"), true);\n        if (httpResponse.getStatusLine().getStatusCode() != 200) {\n            throw new BankException(res.getText(R.string.invalid_card_number).toString());\n        }\n        response = EntityUtils.toString(httpResponse.getEntity());\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        try {\n            JSONObject accountJSONObject = new JSONObject(response).optJSONObject(\"Card\");\n            accountJSONObject = accountJSONObject.optJSONObject(\"Value\");\n\n            Account a = new Account(accountJSONObject.getString(\"Description\"),\n                    Helpers.parseBalance(accountJSONObject.getString(\"Remaining\")),\n                    \"0\");\n            accounts.add(a);\n            balance = balance.add(a.getBalance());\n\n            accountJSONObject = accountJSONObject.optJSONObject(\"Autoload\");\n            if (accountJSONObject != null) {\n                a = new Account(\" - Kommande -\",\n                        Helpers.parseBalance(accountJSONObject.getString(\"Value\")),\n                        \"1\");\n                accounts.add(a);\n                balance = balance.add(a.getBalance());\n            }\n\n        } catch (JSONException e) {\n            throw new BankException(e.getMessage(), e);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Bredband2VoIP.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\npublic class Bredband2VoIP extends Bank {\n\n    private static final String API_URL = \"https://portal.bredband2.com/\";\n\n    //<a href=\"/services/digisipbalance/iServiceID/~ID~/\" class=\"digisipBalance\" target=\"_blank\">Saldo</a>\n    private Pattern reSaldoUrl = Pattern.compile(\n            \"<a href=\\\"/services/digisipbalance/iServiceID/(\\\\d+)/\\\" class=\\\"digisipBalance\\\" target=\\\"_blank\\\">Saldo</a>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reSaldo = Pattern.compile(\"<td class=\\\"white\\\">\\\\s+(\\\\d+.\\\\d{2}) kr\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reInvoiceUrl = Pattern.compile(\"<a href=\\\"([^\\\"]+)\\\" class=\\\"invoice\\\"\");\n\n    private Pattern reTransactions = Pattern.compile(\n            \"^      ([\\\\d-]+)\\\\s+([\\\\S]+)\\\\s+([\\\\S]+)\\\\s+([\\\\d:]+)\\\\s+([\\\\d\\\\.]+)\", Pattern.MULTILINE);\n\n    private String response = null;\n\n    public Bredband2VoIP(Context context) {\n        super(context, R.drawable.logo_bredband2voip);\n        super.inputTypeUsername = InputType.TYPE_CLASS_PHONE;\n        super.inputHintUsername = \"19XXXXXX-XXXX\";\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return IBankTypes.BREDBAND2VOIP;\n    }\n\n    @Override\n    public String getName() {\n        return \"Bredband2 VoIP\";\n    }\n\n    public Bredband2VoIP(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_bredband2));\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"cUsername\", getUsername()));\n        postData.add(new BasicNameValuePair(\"cPassword\", getPassword()));\n        postData.add(new BasicNameValuePair(\"bIsCompany\", \"0\"));\n        postData.add(new BasicNameValuePair(\"submit\", \"Logga in\"));\n        response = urlopen.open(API_URL + \"index/\", postData, true);\n        LoginPackage lp = new LoginPackage(urlopen, postData, response, API_URL + \"start\");\n        if (response.contains(\"Logga ut\")) {\n            lp.setIsLoggedIn(true);\n        }\n        return lp;\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        if (!lp.isLoggedIn()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        response = urlopen.open(API_URL + \"services/\");\n        Matcher mSaldoUrl = reSaldoUrl.matcher(response);\n        while (mSaldoUrl.find()) {\n            String account = mSaldoUrl.group(1);\n            String r = urlopen.open(\n                    API_URL + \"/services/digisipbalance/iServiceID/\" + account + \"/\");\n            Matcher mSaldo = reSaldo.matcher(r);\n            if (mSaldo.find()) {\n                accounts.add(new Account(account,\n                        Helpers.parseBalance(mSaldo.group(1)),\n                        account));\n            }\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        //<a href=\"/services/invoicelist/iServiceID/~ID~/\">Samtal</a>\n        response = urlopen.open(API_URL + \"services/invoicelist/iServiceID/\" + account.getId());\n        Matcher mInvoiceUrl = reInvoiceUrl.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        int i = 1;\n        while (mInvoiceUrl.find() && (i++ <= 4 || transactions.size() <= 30)) {\n            try {\n                String url = mInvoiceUrl.group(1);\n                String sInvoice = urlopen.open(API_URL + url);\n                Matcher mTransaction = reTransactions.matcher(sInvoice);\n                while (mTransaction.find()) {\n                    transactions.add(new Transaction(mTransaction.group(2),\n                            mTransaction.group(1) + \"  —  \" + mTransaction.group(4),\n                            Helpers.parseBalance(mTransaction.group(5)).negate()));\n                }\n            } catch (Exception e) {\n                Timber.w(e, \"Unable to parse: %s\", mInvoiceUrl.group(1));\n            }\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/BrummerKF.java",
    "content": "/* Copyright (C) 2012 Nullbyte <http://nullbyte.eu>\n * Brummer Privat Kapitalförsäkring & Pension support by Per Wigren <per.wigren@gmail.com>\n * Probably does not work with depå/ISK or company accounts as they have separate login pages.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class BrummerKF extends Bank {\n\n    private static final String NAME = \"Brummer KF & Pension\";\n\n    private static final String URL = \"https://www.brummer.se/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.BRUMMER_KF;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"YYYYMMDDNNNN\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    String response;\n\n    private Pattern reError = Pattern\n            .compile(\"<li>(Personnummer och l.*?senord matchar ej\\\\.)</li>\",\n                    Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reViewstate = Pattern.compile(\"\\\"__VIEWSTATE\\\"\\\\s+value=\\\"(.*?)\\\"\",\n            Pattern.DOTALL);\n\n    private Pattern reEventValidation = Pattern.compile(\n            \"\\\"__EVENTVALIDATION\\\"\\\\s+value=\\\"(.*?)\\\"\", Pattern.DOTALL);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<td.*?>\\\\s*<a.*?>\\\\s*(.*?)&nbsp;(.*?)\\\\s*</a>\\\\s*</td>\\\\s*<td.*?>\\\\s*(.*?)\\\\s*</td>\\\\s*<td.*?>\\\\s*(.*?)\\\\s*</td>\\\\s*<td.*?>\\\\s*(.*?)\\\\s*</td>\\\\s*<td.*?>\\\\s*(.*?)\\\\s*</td>\\\\s*<td.*?>\\\\s*<a.*?>\\\\s*Avtalsinformation\\\\s*</a>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    public BrummerKF(Context context) {\n        super(context, R.drawable.logo_brummer_kf);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public BrummerKF(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_brummer));\n        urlopen.setAllowCircularRedirects(true);\n        response = urlopen.open(\"https://www.brummer.se/sv/online/privat/Login/\");\n\n        Matcher mViewstate = reViewstate.matcher(response);\n        if (!mViewstate.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" Viewstate.\");\n        }\n        String viewstate = mViewstate.group(1);\n\n        Matcher mEventValidation = reEventValidation.matcher(response);\n        if (!mEventValidation.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String eventvalidation = mEventValidation.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewstate));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventvalidation));\n        postData.add(new BasicNameValuePair(\"ctl00$cphMainRegion$txtUsername\", getUsername()));\n        postData.add(new BasicNameValuePair(\"ctl00$cphMainRegion$txtPassword\", getPassword()));\n        postData.add(new BasicNameValuePair(\"ctl00$cphMainRegion$btnLogin\", \"Logga in\"));\n        postData.add(new BasicNameValuePair(\"ctl00$ctl08\", \"sv\"));\n        postData.add(\n                new BasicNameValuePair(\"ctl00$ucHeader$ctl01$loginView$ctl01$ddlQuickMenu\", \"-1\"));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.brummer.se/sv/online/privat/Login/\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        String response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n\n        Matcher matcher = reError.matcher(response);\n        if (matcher.find()) {\n            String errormsg = Html.fromHtml(matcher.group(1).trim()).toString();\n            if (errormsg.contains(\"Personnummer\")) {\n                throw new LoginException(errormsg);\n            } else {\n                throw new BankException(errormsg);\n            }\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher;\n\n        response = urlopen.open(\"https://www.brummer.se/sv/online/privat/\");\n        matcher = reAccounts.matcher(response);\n\n        while (matcher.find()) {\n            /*\n             * 1: Kontonamn\n             * 2: Kontonummer\n             * 3: Avkastning under året\n             * 4: Genomsnittlig årlig avkastning sedan start\n             * 5: Avkastning sedan start\n             * 6: Marknadsvärde (kronor)\n             */\n\n            accounts.add(new Account(Html.fromHtml(matcher.group(1)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(6).trim()), matcher.group(2)));\n\n            balance = balance.add(Helpers.parseBalance(matcher.group(6)));\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/CSN.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.protocol.HTTP;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class CSN extends Bank {\n\n    private static final String NAME = \"CSN\";\n\n    private static final String URL = \"https://www.csn.se/bas/inloggning/pinkod.do\";\n\n    private static final int BANKTYPE_ID = IBankTypes.CSN;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    private Pattern reLoginError = Pattern.compile(\"<h3>Observera</h3>\\\\s*<ul>\\\\s*<li>([^<]+)</li>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reBalance = Pattern.compile(\n            \"aktuellStudieskuld\\\\.do\\\\?metod=init&(?:amp;)?SpecNr=(\\\\d{1,})\\\">([^<]+)</a>\\\\s*</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<td>\\\\s*(\\\\d{4}-\\\\d{2}-\\\\d{2})\\\\s*</td>\\\\s*<td>([^<]+)</td>\\\\s*<td>([^<]+)</td>.*?startHideInfoBoxTimer\\\\(\\\\d{1,}\\\\);\\\">([^<]+)</\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reCompletedPayments = Pattern.compile(\n            \"<td>\\\\s*(\\\\d{4}-\\\\d{2}-\\\\d{2})\\\\s*</td>\\\\s*<td>([^<]+)</td>.*?startHideInfoBoxTimer\\\\(\\\\d{1,}\\\\);\\\"[^>]+>([^<]+)</\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private String response = null;\n\n    public CSN(Context context) {\n        super(context, R.drawable.logo_csn);\n        super.url = URL;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public CSN(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_csn));\n        urlopen.setAllowCircularRedirects(true);\n        urlopen.setContentCharset(HTTP.ISO_8859_1);\n        urlopen.addHeader(\"Referer\", \"https://www.csn.se/bas/\");\n        response = urlopen.open(\"https://www.csn.se/bas/inloggning/pinkod.do\");\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"javascript\", \"on\"));\n\n        response = urlopen.open(\"https://www.csn.se/bas/javascript\", postData);\n\n        postData.clear();\n\n        postData.add(new BasicNameValuePair(\"metod\", \"validerapinkod\"));\n        postData.add(new BasicNameValuePair(\"pnr\", getUsername()));\n        postData.add(new BasicNameValuePair(\"pinkod\", getPassword()));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.csn.se/bas/inloggning/Pinkod.do\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        Matcher matcher = reLoginError.matcher(response);\n        if (matcher.find()) {\n            throw new LoginException(Html.fromHtml(matcher.group(1)).toString().trim());\n        }\n        if (!response.contains(\"Inloggad&nbsp;som\")) {\n            throw new BankException(res.getText(R.string.unable_to_login).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        response = urlopen.open(\n                \"https://www.csn.se/aterbetalning/hurStorArMinSkuld/aktuellStudieskuld.do?javascript=off\");\n        Matcher matcher;\n        matcher = reBalance.matcher(response);\n        int i = 0;\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: ID                0\n             * 2: Name              Lån efter 30 juni 2001 (annuitetslån)\n             * 3: Amount            123,456\n             *\n             */\n            BigDecimal amount = Helpers.parseBalance(matcher.group(3).replace(\",\", \"\")).negate();\n            Account account = new Account(\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    amount,\n                    matcher.group(1).trim(),\n                    Account.LOANS);\n            if (i > 0) {\n                account.setAliasfor(\"0\");\n            }\n            accounts.add(account);\n            balance = balance.add(amount);\n            i++;\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        if (account.getAliasfor() == null || account.getAliasfor().length() == 0) {\n            return;\n        }\n\n        Matcher matcher;\n        response = urlopen.open(\n                \"https://www.csn.se/studiemedel/utbetalningar/utbetalningar.do?javascript=off\");\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                        EXAMPLE DATA\n             * 1: Date                      2010-11-25\n             * 2: Specification             Vecka 47-50\n             * 3: Status                    Utbetald\n             * 4: Amount                    8,140\n             *\n             */\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim() + \" (\" + Html\n                            .fromHtml(matcher.group(3)).toString().trim() + \")\",\n                    Helpers.parseBalance(matcher.group(4).replace(\",\", \"\"))));\n        }\n        response = urlopen.open(\n                \"https://www.csn.se/aterbetalning/vadSkallJagBetalUnderAret/betalningstillfallen.do?javascript=off\");\n        matcher = reTransactions.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                        EXAMPLE DATA\n             * 1: Date                      2010-11-25\n             * 2: Specification             Bankgiro 5580-3084\n             * 3: OCR-number                4576225900\n             * 4: Amount                    1,234\n             *\n             */\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim() + \" (\" + Html\n                            .fromHtml(matcher.group(3)).toString().trim() + \")\",\n                    Helpers.parseBalance(matcher.group(4).replace(\",\", \"\")).negate()));\n        }\n\n        response = urlopen.open(\n                \"https://www.csn.se/aterbetalning/harMinaInbetalningarKommitIn/registreradeInbetalningar.do?javascript=off\");\n        matcher = reCompletedPayments.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                        EXAMPLE DATA\n             * 1: Date                      2006-08-21\n             * 2: Specification             Återkrav första halvåret 2006 lån 1\n             * 3: Amount                    1,050\n             *\n             */\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3).replace(\",\", \"\")).negate()));\n        }\n\n        Collections.sort(transactions, Collections.reverseOrder());\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Chalmrest.java",
    "content": "package com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Chalmrest extends Bank {\n\n    private static final String NAME = \"Chalmrest\";\n\n    private static final int BANKTYPE_ID = IBankTypes.CHALMREST;\n\n    private Pattern reViewState = Pattern.compile(\"__VIEWSTATE\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n    private Pattern reEventValidation = Pattern.compile(\"__EVENTVALIDATION\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reAccount = Pattern\n            .compile(\"<span id=\\\"txtPTMCardName\\\">(.*?)</span>\",\n                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);\n\n    private Pattern reBalance = Pattern.compile(\n            \"<span id=\\\"txtPTMCardValue\\\">(.*?)</span>\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);\n\n    private String response = null;\n\n    public Chalmrest(Context context) {\n        super(context, R.drawable.logo_chalmrest);\n        super.inputTitletextUsername = R.string.card_number;\n        super.inputHintUsername = \"XXXXXXXXXXXXXXXX\";\n        super.inputTypeUsername = InputType.TYPE_CLASS_NUMBER;\n        super.inputHiddenPassword = true;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Chalmrest(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context);\n        response = urlopen.open(\"http://kortladdning3.chalmerskonferens.se/Default.aspx\");\n\n        Matcher matcherView = reViewState.matcher(response);\n        if (!matcherView.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String strViewState = matcherView.group(1);\n\n        Matcher matcherEvent = reEventValidation.matcher(response);\n        if (!matcherEvent.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String strEvent = matcherEvent.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", strViewState));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", strEvent));\n        postData.add(new BasicNameValuePair(\"txtCardNumber\", getUsername()));\n        postData.add(new BasicNameValuePair(\"btnNext\", \"Nästa\"));\n        postData.add(new BasicNameValuePair(\"hiddenIsMobile\", \"desktop\"));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"http://kortladdning3.chalmerskonferens.se/Default.aspx\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (!response.contains(\"Logga ut\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        response = urlopen.open(\"http://kortladdning3.chalmerskonferens.se/CardLoad_Order.aspx\");\n        Matcher accountMatcher;\n        Matcher balanceMatcher;\n\n        accountMatcher = reAccount.matcher(response);\n        if (accountMatcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Name              Kalle Karlsson\n             */\n\n            balanceMatcher = reBalance.matcher(response);\n            if (balanceMatcher.find()) {\n                /*\n                 * Capture groups:\n                 * GROUP                EXAMPLE DATA\n                 * 1: Balance              118 kr\n                 */\n\n                String balanceString = balanceMatcher.group(1).replaceAll(\"\\\\<a[^>]*>\", \"\")\n                        .replaceAll(\"\\\\<[^>]*>\", \"\").trim();\n\n                accounts.add(new Account(Html.fromHtml(accountMatcher.group(1)).toString().trim(),\n                        Helpers.parseBalance(balanceString), accountMatcher.group(1)));\n                balance = balance.add(Helpers.parseBalance(balanceString));\n            }\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/DanskeBank.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.protocol.HTTP;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class DanskeBank extends Bank {\n\n    private static final String NAME = \"DanskeBank\";\n\n    private static final String URL\n            = \"https://mobil.danskebank.se/XI?WP=XAI&WO=Logon&WA=MBSELogon&gsSprog=SE&gsBrand=OEB\";\n\n    private static final int BANKTYPE_ID = IBankTypes.DANSKEBANK;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private Pattern reSessionId = Pattern.compile(\"WSES=([^\\\"& ]+)\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern rePersonnr = Pattern.compile(\"WAFT=([^\\\"& ]+)\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<a\\\\shref=\\\"[^\\\"]+KBList[^\\\"]+WCI=([^\\\"]+)\\\">([^<]+)</a><br/>([^<]+)<br/>Saldo:([^<]+)<br/>Disponibelt:([^<]+)<\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<a\\\\shref=\\\"[^\\\"]+KBDetVis[^\\\"]+\\\">([^<]+)</a><br/>Datum:([^<]+)<br/>Belopp:([^<]+)<br/>Status:([^<]+)<\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    private String mSessionId = null;\n\n    private String mPersonnr = null;\n\n    public DanskeBank(Context context) {\n        super(context, R.drawable.logo_danskebank);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public DanskeBank(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_danskebank));\n        urlopen.setContentCharset(HTTP.ISO_8859_1);\n        urlopen.addHeader(\"Referer\", \"https://mobil.danskebank.se/\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        SimpleDateFormat sdf = new SimpleDateFormat(\"HH:mm - dd.MM.yyyy\");\n        postData.add(new BasicNameValuePair(\"gsSprog\", \"SE\"));\n        postData.add(new BasicNameValuePair(\"gsBrand\", \"OEB\"));\n        postData.add(new BasicNameValuePair(\"gsSession\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsProdukt\", \"XAS\"));\n        postData.add(new BasicNameValuePair(\"gsNextObj\", \"Forside\"));\n        postData.add(new BasicNameValuePair(\"gsNextAkt\", \"MBForside\"));\n        postData.add(new BasicNameValuePair(\"gsNextUObj\", \"SC\"));\n        postData.add(new BasicNameValuePair(\"gsCurItem\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsCurItem2\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsCurItem3\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsCurItem4\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsCurItem5\", \"\"));\n        postData.add(new BasicNameValuePair(\"gsCurObj\", \"Logon\"));\n        postData.add(new BasicNameValuePair(\"gsCurAkt\", \"MBSELogon\"));\n        postData.add(new BasicNameValuePair(\"gsCurUObj\", \"SC\"));\n        postData.add(new BasicNameValuePair(\"hidStatusType\", \"A00\"));\n        postData.add(new BasicNameValuePair(\"hidStatusTekst\", \"\"));\n        postData.add(new BasicNameValuePair(\"hidStatusTid\", sdf.format(new Date())));\n        postData.add(new BasicNameValuePair(\"gsSikSystem\", \"KO\"));\n        postData.add(new BasicNameValuePair(\"gsLand\", \"SE\"));\n        postData.add(new BasicNameValuePair(\"gsAftlnr\", getUsername()));\n        postData.add(new BasicNameValuePair(\"gsLogon\", getPassword()));\n\n        return new LoginPackage(urlopen, postData, response, \"https://mobil.danskebank.se/XI\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"et personnummer eller servicekod du angett\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher;\n        matcher = reSessionId.matcher(response);\n        if (matcher.find()) {\n            mSessionId = matcher.group(1);\n        } else {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" session id.\");\n        }\n        matcher = rePersonnr.matcher(response);\n        if (matcher.find()) {\n            mPersonnr = matcher.group(1);\n        } else {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" personnummer.\");\n        }\n\n        response = urlopen.open(String.format(\n                \"https://mobil.danskebank.se/XI?WP=XAS&WO=Konto&WA=KTList&WSES=%s&WAFT=%s\",\n                mSessionId, mPersonnr));\n        matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: Internal acc number?  0123456789\n             * 2: Account name          Danske Direkt Bas\n             * 3: Account number        01234567890\n             * 4: Balance               1.124,56\n             * 5: Balance (disp.)       1.124,56\n             *\n             */\n            String name = Html.fromHtml(matcher.group(2)).toString().trim();\n            Account account = new Account(name, Helpers.parseBalance(matcher.group(5)),\n                    matcher.group(1).trim());\n            if (name.contains(\"lån\") || name.contains(\"Lån\")) {\n                account.setType(Account.LOANS);\n            } else {\n                balance = balance.add(Helpers.parseBalance(matcher.group(5)));\n            }\n            accounts.add(account);\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        //No transaction history for loans, funds and credit cards.\n        int accType = account.getType();\n        if (accType == Account.LOANS || accType == Account.FUNDS || accType == Account.CCARD) {\n            return;\n        }\n\n        response = urlopen.open(String.format(\n                \"https://mobil.danskebank.se/XI?WP=XAS&WAFT=%s&WSES=%s&WO=Konto&WA=KBList&WCI=%s\",\n                mPersonnr, mSessionId, account.getId()));\n        Matcher matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: Transaction           Till Fondsparande\n             * 2: Date                  2011-07-28\n             * 3: Amount                ?\n             * 4: Status                Väntar | Utförd\n             *\n             */\n            transactions.add(new Transaction(Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Html.fromHtml(matcher.group(1)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Everydaycard.java",
    "content": "/*\n * Copyright (C) 2011 Nullbyte <http://nullbyte.eu>\n * Copyright (C) 2011, 2012 Andreas Gunnerås\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Everydaycard extends Bank {\n\n    private static final String NAME = \"Everydaycard\";\n\n    private static final String URL = \"http://www.everydaycard.se/mobil/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.EVERYDAYCARD;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private Pattern reSaldo = Pattern.compile(\n            \"Utnyttjad kredit \\\\(sek\\\\)</td>\\\\s*<td></td>\\\\s*<td>([^<]+)<\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reBonus = Pattern.compile(\n            \"Aktuell bonus \\\\(sek\\\\)</td>\\\\s*<td>.*</td>\\\\s*<td>([^<]+)<\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    public Everydaycard(Context context) {\n        super(context, R.drawable.logo_everydaycard);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Everydaycard(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        return preLoginInternal(\"http://valuta.g2solutions.se/mobil/web/logonSubmit.do\");\n    }\n\n    private LoginPackage preLoginInternal(String url) throws BankException, IOException {\n        urlopen = new Urllib(context);\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"nextPage\", \"firstPage\"));\n        postData.add(new BasicNameValuePair(\"username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n        return new LoginPackage(urlopen, postData, response, url);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Felaktigt Login\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        Matcher matcher = reBonus.matcher(response);\n        if (matcher.find()) {\n            BigDecimal bonusBalance = Helpers.parseBalance(matcher.group(1));\n            Account account = new Account(\"Bonus\", bonusBalance, \"Bonus\", Account.OTHER);\n            balance = balance.add(bonusBalance);\n            accounts.add(account);\n        }\n\n        matcher = reSaldo.matcher(response);\n        if (matcher.find()) {\n            BigDecimal accountBalance = Helpers.parseBalance(matcher.group(1)).negate();\n            Account account = new Account(\"Everydaycard\", accountBalance, \"1\", Account.CCARD);\n            balance = balance.add(accountBalance);\n            accounts.add(account);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/FirstCard.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class FirstCard extends Bank {\n\n    private static final String NAME = \"First Card\";\n\n    private static final String URL = \"https://www.firstcard.se/login.jsp\";\n\n    private static final int BANKTYPE_ID = IBankTypes.FIRSTCARD;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private Pattern reAccounts = Pattern.compile(\n            \"translist\\\\.jsp\\\\?p=a&(?:amp;)?cardID=([^\\\"]+)\\\">([^<]+)</a>\\\\s*</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"pagecolumns\\\">(\\\\d{6})</td>\\\\s*<td>\\\\s*</td>\\\\s*<td>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)</td>\\\\s*<td[^>]+>([^<]+)<\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    public FirstCard(Context context) {\n        super(context, R.drawable.logo_firstcard);\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public FirstCard(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_firstcard));\n        response = urlopen.open(\"https://www.firstcard.se/login.jsp\");\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"op\", \"login\"));\n        postData.add(new BasicNameValuePair(\"errorpage\", \"login.jsp\"));\n        postData.add(new BasicNameValuePair(\"pnr\", getUsername()));\n        postData.add(new BasicNameValuePair(\"intpwd\", getPassword()));\n        return new LoginPackage(urlopen, postData, null, \"https://www.firstcard.se/login.jsp\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Logga in med din kod\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        response = urlopen.open(\"https://www.firstcard.se/mkol/index.jsp\");\n        Matcher matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: id                kdKPq4ghlcy9wpXymSzzS46wWQcS_0OT\n             * 2: account number    1111 3333 7777 9999\n             * 3: amount            9 824,08\n             *\n             */\n            accounts.add(new Account(Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3)), matcher.group(1).trim()));\n            balance = balance.add(Helpers.parseBalance(matcher.group(3)));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        response = urlopen.open(\n                \"https://www.firstcard.se/mkol/translist.jsp?p=a&cardID=\" + account.getId());\n        Matcher matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                        EXAMPLE DATA\n             * 1: date                      101006\n             * 2: specification             GOOGLE *RealArcade\n             * 3: currency                  USD\n             * 4: amount                    3,49\n             * 5: amount in local currency  24,08\n             *\n             */\n            String strDate = Html.fromHtml(matcher.group(1)).toString().trim();\n            strDate = \"20\" + strDate.charAt(0) + strDate.charAt(1) + \"-\" + strDate.charAt(2)\n                    + strDate.charAt(3) + \"-\" + strDate.charAt(4) + strDate.charAt(5);\n            transactions.add(new Transaction(strDate,\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(5)).negate()));\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Hemkop.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n * Contributors: firetech\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\nimport android.text.TextUtils;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Hemkop extends Bank {\n\n    private static final String NAME = \"Hemköp Kundkort\";\n\n    private static final String URL = \"https://www.hemkop.se/Mina-sidor/Logga-in/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.HEMKOP;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅÅÅMMDDXXXX\";\n\n    private String response = null;\n\n    public Hemkop(Context context) {\n        super(context, R.drawable.logo_hemkop);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Hemkop(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_hemkop));\n        urlopen.setAllowCircularRedirects(true);\n        response = urlopen.open(\"https://www.hemkop.se/Mina-sidor/Logga-in/\");\n\n        Document d = Jsoup.parse(response);\n        Element e = d.getElementById(\"__VIEWSTATE\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String viewState = e.attr(\"value\");\n\n        e = d.getElementById(\"__EVENTVALIDATION\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String eventValidation = e.attr(\"value\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\", \"ctl00$MainContent$BtnLogin\"));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewState));\n        postData.add(new BasicNameValuePair(\"__SCROLLPOSITIONX\", \"0\"));\n        postData.add(new BasicNameValuePair(\"__SCROLLPOSITIONY\", \"266\"));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventValidation));\n        postData.add(new BasicNameValuePair(\"ctl00$uiTopMenu$Search\", \"\"));\n        postData.add(new BasicNameValuePair(\"ctl00$MainContent$tbUsername\", getUsername()));\n        postData.add(new BasicNameValuePair(\"ctl00$MainContent$tbPassword\", getPassword()));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.hemkop.se/Mina-sidor/Logga-in/\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (!response.contains(\"Inloggad som\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        response = urlopen.open(\"https://www.hemkop.se/Mina-sidor/Bonussaldo/\");\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        Document d = Jsoup.parse(response);\n        Elements amounts = d.select(\".bonusStatement .amount\");\n        Elements names = d.select(\".bonusStatement .label\");\n        for (int i = 0; i < Math.min(amounts.size(), names.size()); i++) {\n            Element amount = amounts.get(i);\n            Element name = names.get(i);\n            BigDecimal accountBalance = Helpers.parseBalance(amount.ownText());\n            Account account = new Account(name.ownText().replace(\":\", \"\").trim(), accountBalance,\n                    String.format(\"acc_%d\", i));\n            if (i > 0) {\n                account.setAliasfor(\"acc_0\");\n            }\n            accounts.add(account);\n            balance = balance.add(accountBalance);\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n\n        Account account = accounts.get(0);\n\n        response = urlopen.open(\"https://www.hemkop.se/Mina-sidor/Kontoutdrag/\");\n        d = Jsoup.parse(response);\n        Elements es = d.select(\".transactions tbody tr\");\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        for (Element e : es) {\n            Transaction t = new Transaction(e.child(1).ownText().trim(),\n                    e.child(0).ownText().trim(),\n                    Helpers.parseBalance(e.child(3).ownText()));\n            if (!TextUtils.isEmpty(e.child(2).ownText())) {\n                t.setCurrency(Helpers.parseCurrency(e.child(2).ownText().trim(), \"SEK\"));\n            }\n            transactions.add(t);\n        }\n        account.setTransactions(transactions);\n\n        es = d.select(\".currentBalance,.disposable\");\n        int i = 0;\n        for (Element e : es) {\n            Account a = new Account(e.child(0).ownText().trim(),\n                    Helpers.parseBalance(e.child(1).ownText()), String.format(\"acc_cc_%d\", i));\n            a.setAliasfor(\"acc_0\");\n            accounts.add(a);\n            i++;\n        }\n\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        /*\n        if (!\"acc_0\".equals(account.getId())) return;\n        try {\n            response = urlopen.open(\"https://www.hemkop.se/Mina-sidor/Kontoutdrag/\");\n            Document d = Jsoup.parse(response);\n            Elements es = d.select(\".transactions tbody tr\");\n            ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n            for (Element e : es) {\n                Transaction t = new Transaction(e.child(1).ownText().trim(),\n                                    e.child(0).ownText().trim(),\n                        Helpers.parseBalance(e.child(3).ownText()));\n                if (!TextUtils.isEmpty(e.child(2).ownText())) {\n                    t.setCurrency(Helpers.parseCurrency(e.child(2).ownText().trim(), \"SEK\"));\n                }\n                transactions.add(t);\n            }\n            account.setTransactions(transactions);\n        } catch (ClientProtocolException e) {\n            e.printStackTrace();\n            Log.e(TAG, e.getMessage() != null ? e.getMessage() : \"\");\n        } catch (IOException e) {\n            e.printStackTrace();\n            Log.e(TAG,  e.getMessage() != null ? e.getMessage() : \"\");\n        }\n        finally {\n            super.updateComplete();\n        }\n        */\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Hors.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Hors extends Bank {\n\n    private static final String NAME = \"Hörs\";\n\n    private static final String URL = \"http://www.dittkort.se/hors/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.HORS;\n\n    private static final boolean DISPLAY_DECIMALS = false;\n\n    private String response = null;\n\n    public Hors(Context context) {\n        super(context, R.drawable.logo_hors);\n\n        super.url = URL;\n        super.displayDecimals = DISPLAY_DECIMALS;\n        super.inputTypeUsername = InputType.TYPE_CLASS_TEXT\n                | +InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n        super.inputHintUsername = context.getString(R.string.card_id);\n        super.inputHiddenPassword = true;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Hors(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context);\n        urlopen.setAllowCircularRedirects(true);\n        response = urlopen.open(\"https://www.dittkort.se//q/?p=7EB4F129-0A41-417F-8FEA-51B2B75B9D24\");\n\n        Document d = Jsoup.parse(response);\n        Element e = d.getElementById(\"__VIEWSTATE\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String viewState = e.attr(\"value\");\n\n        e = d.getElementById(\"__EVENTVALIDATION\");\n        if (e == null || e.attr(\"value\") == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String eventValidation = e.attr(\"value\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\", \"\"));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewState));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATEGENERATOR\", \"D7823E0B\"));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventValidation));\n        postData.add(new BasicNameValuePair(\"_ctl0:cphMain:SmartpassTextbox\", getUsername()));\n        postData.add(new BasicNameValuePair(\"_ctl0:cphMain:SubmitButton\", \"OK\"));\n        postData.add(new BasicNameValuePair(\"_ctl0:cphMain:chbRememberSmartPassCode\", \"on\"));\n        postData.add(new BasicNameValuePair(\"_ctl0:cphMain:cookieEnabled\", \"true\"));\n        return new LoginPackage(urlopen, postData, response, \"https://www.dittkort.se//q/?p=7EB4F129-0A41-417F-8FEA-51B2B75B9D24\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"cphMain_txtGeneralCardError\")) {\n            throw new LoginException(res.getText(R.string.invalid_card_number).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        urlopen = login();\n        Document document = Jsoup.parse(response);\n        Element balanceElement = document.getElementById(\"cphMain_lblAmount\");\n        if (balanceElement == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + res.getText(R.string.balance).toString());\n        }\n\n        Element nameElement = document.getElementById(\"lblCardName\");\n        String accountName = nameElement == null ? NAME.toUpperCase() : nameElement.text();\n        if (this.getCustomName().isEmpty()) {\n            this.setCustomName(accountName);\n        }\n\n        Account account = new Account(accountName, Helpers.parseBalance(balanceElement.text()), \"0\");\n        accounts.add(account);\n        balance = balance.add(account.getBalance());\n\n        document = Jsoup.parse(urlopen.open(\"https://www.dittkort.se/q/Partial/Transactions.aspx?cnt=20\"));\n        Elements transactionElements = document.select(\"tr\");\n        List<Transaction> transactions = new ArrayList<Transaction>();\n        if (transactionElements != null) {\n            for (Element element : transactionElements) {\n                transactions.add(asTransaction(element));\n            }\n        }\n        account.setTransactions(transactions);\n        super.updateComplete();\n    }\n\n    private Transaction asTransaction(Element element) {\n        return new Transaction(element.child(0).text().trim(), element.child(1).text().trim(),\n                Helpers.parseBalance(element.child(2).text()));\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/IKEA.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport android.content.Context;\n\nimport java.io.IOException;\n\n\npublic class IKEA extends AbsIkanoPartner {\n\n    private static final String NAME = \"IKEA HANDLA kort\";\n\n    private static final String URL\n            = \"https://partner.ikanobank.se/web/engines/page.aspx?structid=1420\";\n\n    private static final int BANKTYPE_ID = Bank.IKEA;\n\n    public IKEA(Context context) {\n        super(context, R.drawable.logo_ikea);\n\n        super.url = URL;\n        this.structId = \"1420\";\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public IKEA(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/IkanoBank.java",
    "content": "/*\n * Copyright (C) 2013 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\npublic class IkanoBank extends Bank {\n\n    private static final String NAME = \"Ikano Bank\";\n\n    private static final String URL = \"https://secure.ikanobank.se/engines/page.aspx?structid=1895\";\n\n    private static final int BANKTYPE_ID = IBankTypes.IKANOBANK;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private Pattern reEventValidation = Pattern.compile(\n            \"__EVENTVALIDATION\\\"\\\\s+.*?value=\\\"([^\\\"]+)\\\"\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern reViewState = Pattern.compile(\"__VIEWSTATE\\\"\\\\s+.*?value=\\\"([^\\\"]+)\\\"\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"(ctl\\\\d{1,}_rptAccountList_ctl\\\\d{1,}_RowLink)[^>]+>([^<]+)</a>\\\\s*</td>\\\\s*<td>([^<]+)</td>\\\\s*<td>[^<]+</td>\\\\s*<td[^>]+>[^<]+</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<td>(\\\\d{4}-\\\\d{2}-\\\\d{2})</td>\\\\s*<td>([^<]+)</td>\\\\s*<td>[^<]+</td>\\\\s*<td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reErrorMessage = Pattern.compile(\n            \"<div\\\\s*class=\\\"(?:error|message)-box-inner\\\">\\\\s*<div>\\\\s*<p>(.+)</p\");\n\n    private String response = null;\n\n    public IkanoBank(Context context) {\n        super(context, R.drawable.logo_ikanobank);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public IkanoBank(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_ikanobank));\n        response = urlopen.open(\"https://secure.ikanobank.se/login\");\n        Matcher matcher;\n        if (response.contains(\"Banken är stängd\")) {\n            matcher = reErrorMessage.matcher(response);\n            if (matcher.find()) {\n                throw new BankException(Helpers.removeHtml(matcher.group(1).replace(\"<BR>\", \"\\n\")));\n            }\n        }\n        matcher = reViewState.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String strViewState = matcher.group(1);\n        matcher = reEventValidation.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String strEventValidation = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__LASTFOCUS\", \"\"));\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\", \"ctl02$lbLogin\"));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", strViewState));\n        postData.add(new BasicNameValuePair(\"ctl02$txtSocialSecurityNumber\", getUsername()));\n        postData.add(new BasicNameValuePair(\"ctl02$txtPinCode\", getPassword()));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", strEventValidation));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://secure.ikanobank.se/engines/page.aspx?structid=1895\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Ogiltigt personnummer\") || response.contains(\n                \"felaktigt personnummer\")) {\n            Matcher matcher = reErrorMessage.matcher(response);\n            if (matcher.find()) {\n                throw new LoginException(\n                        Helpers.removeHtml(matcher.group(1).replace(\"<BR>\", \"\\n\")));\n            } else {\n                throw new LoginException(\n                        res.getText(R.string.invalid_username_password).toString());\n            }\n\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: ID                    ctl07_rptAccountList_ctl00_RowLink\n             * 2: Name                  Kontonamn1\n             * 3: Account number        123456\n             * 4: Balance               316 000,39\n             *\n             */\n            accounts.add(new Account(Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(4).trim()), matcher.group(1).trim()));\n            balance = balance.add(Helpers.parseBalance(matcher.group(4)));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        // Find viewstate and eventvalidation from last page.\n        Matcher matcher;\n        matcher = reViewState.matcher(response);\n        if (!matcher.find()) {\n            Timber.e(\"Unable to find ViewState. L156.\");\n            return;\n        }\n        String strViewState = matcher.group(1);\n        matcher = reEventValidation.matcher(response);\n        if (!matcher.find()) {\n            Timber.e(\"Unable to find EventValidation. L161.\");\n            return;\n        }\n        String strEventValidation = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\", account.getId().replace(\"_\", \"$\")));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", strViewState));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", strEventValidation));\n        response = urlopen.open(\"https://secure.ikanobank.se/engines/page.aspx?structid=1787\",\n                postData);\n\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Date              2010-10-27\n             * 2: Specification     ÍVERFÍRING\n             * 3: Amount            50\n             *\n             */\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Jojo.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\npublic class Jojo extends Bank {\n\n    private static final String NAME = \"Jojo Reskassa\";\n\n    private static final String URL = \"https://www.skanetrafiken.se\";\n\n    private static final int BANKTYPE_ID = IBankTypes.JOJO;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT\n            | +InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n\n    private static final String NAME_NOT_SET = \"KortnamnSaknas\";\n\n    private String response = null;\n\n    public Jojo(Context context) {\n        super(context, R.drawable.logo_jojo);\n\n        super.url = URL;\n        super.inputTitletextUsername = R.string.email;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Jojo(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException,\n            IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_jojo));\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"loginInputModel.Email\", getUsername()));\n        postData.add(new BasicNameValuePair(\"loginInputModel.Password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"loginInputModel.Role\", \"Private\"));\n        return new LoginPackage(urlopen, postData, response, URL + \"/inloggning/LoginPost/\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (!response.contains(\"window.location\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        response = urlopen.open(URL + \"/mitt-konto/se-saldo-och-ladda-kort/\");\n\n        Document document = Jsoup.parse(response);\n        Elements elements = document.select(\".card-content\");\n        for (Element element : elements) {\n            accounts.add(toAccount(element));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    private Account toAccount(Element card) {\n        String cardNumber = card.select(\".card-number\").text().trim();\n        BigDecimal balance = getBalance(cardNumber);\n        String name = card.select(\".title\").text().trim();\n        String displayName = NAME_NOT_SET.equals(name) ? cardNumber : name;\n        return new Account(displayName, balance, cardNumber);\n    }\n\n    private BigDecimal getBalance(String cardNumber) {\n        try {\n            String balanceData = urlopen.open(URL +\n                    \"/mitt-konto/se-saldo-och-ladda-kort/GetCardBalance/?cardId=\" + cardNumber);\n            Document balanceDocument = Jsoup.parse(balanceData);\n            Elements balance = balanceDocument.select(\".balance\");\n\n            if (!balance.isEmpty()) {\n                return Helpers.parseBalance(balance.first().text().trim());\n            }\n        } catch (IOException e) {\n            // Ignore and defaults to zero\n            Timber.w(e, \"Getting Jojo card balance failed\");\n        }\n        return BigDecimal.ZERO;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/McDonalds.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n * Contributors: PMC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class McDonalds extends Bank {\n\n    private static final String NAME = \"McDonald's Presentkort\";\n\n    private static final String URL = \"http://apps.mcdonalds.se/sweden/giftquer.nsf/egift?OpenForm\";\n\n    private static final int BANKTYPE_ID = Bank.MCDONALDS;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final boolean INPUT_HIDDEN_PASSWORD = true;\n\n    private static final int INPUT_TITLETEXT_USERNAME = R.string.card_number;\n\n    private Pattern reBalance = Pattern.compile(\"saldo:\\\\s*([0-9,. -]+)\\\\s*kronor\");\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<tr><td>(\\\\d{2}-\\\\d{2}-\\\\d{2})\\\\s*\\\\d{2}:\\\\d{2}</td><td>([^<]+)</td><td>[^<]+</td><td>([^<]+)</td></tr>\");\n\n    private String response = \"\";\n\n    public McDonalds(Context context) {\n        super(context, R.drawable.logo_mcdonalds);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHiddenPassword = INPUT_HIDDEN_PASSWORD;\n        super.inputTitletextUsername = INPUT_TITLETEXT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public McDonalds(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, ClientProtocolException, IOException {\n        urlopen = new Urllib(context);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__Click\", \"0\"));\n        postData.add(new BasicNameValuePair(\"CardNumber\", getUsername()));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"http://apps.mcdonalds.se/sweden/giftquer.nsf/egift?OpenForm&Seq=1\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"felaktigt kortnummer\")) {\n            throw new LoginException(res.getText(R.string.invalid_card_number).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().length() != 19) {\n            throw new LoginException(res.getText(R.string.invalid_card_number).toString());\n        }\n        login();\n        Matcher matcher = reBalance.matcher(response);\n        if (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: balance               845\n             *\n             */\n            Account account = new Account(\"Presentkort\", Helpers.parseBalance(matcher.group(1)),\n                    \"1\");\n            balance = Helpers.parseBalance(matcher.group(1));\n            ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n            matcher = reTransactions.matcher(response);\n            while (matcher.find()) {\n                /*\n                 * Capture groups:\n                 * GROUP                    EXAMPLE DATA\n                 * 1: Date                  11-03-17\n                 * 2: Location              Sthlm, Sk&ouml;ndal\n                 * 3: Amount                -144\n                 *\n                 */\n                transactions.add(new Transaction(\"20\" + matcher.group(1).trim(),\n                        Html.fromHtml(matcher.group(2)).toString().trim(),\n                        Helpers.parseBalance(matcher.group(3))));\n                account.setTransactions(transactions);\n            }\n            accounts.add(account);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Meniga.java",
    "content": "package com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.protocol.HTTP;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Meniga extends Bank {\n\n    private static final String NAME = \"Meniga\";\n\n    private static final String URL = \"https://www.meniga.is/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.MENIGA;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n\n    private static final String INPUT_HINT_USERNAME = \"name@company.com\";\n\n    String response;\n\n    private Pattern reAccounts = Pattern.compile(\n            \"\\\\?account=([^']+)'[^>]*>\\\\s*<div\\\\s*class=\\\"account-info\\\">[^<]*<span\\\\s*class=\\\"bold\\\">([^<]+)</span>\\\\s*(?:</div>\\\\s*<div\\\\s*class=\\\"account-status\\\">)\\\\s*<span\\\\s*class=\\\"(minus|plus)\\\">([^<]+)</span>\");\n\n    private Pattern reTransactions = Pattern.compile(\n            \"\\\"Id\\\":([^,]*),.*?\\\"Text\\\":\\\"([^\\\"]*)\\\".*?\\\"OriginalDate\\\":\\\".?.?Date\\\\(([^\\\\)]*)\\\\).*?\\\"Amount\\\":([^,]*),\");\n\n    public Meniga(Context context) {\n        super(context, R.drawable.logo_meniga);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.setCurrency(\"ISK\");\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Meniga(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_meniga));\n        urlopen.setContentCharset(HTTP.ISO_8859_1);\n        response = urlopen.open(\"https://www.meniga.is/Mobile\");\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"email\", getUsername()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n        return new LoginPackage(urlopen, postData, response, \"https://www.meniga.is/Mobile\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n\n        if (response.contains(\"<div class=\\\"login\\\">\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        response = urlopen.open(\"https://www.meniga.is/mobile/language/?lang=is-IS\");\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        response = urlopen.open(\"https://www.meniga.is/Mobile/Accounts\");\n        Matcher matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Type              id\n             * 2: Name              accont\n             * 3: ----              plus or minus\n             * 4: Balance            5 678\n             *\n             */\n            String balanceString;\n            balanceString = matcher.group(4) + \".00\";\n            Account account = new Account(Html.fromHtml(matcher.group(2)).toString(),\n                    Helpers.parseBalance(balanceString), matcher.group(1).trim());\n            account.setCurrency(\"ISK\");\n            balance = balance.add(Helpers.parseBalance(matcher.group(4)));\n            accounts.add(account);\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        if (account.getType() == Account.OTHER) {\n            return;\n        }\n\n        String response;\n        Matcher matcher;\n\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        response = urlopen.open(\"https://www.meniga.is/Transactions?account=\" + account.getId());\n        matcher = reTransactions.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: Id                    1231213\n             * 2: Specification         Pressbyran\n             * 3: Date in millisec      2142411351235\n             * 4: Amount                -20\n             *\n             *\n             */\n            Long date = Long.valueOf(matcher.group(3));\n            SimpleDateFormat ft = new SimpleDateFormat(\"yy-MM-dd\");\n            Transaction transaction = new Transaction(ft.format(date),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(4)));\n            transaction.setCurrency(\"ISK\");\n            transactions.add(transaction);\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/MinPension.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class MinPension extends Bank {\n\n    public MinPension(Context context) {\n        super(context, R.drawable.logo_minpension);\n        inputTypeUsername = InputType.TYPE_CLASS_PHONE;\n        inputTypePassword = InputType.TYPE_CLASS_PHONE | InputType.TYPE_TEXT_VARIATION_PASSWORD;\n        inputHintUsername = res.getText(R.string.pno).toString();\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return IBankTypes.MINPENSION;\n    }\n\n    @Override\n    public String getName() {\n        return \"Min Pension.se\";\n    }\n\n    public MinPension(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException,\n            IOException {\n        List<NameValuePair> postData = new ArrayList<>();\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_minpension));\n        String response = urlopen.open(\"https://www.minpension.se/inloggning\");\n        Document jDoc = Jsoup.parse(response);\n        Element el = jDoc.select(\"input[name=__RequestVerificationToken]\").first();\n        if (el == null) {\n            throw new BankException(res.getText(R.string.unable_to_find).toString() + \" token.\");\n        }\n        postData.add(new BasicNameValuePair(\"__RequestVerificationToken\", el.val()));\n        postData.add(new BasicNameValuePair(\"viewModel.Personnummer\", getUsername()));\n        postData.add(new BasicNameValuePair(\"viewModel.Kod\", getPassword()));\n        LoginPackage lp = new LoginPackage(urlopen, postData, null,\n                \"https://www.minpension.se/inloggning/personlig-kod\");\n        return lp;\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n\n        String response = urlopen.open(lp.getLoginTarget(), lp.getPostData(), true);\n        if (!response.contains(\"LoggaUt.aspx\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        response = urlopen.open(\n                \"https://www.minpension.se/mina-sidor/redirect?path=MinPension%2FDefault.aspx&bodyMargin=0\");\n        Document document = Jsoup.parse(response);\n        Element e = document.select(\"#authenticationResult\").first();\n        if (e == null) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        List<NameValuePair> postData = new ArrayList<>();\n        postData.add(new BasicNameValuePair(\"authenticationResult\", e.val()));\n        urlopen.open(\"https://minasidor.minpension.se/MinPension/Default.aspx\", postData, true);\n\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n//Allmän pension\n        accounts.add(updateAccount(\"https://minasidor.minpension.se/MinPension/AllmanPension.aspx\",\n                \"#AllmänPensionTable tr\",\n                res.getText(R.string.public_pension).toString()));\n//Tjänstepension\n        accounts.add(updateAccount(\"https://minasidor.minpension.se/MinPension/Tjanstepension.aspx\",\n                \"#TjänstepensionTable tr\",\n                res.getText(R.string.occupational_pension).toString()));\n//Privat pension\n        accounts.add(updateAccount(\"https://minasidor.minpension.se/MinPension/PrivatPension.aspx\",\n                \"#PrivatPensionTable tr\",\n                res.getText(R.string.private_pension).toString()));\n\n        super.updateComplete();\n    }\n\n    private Account updateAccount(String url, String selector, String name) throws IOException {\n        String response = urlopen.open(url);\n        Document dResponse = Jsoup.parse(response);\n        List<Transaction> transactions = new ArrayList<>();\n        String institute = \"\";\n        String subInstitute = \"\";\n        for (Element e : dResponse.select(selector)) {\n            if (e.hasClass(\"GroupRow\")) {\n                institute = e.children().first().text();\n            } else if (e.hasClass(\"GroupMemberRow\") || e.hasClass(\"SubRow\")) {\n                Elements elements = e.children();\n                if (elements.size() == 6) { //Special case for \"Allmän pension\"\n                    if (elements.get(2).text().isEmpty()) {\n                        //   subInstitute =  \" — \" + elements.get(1).text(); /* Doesn't fit atm. */\n                    } else {\n                        transactions.add(new Transaction(elements.get(5).text(),\n                                institute + subInstitute + \"\\n — \" + elements.get(1).text(),\n                                Helpers.parseBalance(elements.get(2).text())));\n                        subInstitute = \"\";\n                    }\n                } else if (elements.size() >= 7) {\n                    transactions.add(new Transaction(elements.get(6).text(),\n                            institute + \"\\n — \" + elements.get(1).text(),\n                            Helpers.parseBalance(elements.get(4).text())));\n                }\n            }\n        }\n\n        balance = BigDecimal.ZERO;\n        for (Transaction t : transactions) {\n            balance = balance.add(t.getAmount());\n        }\n        Account account = new Account(name, balance, name, Account.REGULAR, \"\");\n        account.setTransactions(transactions);\n        return account;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Nordnet.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.protocol.HTTP;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport android.content.Context;\nimport android.text.Html;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Nordnet extends Bank {\n\n    private static final String NAME = \"Nordnet\";\n\n    private static final String URL = \"https://www.nordnet.se/mux/login/startSE.html\";\n\n    private static final int BANKTYPE_ID = IBankTypes.NORDNET;\n\n    private Pattern reAccounts =\n            Pattern.compile(\n                    \"<span class=\\\"bullet\\\">·<\\\\/span>\\\\n\\\\t\\\\t\\\\t\\\\t\\\\t\\\\t<span>(.*?)<\\\\/span>\");\n\n    private Pattern reBalance = Pattern.compile(\n            \"<div class=\\\\\\\"value\\\\\\\">\\\\n(.*?)\\\\n\\\\t\\\\t<\\\\/div>\");\n\n    private String response = null;\n\n    public Nordnet(Context context) {\n        super(context, R.drawable.logo_nordnet);\n\n        super.url = URL;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Nordnet(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_nordnet));\n        urlopen.setContentCharset(HTTP.ISO_8859_1);\n        response = urlopen.open(\"https://www.nordnet.se/mux/login/startSE.html\");\n\n        Document d = Jsoup.parse(response);\n        Element e = d.getElementById(\"input1\");\n        if (e == null || \"\".equals(e.attr(\"name\"))) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" username field.\");\n        }\n        String loginFieldName = e.attr(\"name\");\n        e = d.getElementById(\"pContHidden\");\n        if (e == null || \"\".equals(e.attr(\"name\"))) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" password field.\");\n        }\n        String loginFieldPassword = e.attr(\"name\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"checksum\", \"\"));\n        postData.add(new BasicNameValuePair(\"referer\", \"\"));\n        postData.add(new BasicNameValuePair(\"encryption\", \"0\"));\n        postData.add(new BasicNameValuePair(loginFieldName, getUsername()));\n        postData.add(new BasicNameValuePair(loginFieldPassword, getPassword()));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.nordnet.se/mux/login/login.html\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"fel vid inloggningen\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        Matcher accountMatcher = reAccounts.matcher(response);\n        Matcher balanceMatcher = reBalance.matcher(response);\n        while (accountMatcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Account name and number      Investeringssparkonto 1234567   | Sparkonto 1234 567890 1\n             *\n             */\n            if (balanceMatcher.find()) {\n                /*\n                * Capture groups:\n                * GROUP                EXAMPLE DATA\n                * 1: Account balance     62 356 | 0\n                *\n                */\n                Account account = new Account(Html.fromHtml(accountMatcher.group(1)).toString().trim(),\n                        Helpers.parseBalance(balanceMatcher.group(1)),\n                        Html.fromHtml(accountMatcher.group(1)).toString().trim().replaceAll(\" \", \"\"));\n\n                // Saving accounts contain white space characters in the account number\n                if (!accountMatcher.group(1).trim().contains(\" \")) {\n                    account.setType(Account.FUNDS);\n                }\n                accounts.add(account);\n                balance = balance.add(Helpers.parseBalance(balanceMatcher.group(1)));\n            }\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/OKQ8.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n * Contributors: COLA\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class OKQ8 extends Bank {\n\n    private static final String NAME = \"OKQ8 VISA\";\n\n    private static final String URL\n            = \"https://nettbank.edb.com/Logon/index.jsp?domain=0066&from_page=http://www.okq8.se&to_page=https://nettbank.edb.com/cardpayment/transigo/logon/done/okq8\";\n\n    private static final int BANKTYPE_ID = IBankTypes.OKQ8;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDDXXXX\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    private Pattern reLoginRedir = Pattern.compile(\"value=\\\"([^\\\"]*)\\\"\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern reSessionId = Pattern.compile(\"action=\\\"([^\\\"]*)\\\"\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern reBalance = Pattern\n            .compile(\"<div class=\\\"numberpositive\\\">([^<]*)</div>\", Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"style=\\\"white-space: nowrap\\\">([^<]*)</td>\\\\s*<td[^>]*>[^<]*</td>\\\\s*<td[^>]*>[^<]*</td>\\\\s*<td[^>]*>([^<]*)</td>\\\\s*<td[^>]*><div[^>]*>([^<]*)</div></td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    public OKQ8(Context context) {\n        super(context, R.drawable.logo_okq8);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public OKQ8(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_okq8));\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        response = urlopen\n                .open(\"https://nettbank.edb.com/authenticate/login/basicauth?configKey=okq8\");\n        //p_tranid is the epoch time in milliseconds\n        Matcher matcher;\n        matcher = reSessionId.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\"Could not find post action.\");\n        }\n        String postAction = matcher.group(1);\n        postData.add(new BasicNameValuePair(\"javax.faces.ViewState\",\n                postAction.substring(postAction.length() - 5, postAction.length() - 1)));\n        postData.add(new BasicNameValuePair(\"loginForm\", \"loginForm\"));\n        postData.add(new BasicNameValuePair(\"button\", \"Logga in\"));\n\n        postData.add(new BasicNameValuePair(\"userid\", getUsername().toUpperCase()));\n        postData.add(new BasicNameValuePair(\"useridInput\", getUsername().toUpperCase()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://nettbank.edb.com\" + postAction);\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        Matcher matcher;\n        String value = null;\n\n        LoginPackage lp = preLogin();\n        List<NameValuePair> postData = lp.getPostData();\n        response = urlopen.open(lp.getLoginTarget(), postData);\n        if (!response.contains(\"Please wait\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n            /*\n             * After login ok we end up at an intermediate login page with a submit\n             * form that contains information that must be passed to the next page:\n             * <input type=\"hidden\" name=\"so\" value=\"xxx\"/>\n             * <input type=\"hidden\" name=\"last_logon_time\" value=\"xxx\"/>\n             * <input type=\"hidden\" name=\"failed_logon_attempts\" value=\"xxx\"/>\n             * <input type=\"hidden\" name=\"login_service_url\" value=\"xxx\"/>\n             */\n        matcher = reLoginRedir.matcher(response);\n        postData.clear();\n        if (!matcher.find()) {\n            throw new LoginException(\"Could not find value for 'so'.\");\n        }\n        value = matcher.group(1);\n        postData.add(new BasicNameValuePair(\"so\", value));\n\n        if (!matcher.find()) {\n            throw new LoginException(\"Could not find value for 'last_logon_time'.\");\n        }\n        value = matcher.group(1);\n        postData.add(new BasicNameValuePair(\"last_logon_time\", value));\n\n        if (!matcher.find()) {\n            throw new LoginException(\"Could not find value for 'failed_logon_attempts'.\");\n        }\n        value = matcher.group(1);\n        postData.add(new BasicNameValuePair(\"failed_logon_attempts\", value));\n\n        if (!matcher.find()) {\n            throw new LoginException(\"Could not find value for 'login_service_url'.\");\n        }\n        value = matcher.group(1);\n        postData.add(new BasicNameValuePair(\"login_service_url\", value));\n\n        response = urlopen\n                .open(\"https://nettbank.edb.com/payment/transigo/logon/done/okq8\", postData);\n\n        if (response.contains(\"HTML REDIRECT\")) {\n            throw new LoginException(\"Login failed.\");\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        if (response == null) {\n            urlopen = login();\n        }\n        /*\n         * The start page contains the balance of the account (\"Kvar att utnytta\") so read it.\n         * The balance is the first value (of three) that are matched by reBalance expression.\n         */\n        Matcher matcher = reBalance.matcher(response);\n        if (matcher.find()) {\n            accounts.add(\n                    new Account(\"Kvar att utnyttja\", Helpers.parseBalance(matcher.group(1)), \"1\"));\n            balance = balance.add(Helpers.parseBalance(matcher.group(1)));\n        }\n        /*\n         * Find the next value that is \"Saldo\". Add a new account but don't add to the balance.\n         */\n        if (matcher.find()) {\n            accounts.add(new Account(\"Saldo\", Helpers.parseBalance(matcher.group(1)), \"2\"));\n            accounts.add(\n                    new Account(\"Saldo\", Helpers.parseBalance(matcher.group(1)).negate(), \"4\"));\n        }\n        /*\n         * Find the next value that is \"Köpgräns\". Add a new account but don't add to the balance.\n         */\n        if (matcher.find()) {\n            accounts.add(new Account(\"Köpgräns\", Helpers.parseBalance(matcher.group(1)), \"3\"));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n\n        response = urlopen\n                .open(\"https://nettbank.edb.com/payment/transigo/card/overview/lastTransactionsAccount\");\n\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture group 1 = date\n             * Capture group 2 = text\n             * Capture group 3 = amount\n             * Negate the amount since buys are reported as positive.\n             */\n            transactions.add(new Transaction(matcher.group(1).trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3)).negate()));\n        }\n        accounts.get(0).setTransactions(transactions);\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Ostgotatrafiken.java",
    "content": "/*\n * Copyright (C) 2014 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Ostgotatrafiken extends Bank {\n\n    private static final String NAME = \"Östgötatrafiken\";\n\n    private static final int BANKTYPE_ID = IBankTypes.OSTGOTATRAFIKEN;\n\n    private Pattern reViewState = Pattern.compile(\n            \"<input [^>]+ id=\\\"javax.faces.ViewState\\\"[^>]* value=\\\"([^\\\"]+)\\\"\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private Pattern reMoreCards = Pattern.compile(\n            \"<li><a [^>]+ id=\\\"(form1cardOverviewTabs[^\\\"]+)\\\"\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private Pattern reCardNumber = Pattern.compile(\">Kortnummer: (\\\\d+)<\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private Pattern reCardName = Pattern.compile(\"<li class=\\\"selected\\\">.*?>(\\\\w+?)</span>\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private Pattern reCardBalance = Pattern.compile(\">Saldo.*?>\\\\s*(\\\\d+)\\\\s*kr\\\\s*</span>\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private String response = null;\n\n    public Ostgotatrafiken(Context context) {\n        super(context, R.drawable.logo_ogt);\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Ostgotatrafiken(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context,\n                R.raw.cert_ostgotatrafiken_login, R.raw.cert_ostgotatrafiken_overview));\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"\", \"{\\\"authSource\\\":10,\" +\n                                            \"\\\"keepMeLimitedLoggedIn\\\":true,\" +\n                                            \"\\\"userName\\\":\\\"\" + getUsername() + \"\\\",\" +\n                                            \"\\\"password\\\":\\\"\" + getPassword() + \"\\\",\" +\n                                            \"\\\"impersonateUserName\\\":\\\"\\\"}\"));\n\n        return new LoginPackage(urlopen, postData, response, \"https://www.ostgotatrafiken.se/ajax/Login/Attempt\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (!response.contains(\"presentationUserName\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        String cardOverviewUrl\n                = \"https://webtick.ostgotatrafiken.se/webtick/user/pages/CardOverview.iface\";\n        response = urlopen.open(cardOverviewUrl);\n        parseTravelCardBalanceFromServerResponse(response);\n\n        Matcher viewStateMatcher = reViewState.matcher(response);\n        if (!viewStateMatcher.find()) {\n            throw new BankException(res.getText(R.string.unable_to_find).toString() + \" ViewState\");\n        }\n        Matcher moreCardsMatcher = reMoreCards.matcher(response);\n        while (moreCardsMatcher.find()) {\n            List<NameValuePair> postData = new ArrayList<NameValuePair>();\n            postData.add(new BasicNameValuePair(\"form1cardOverviewTabs:j_idcl\",\n                    moreCardsMatcher.group(1)));\n            postData.add(new BasicNameValuePair(\"ice.focus\", moreCardsMatcher.group(1)));\n            postData.add(\n                    new BasicNameValuePair(moreCardsMatcher.group(1), moreCardsMatcher.group(1)));\n            postData.add(new BasicNameValuePair(\"form1cardOverviewTabs\", \"form1cardOverviewTabs\"));\n            postData.add(new BasicNameValuePair(\"ice.event.captured\", moreCardsMatcher.group(1)));\n            postData.add(new BasicNameValuePair(\"javax.faces.source\", moreCardsMatcher.group(1)));\n            postData.add(\n                    new BasicNameValuePair(\"javax.faces.ViewState\", viewStateMatcher.group(1)));\n\n            postData.add(new BasicNameValuePair(\"icefacesCssUpdates\", \"\"));\n            postData.add(new BasicNameValuePair(\"javax.faces.partial.event\", \"click\"));\n            postData.add(new BasicNameValuePair(\"javax.faces.partial.execute\", \"@all\"));\n            postData.add(new BasicNameValuePair(\"javax.faces.partial.render\", \"@all\"));\n            postData.add(new BasicNameValuePair(\"ice.event.type\", \"onclick\"));\n            postData.add(new BasicNameValuePair(\"ice.event.alt\", \"false\"));\n            postData.add(new BasicNameValuePair(\"ice.event.ctrl\", \"false\"));\n            postData.add(new BasicNameValuePair(\"ice.event.shift\", \"false\"));\n            postData.add(new BasicNameValuePair(\"ice.event.meta\", \"false\"));\n            postData.add(new BasicNameValuePair(\"ice.event.x\", \"606\"));\n            postData.add(new BasicNameValuePair(\"ice.event.y\", \"362\"));\n            postData.add(new BasicNameValuePair(\"ice.event.left\", \"true\"));\n            postData.add(new BasicNameValuePair(\"ice.event.right\", \"false\"));\n            postData.add(new BasicNameValuePair(\"ice.submit.type\", \"ice.s\"));\n            postData.add(new BasicNameValuePair(\"ice.submit.serialization\", \"form\"));\n            postData.add(new BasicNameValuePair(\"javax.faces.partial.ajax\", \"true\"));\n\n            // ice.event.target is sent by browser, but not needed by\n            // server so don't bother parsing response for its correct value\n            //postData.add(new BasicNameValuePair(\"ice.event.target\", \"form1cardOverviewTabs:j_idt240:1:j_idt243\"));\n\n            // ice.window and ice.view are sent by browser, but by not sending\n            // these to server we get an HTML response which can be parsed\n            // just like the initial response. If including ice.window and\n            // ice.view in POST the server will give us XML data back which\n            // would need separate parsing.\n            //postData.add(new BasicNameValuePair(\"ice.window\", \"p7htbwx9t8\"));\n            //postData.add(new BasicNameValuePair(\"ice.view\", \"vcuag6esom\"));\n\n            urlopen.addHeader(\"Faces-Request\", \"partial/ajax\");\n            response = urlopen.open(cardOverviewUrl, postData);\n            parseTravelCardBalanceFromServerResponse(response);\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    private void parseTravelCardBalanceFromServerResponse(String response) {\n        Matcher cardNameMatcher = reCardName.matcher(response);\n        Matcher cardNumberMatcher = reCardNumber.matcher(response);\n        Matcher balanceMatcher = reCardBalance.matcher(response);\n\n        if (cardNameMatcher.find() && cardNumberMatcher.find() && balanceMatcher.find()) {\n            String cardName = cardNameMatcher.group(1);\n            String cardNumber = cardNumberMatcher.group(1);\n            String cardBalance = balanceMatcher.group(1);\n\n            accounts.add(new Account(cardName, Helpers.parseBalance(cardBalance), cardNumber));\n            balance = balance.add(Helpers.parseBalance(cardBalance));\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Osuuspankki.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Osuuspankki extends Bank {\n\n    private static final String NAME = \"Osuuspankki\";\n\n    private static final String URL = \"https://www.op.fi/op?kielikoodi=sv\";\n\n    private static final int BANKTYPE_ID = IBankTypes.OSUUSPANKKI;\n\n    private Pattern reAccounts = Pattern.compile(\n            \"href=\\\"\\\\?id=(\\\\d{1,})&(?:amp;)?tilinro=([^&]+)&[^>]+>([^<]+)</a>\\\\s*<br\\\\s?/>\\\\s*<span[^>]+>\\\\s*<b>([^<]+)</b>([^<]+)</span>\");\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<tr[^>]*>\\\\s*<td>\\\\s*<div\\\\s*class=\\\"Ensimmainen\\\">\\\\s*(\\\\d{2}\\\\.\\\\d{2})\\\\.<br.?/>\\\\s*\\\\s*(\\\\d{2}\\\\.\\\\d{2})\\\\.\\\\s*</div>\\\\s*</td>\\\\s*<td>\\\\s*<div>([^<]+)<br.?/>.*?</div>\\\\s*</td>\\\\s*<td>\\\\s*<div\\\\s*class=\\\"Nowrap\\\">\\\\s*<a[^>]+>([^<]+)<br.?/>\\\\s*</a>.*?</div>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<div[^>]*>([^<]+)</div>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private String response = null;\n\n    public Osuuspankki(Context context) {\n        super(context, R.drawable.logo_osuuspankki);\n        super.url = URL;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Osuuspankki(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context,\n                R.raw.cert_osuuspankki, R.raw.cert_osuuspankki_mobile));\n        response = urlopen.open(\"https://www.op.fi/op?kielikoodi=sv\");\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"REQUEST_LOGIN_ATTEMPTED\", \"true\"));\n        postData.add(new BasicNameValuePair(\"REQUEST_PREVIOUS_QUERYSTRING\", \"\"));\n        postData.add(new BasicNameValuePair(\"x\", \"24\"));\n        postData.add(new BasicNameValuePair(\"y\", \"5\"));\n        postData.add(new BasicNameValuePair(\"USERNAME\", getUsername()));\n        postData.add(new BasicNameValuePair(\"PWD\", getPassword()));\n\n        return new LoginPackage(urlopen, postData, response, \"https://www.op.fi/op?kielikoodi=sv\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n\n        if (response.contains(\"du nya koder genom att bes\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher;\n        matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: Account type          12401 | 12701\n             * 2: Account id            ecb_5f0e0dfcbc1e8aabe4f5ab85e3382266\n             * 3: Account name          FI91 5553 5140 0165 27\n             * 4: Amount                +882,35\n             * 5: Currency              &nbsp;&euro;\n             *\n             */\n            String currency = Helpers.parseCurrency(\n                    Html.fromHtml(matcher.group(5)).toString().trim(), \"EUR\");\n            Account account = new Account(Html.fromHtml(matcher.group(3)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(4)), matcher.group(2).trim());\n            account.setCurrency(currency);\n            //Bonuskonto\n            if (\"12701\".equals(matcher.group(1))) {\n                account.setType(Account.OTHER);\n            }\n            this.setCurrency(currency);\n            accounts.add(account);\n            balance = balance.add(Helpers.parseBalance(matcher.group(4)));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        Matcher matcher;\n\n        response = urlopen.open(String.format(\"https://www.op.fi/?id=%s&tilinro=%s&ecb=1&srcpl=4\",\n                (account.getType() == Account.OTHER ? \"12701\" : \"12401\"), account.getId()));\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: Book. date            21.01\n             * 2: Trans. date           20.01\n             * 3: Description           ITUNES-EURO LUXEMBOURG\n             * 4: Transaction type      BANKKORTSBET.\n             * 5: Amount in EUR         -3,99\n             *\n             */\n            String[] date = Html.fromHtml(matcher.group(2)).toString().trim().split(\"\\\\.\");\n            Transaction transaction = new Transaction(Helpers.getTransactionDate(date[1], date[0]),\n                    Html.fromHtml(matcher.group(3)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(5)));\n            transaction.setCurrency(account.getCurrency());\n            transactions.add(transaction);\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Payson.java",
    "content": "/*\n * Copyright (C) 2010-2015 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Payson extends Bank {\n\n    private static final String NAME = \"Payson\";\n\n    private static final String URL = \"https://www.payson.se/signin/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.PAYSON;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT\n            | +InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n\n    private Pattern reVerificationToken = Pattern.compile(\n            \"<input[^>]+name=\\\"__RequestVerificationToken\\\"[^>]+value=\\\"([^\\\"]+)\\\"\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\n    private String response = null;\n\n    private JSONObject userInfo = null;\n\n    public Payson(Context context) {\n        super(context, R.drawable.logo_payson);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Payson(String username, String password, Context context) throws BankChoiceException,\n            BankException, LoginException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_payson));\n        response = urlopen.open(URL);\n        Matcher matcher = reVerificationToken.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" RequestVerificationToken\");\n        }\n        String verificationToken = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__RequestVerificationToken\", verificationToken));\n        postData.add(new BasicNameValuePair(\"Username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"Password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"RedirectAfterLogin\", \"\"));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.payson.se/myaccount/account/SignIn/\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        try {\n            LoginPackage lp = preLogin();\n            response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n            userInfo = new JSONObject(\n                    urlopen.open(\"https://www.payson.se/myaccount/user/getuserinfo\"));\n        } catch (JSONException e) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString(), e);\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankChoiceException, BankException, LoginException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        try {\n            Account account = new Account(res.getText(R.string.balance).toString(),\n                    Helpers.parseBalance(userInfo.getString(\"balance\")), \"1\");\n            accounts.add(account);\n        } catch (JSONException e) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString(), e);\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/PlusGirot.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class PlusGirot extends Bank {\n\n    private static final String NAME = \"PlusGirot\";\n\n    private static final String URL = \"https://kontoutdrag.plusgirot.se/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.PLUSGIROT;\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<tr>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\\\\s*</td>\\\\s*<td[^>]+><font[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"<a[^>]+>([^<]+)</a>\\\\s*</font>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</font>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<font[^>]+>([^<]+)</f\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    public PlusGirot(Context context) {\n        super(context, R.drawable.logo_plusgirot);\n        super.url = URL;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public PlusGirot(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_plusgirot));\n        // Request first page to get cookies\n        response = urlopen.open(\"https://kontoutdrag.plusgirot.se/ku/html/epostllg.htm\");\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"KONTO\", getUsername()));\n        postData.add(new BasicNameValuePair(\"PIN_KOD\", getPassword()));\n        return new LoginPackage(urlopen, postData, response,\n                \"https://kontoutdrag.plusgirot.se/ku/bgya006/init\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"elaktigt kontonummer\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        Matcher matcher = reAccounts.matcher(response);\n        if (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Account holder    Efternamn,Fornamn\n             * 2: PG account        456 12 34-5\n             * 3: Amount            123,45\n             * 4: Credit            24,68\n             *\n             */\n            Account account = new Account(\n                    matcher.group(2).trim() + \" (\" + Html.fromHtml(matcher.group(1)).toString()\n                            .trim() + \")\",\n                    Helpers.parseBalance(matcher.group(3)),\n                    matcher.group(2).trim().replaceAll(\"[^0-9]*\", \"\"));\n            accounts.add(account);\n            balance = balance.add(Helpers.parseBalance(matcher.group(3)));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Date              2011-04-04\n             * 2: Specification     UTTAG\n             * 3: Payment code      Inr.\n             * 4: Amount            -100,00\n             *\n             */\n            transactions.add(\n                    new Transaction(matcher.group(1).trim(),\n                            Html.fromHtml(matcher.group(2)).toString().trim() + \" \" + Html.fromHtml(\n                                    matcher.group(3)).toString().trim(),\n                            Helpers.parseBalance(matcher.group(4))));\n        }\n        accounts.get(0).setTransactions(transactions);\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/SevenDay.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class SevenDay extends Bank {\n\n    private static final String NAME = \"SevenDay\";\n\n    private static final String URL = \"https://www.sevenday.se/mina-sidor/mina-sidor.htm\";\n\n    private static final int BANKTYPE_ID = IBankTypes.SEVENDAY;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDD-XXXX\";\n\n\n    private Pattern reViewState = Pattern.compile(\"ViewState\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"'depositAccountNum':'([^=]+)=='[^>]+>([^<]+)</a></td>\\\\s*<td[^>]+>\\\\s*<span[^>]+>\\\\s*([0-9,]+)[^<]+</span>\\\\s*</td>\\\\s*<td[^>]+>\\\\s*<span[^>]+>\\\\s*([^<]+)<\");\n\n    private String response = null;\n\n    public SevenDay(Context context) {\n        super(context, R.drawable.logo_sevenday);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public SevenDay(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_sevenday));\n        response = urlopen.open(\"https://www.sevenday.se/mina-sidor/mina-sidor.htm\");\n\n        Matcher matcher = reViewState.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String viewState = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"loginForm\", \"loginForm\"));\n        postData.add(new BasicNameValuePair(\"login\", \"login\"));\n        postData.add(new BasicNameValuePair(\"javax.faces.ViewState\", viewState));\n        postData.add(new BasicNameValuePair(\"ssn\", getUsername()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.sevenday.se/mina-sidor/mina-sidor.htm\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Logga in med personnummer\") || response.contains(\n                \"kommer automatiskt till startsidan\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        Matcher matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Account id        JigBFAUETrrqVKY+V4Dm3tcoY1n6Usa21IuHxa1BV7MnJT3T6rrGChDcDK0RSuM731uAeB/f9rvPRXRFYCCBcQ\n             * 2: Account name      Sparkonto: XXX\n             * 3: Interest          2,55\n             * 4: Amount            10&nbsp;kr\n             *\n             */\n            accounts.add(new Account(Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(4)),\n                    Html.fromHtml(matcher.group(1)).toString().trim()));\n            balance = balance.add(Helpers.parseBalance(matcher.group(4)));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/SveaDirekt.java",
    "content": "package com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.params.ClientPNames;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class SveaDirekt extends Bank {\n\n    private static final String NAME = \"Svea Direkt\";\n\n    private static final String URL = \"https://http://www.sveadirekt.com/sv/swe//\";\n\n    private static final int BANKTYPE_ID = IBankTypes.SVEADIREKT;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"YYMMDDXXXX\";\n\n\n    private static final String BASE_URL = \"https://services.sveadirekt.se/mypages/sv/\";\n\n    private static final String LOGIN_URL\n            = \"https://services.sveadirekt.se/mypages/sv/j_security_check\";\n\n    private static final String ACCOUNTS_URL\n            = \"https://services.sveadirekt.se/customerweb/mypages/save/index.page\";\n\n    private static final String TRANSACTIONS_URL\n            = \"https://services.sveadirekt.se/customerweb/mypages/save/account-details.page\";\n\n    private String response;\n\n    public SveaDirekt(Context context) {\n        super(context, R.drawable.logo_sveadirekt);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public SveaDirekt(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        if (urlopen == null) {\n            urlopen = new Urllib(context,\n                    CertificateReader.getCertificates(context, R.raw.cert_sveadirekt));\n            urlopen.getHttpclient().getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,\n                    true);\n        }\n        response = urlopen\n                .open(BASE_URL);\n\n        Document doc = Jsoup.parse(response);\n        if (!\"Logga in\".equals(doc.title())) {\n            throw new BankException(res.getText(R.string.unable_to_find)\n                    .toString() + \" login url.\");\n        }\n        String strLoginUrl = LOGIN_URL;\n\n        List<NameValuePair> postData = new ArrayList<>();\n        postData.add(new BasicNameValuePair(\"j_username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"j_password\", getPassword()));\n        return new LoginPackage(urlopen, postData, response, strLoginUrl);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(LOGIN_URL, lp.getPostData());\n        if (response.contains(\"error-failed-to-login\")) {\n            throw new LoginException(res.getText(\n                    R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(\n                    R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        response = urlopen.open(ACCOUNTS_URL);\n        Document doc = Jsoup.parse(response);\n        ArrayList<Account> accounts = parseAccounts(doc);\n        for (Account account : accounts) {\n            response = urlopen.open(TRANSACTIONS_URL + \"?account=\" + account.getId());\n            account.setTransactions(parseTransactions(response));\n        }\n        this.setAccounts(accounts);\n        super.updateComplete();\n    }\n\n    private ArrayList<Account> parseAccounts(Document pDocument) {\n        ArrayList<Account> accountList = new ArrayList<>();\n        Elements accounts = pDocument.select(\"table > tbody > tr\");\n        for (Element accountElement : accounts) {\n            Account account = new Account(\n                    accountElement.child(1).text(),\n                    amountOf(accountElement.child(3).text()),\n                    accountElement.child(0).text());\n            accountList.add(account);\n        }\n        return accountList;\n    }\n\n    private List<Transaction> parseTransactions(String pResponse) {\n        List<Transaction> vTransactions = new ArrayList<>();\n        Document doc = Jsoup.parse(pResponse);\n        Elements transactionElements =\n                doc.select(\"table > tbody\").get(1).children();\n\n        for (Element element : transactionElements) {\n            BigDecimal amount = amountOf(element.child(2).text());\n            String description = element.child(1).text();\n            if (description == null || description.isEmpty()) {\n                description = amount.compareTo(BigDecimal.ZERO) > 0 ? \"Insättning\"\n                        : \"Uttag\";\n            }\n            String date = element.child(0).text();\n            vTransactions.add(new Transaction(date, description, amount));\n        }\n        return vTransactions;\n    }\n\n    private BigDecimal amountOf(String amount) {\n        return new BigDecimal(amount\n                .replaceAll(\"\\\\u2011\", \"-\")\n                .replaceAll(\"[^\\\\d-]\", \"\"));\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/SvenskaSpel.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n * Contributors: Jonathan Hjertström (jh@nixi.com)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.util.EntityUtils;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class SvenskaSpel extends Bank {\n\n    private static final String NAME = \"Svenska Spel\";\n\n    private static final String URL = \"https://api.www.svenskaspel.se/player/sessions\";\n\n    private static final int BANKTYPE_ID = Bank.SVENSKASPEL;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT;\n\n    private static final int INPUT_TITLETEXT_USERNAME = R.string.username;\n\n    private Pattern reBalance = Pattern.compile(\"balance\\\":\\\"(.*?)\\\",\", Pattern.CASE_INSENSITIVE);\n\n    private String response = \"\";\n\n    public SvenskaSpel(Context context) {\n        super(context, R.drawable.logo_svenskaspel);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTitletextUsername = INPUT_TITLETEXT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public SvenskaSpel(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_svenskaspel));\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        return new LoginPackage(urlopen, postData, response, URL);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n\n        StringEntity postdata = new StringEntity(\n                \"{\\\"userName\\\":\\\"\" + getUsername() + \"\\\",\\\"password\\\":\\\"\" + getPassword() + \"\\\"}\");\n        HttpResponse httpResponse = urlopen.openAsHttpResponse(lp.getLoginTarget(), postdata, true);\n\n        if (httpResponse.getStatusLine().getStatusCode() != 200) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        response = EntityUtils.toString(httpResponse.getEntity());\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n\n        Matcher matcher = reBalance.matcher(response);\n        if (matcher.find()) {\n                        /*\n             * Capture groups:\n             * GROUP                    EXAMPLE DATA\n             * 1: balance               845\n             *\n             */\n            Account account = new Account(\"Saldo\", Helpers.parseBalance(matcher.group(1)), \"1\");\n            balance = Helpers.parseBalance(matcher.group(1));\n            balance = balance.add(Helpers.parseBalance(matcher.group(1)));\n            accounts.add(account);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/TestBank.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Random;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class TestBank extends Bank {\n\n    private static final String NAME = \"Testbank\";\n\n    private static final String URL = \"http://www.nullbyte.eu/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.TESTBANK;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅMMDD-XXXX\";\n\n    private static final String VOLATILE_ACCOUNT_NAME = \"Volatile\";\n\n    private final Random random = new Random();\n\n    private Pattern reAccounts = Pattern.compile(\n            \"<div>\\\\s*<span>([^<]+)</span>\\\\s*<span>([^<]+)</span>\\\\s*<span>([^<]+)</span>\\\\s*<span>([^<]+)</\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"(\\\\d{4}-\\\\d{2}-\\\\d{2})\\\\s</dt>[^>]+>([^<]+)[^>]+>.*?(?:Positive|Negative)\\\">([^<]+)\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    public TestBank(Context context) {\n        super(context, R.drawable.logo_bankdroid);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public TestBank(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException {\n        urlopen = new Urllib(context);\n        return urlopen;\n    }\n\n    /**\n     * Adds a new account to the accounts list.\n     * <p/>\n     * If the account is already there it will have its balance updated.\n     * <p/>\n     * The purpose of this account is to test updates and how they propagate in the UI.\n     */\n    private void addVolatileAccount() {\n        Account volatileAccount = null;\n        for (Account account: accounts) {\n            if (VOLATILE_ACCOUNT_NAME.equals(account.getName())) {\n                volatileAccount = account;\n            }\n        }\n\n        if (volatileAccount == null) {\n            volatileAccount =\n                new Account(VOLATILE_ACCOUNT_NAME, BigDecimal.ZERO, VOLATILE_ACCOUNT_NAME);\n            accounts.add(volatileAccount);\n        }\n        double balance = Math.round(random.nextDouble() * 1000000) / 100;\n        volatileAccount.setBalance(BigDecimal.valueOf(balance));\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        String response = urlopen.open(\n                \"http://www.nullbyte.eu/bankdroid/tests/testbank/accounts.htm\");\n        Matcher matcher = reAccounts.matcher(response);\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Name              Sparkonto\n             * 2: Amount            83553,70\n             * 3: ID                1\n             * 4: Type              trans|fund\n             */\n            Account acc = new Account(Html.fromHtml(matcher.group(1)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(2)),\n                    (\"fund\".equals(matcher.group(4)) ? \"f:\" : \"\") + matcher.group(3).trim());\n            if (\"fund\".equals(matcher.group(4))) {\n                acc.setType(Account.FUNDS);\n            } else {\n                balance = balance.add(Helpers.parseBalance(matcher.group(3)));\n            }\n            accounts.add(acc);\n        }\n\n        addVolatileAccount();\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        //No transaction history for loans, funds and credit cards.\n        int accType = account.getType();\n        if (accType == Account.LOANS || accType == Account.FUNDS || accType == Account.CCARD) {\n            return;\n        }\n\n        Matcher matcher;\n        String response = urlopen.open(\n                \"http://www.nullbyte.eu/bankdroid/tests/testbank/transactions_\" + account.getId()\n                        + \".htm\");\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find()) {\n            transactions.add(new Transaction(Html.fromHtml(matcher.group(1)).toString().trim(),\n                    Html.fromHtml(matcher.group(2)).toString().trim(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/TicketRikskortet.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class TicketRikskortet extends Bank {\n\n    private static final String NAME = \"Ticket Rikskortet\";\n\n    private static final String URL = \"https://www.edenred.se/rikskuponger/mina-sidor/logga-in/\";\n\n    private static final String URL_OVERVIEW = \"https://www.edenred.se/rikskuponger/mina-sidor/employee/start/\";\n\n    private static final String URL_TRANSACTIONS = \"https://www.edenred.se/rikskuponger/mina-sidor/employee/start/transaktioner/\";\n\n    private static final int BANKTYPE_ID = Bank.RIKSKORTET;\n\n    private Pattern reViewState = Pattern.compile(\"__VIEWSTATE\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reEventValidation = Pattern\n            .compile(\"__EVENTVALIDATION\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reBalance = Pattern.compile(\"EmployeeBalanceLabel\\\">([^<]+)</span>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reTransactions = Pattern.compile(\n            \"(\\\\d{4}-\\\\d{2}-\\\\d{2})</td><td[^>]+>([^<]+)</td><td[^>]+>([^<]+)</td>\",\n            Pattern.CASE_INSENSITIVE);\n\n    private String response = null;\n\n    public TicketRikskortet(Context context) {\n        super(context, R.drawable.logo_rikskortet);\n\n        super.url = URL;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public TicketRikskortet(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_ticketrikskortet));\n        response = urlopen.open(URL);\n        Matcher matcher = reViewState.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String viewState = matcher.group(1);\n\n        matcher = reEventValidation.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" EventValidation.\");\n        }\n        String eventValidation = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__EVENTTARGET\", \"\"));\n        postData.add(new BasicNameValuePair(\"__EVENTARGUMENT\", \"\"));\n        postData.add(new BasicNameValuePair(\"__EVENTVALIDATION\", eventValidation));\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", viewState));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$CorporateHeaderArea$CorporateHeaderID$QuickSearch$SearchText\", \"Sök här\"));\n        postData.add(\n                new BasicNameValuePair(\"ctl00$StartpageArea$ApplicationArea$LoginControl$UserName\",\n                        getUsername()));\n        postData.add(\n                new BasicNameValuePair(\"ctl00$StartpageArea$ApplicationArea$LoginControl$Password\",\n                        getPassword()));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$StartpageArea$ApplicationArea$LoginControl$LoginButton\", \"Logga in\"));\n        return new LoginPackage(urlopen, postData, response, URL);\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (response.contains(\"Inloggningen misslyckades\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        if (!urlopen.getCurrentURI().equalsIgnoreCase(URL_OVERVIEW)) {\n            response = urlopen.open(URL_OVERVIEW);\n        }\n\n        Matcher matcher = reBalance.matcher(response);\n        if (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Balance           590,22 kr\n             *\n             */\n            BigDecimal b = Helpers.parseBalance(matcher.group(1));\n            accounts.add(new Account(\"Saldo\", b, \"1\"));\n            balance = balance.add(Helpers.parseBalance(matcher.group(1)));\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        Matcher matcher;\n        String response = urlopen.open(URL_TRANSACTIONS);\n        matcher = reTransactions.matcher(response);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n\n        while (matcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Trans. date       2012-06-01\n             * 2: Specification     DANMARKSG  KISTA\n             * 3: Amount            - 85 kr\n             *\n             */\n\n            transactions.add(new Transaction(matcher.group(1),\n                    Html.fromHtml(matcher.group(2).trim()).toString(),\n                    Helpers.parseBalance(matcher.group(3))));\n        }\n        account.setTransactions(transactions);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Vasttrafik.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Vasttrafik extends Bank {\n\n    private static final String NAME = \"Västtrafik\";\n\n    private static final String URL = \"https://www.vasttrafik.se/mina-sidor/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.VASTTRAFIK;\n\n    private Pattern reViewState = Pattern.compile(\"__VIEWSTATE\\\"\\\\s+value=\\\"([^\\\"]+)\\\"\");\n\n    private Pattern reAccounts = Pattern\n            .compile(\"<h3 class=\\\"cardName\\\">(.*?)</h3>(.*?)<span class=\\\"isAccount hidden\\\">\",\n                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);\n\n    private Pattern reBalance = Pattern.compile(\n            \"<span class=\\\"chargeType\\\"><span class='col1'>(.*?):</span><span class='col2 boldType'>(.*?)</span></span>\",\n            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);\n\n    private String response = null;\n\n    public Vasttrafik(Context context) {\n        super(context, R.drawable.logo_vasttrafik);\n        super.url = URL;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Vasttrafik(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_vasttrafik));\n        response = urlopen.open(\"https://www.vasttrafik.se/mina-sidor/logga-in/\");\n\n        Matcher matcher = reViewState.matcher(response);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" ViewState.\");\n        }\n        String strViewState = matcher.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"__VIEWSTATE\", strViewState));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$ctl00$SiteRegion$SiteRegion$ContentRegion$MainContentRegion$AddContentRegion$ctl00$TextBoxUserName\",\n                getUsername()));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$ctl00$SiteRegion$SiteRegion$ContentRegion$MainContentRegion$AddContentRegion$ctl00$TextBoxPassword\",\n                getPassword()));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$ctl00$SiteRegion$SiteRegion$ContentRegion$MainContentRegion$AddContentRegion$ctl00$CheckBoxPersistent\",\n                \"on\"));\n        postData.add(new BasicNameValuePair(\n                \"ctl00$ctl00$SiteRegion$SiteRegion$ContentRegion$MainContentRegion$AddContentRegion$ctl00$ButtonLogin\",\n                \"Logga in\"));\n\n        return new LoginPackage(urlopen, postData, response,\n                \"https://www.vasttrafik.se/mina-sidor/logga-in/?ReturnUrl=/mina-sidor-inloggad/mina-kort/\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        if (!response.contains(\"<span class=\\\"loggedInAs\\\">\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        urlopen = login();\n        response = urlopen.open(\"https://www.vasttrafik.se/mina-sidor-inloggad/mina-kort/\");\n        Matcher accountMatcher;\n        Matcher balanceMatcher;\n\n        accountMatcher = reAccounts.matcher(response);\n        while (accountMatcher.find()) {\n            /*\n             * Capture groups:\n             * GROUP                EXAMPLE DATA\n             * 1: Name              Nytt\n             * 2: Balance information\n             */\n\n            if (\"\".equals(accountMatcher.group(1))) {\n                continue;\n            }\n\n            balanceMatcher = reBalance.matcher(accountMatcher.group(2));\n            if (balanceMatcher.find()) {\n                /*\n                 * Capture groups:\n                 * GROUP                EXAMPLE DATA\n                 * 1: Type              Kontoladdning\n                 * 2: Amount            592,80 kr\n                 */\n\n                String balanceString = balanceMatcher.group(2).replaceAll(\"\\\\<a[^>]*>\", \"\")\n                        .replaceAll(\"\\\\<[^>]*>\", \"\").trim();\n\n                accounts.add(new Account(Html.fromHtml(accountMatcher.group(1)).toString().trim(),\n                        Helpers.parseBalance(balanceString), accountMatcher.group(1)));\n                balance = balance.add(Helpers.parseBalance(balanceString));\n            }\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/Zidisha.java",
    "content": "/* Copyright (C) 2012 Nullbyte <http://nullbyte.eu>\n * Zidisha support by Per Wigren <per.wigren@gmail.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Zidisha extends Bank {\n\n    private static final String NAME = \"Zidisha\";\n\n    private static final String URL = \"https://www.zidisha.org/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.ZIDISHA;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_TEXT;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_TEXT;\n\n    private static final String INPUT_HINT_USERNAME = \"Username\";\n\n    private static final boolean STATIC_BALANCE = true;\n\n    String response;\n\n    private Pattern reUserGuess = Pattern\n            .compile(\"<input.*?name=\\\"user_guess\\\" value=\\\"([0-9a-f]+)\\\"\", Pattern.DOTALL);\n\n    private Pattern reAccounts = Pattern.compile(\n            \"Funds uploaded:</td>.*?USD ([^<]+).*Credit Available:.*?USD ([^<]+).*Amount Lent By Me:.*?USD ([^<]+).*Total Impact:.*?USD ([^<]+)\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    public Zidisha(Context context) {\n        super(context, R.drawable.logo_zidisha);\n\n        super.url = URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        super.staticBalance = STATIC_BALANCE;\n        super.currency = \"USD\";\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Zidisha(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_zidisha));\n        urlopen.setAllowCircularRedirects(true);\n        response = urlopen.open(\"https://www.zidisha.org/\");\n        Matcher mUserGuess = reUserGuess.matcher(response);\n        if (!mUserGuess.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" user_guess.\");\n        }\n        String userGuess = mUserGuess.group(1);\n\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        postData.add(new BasicNameValuePair(\"username\", getUsername()));\n        postData.add(new BasicNameValuePair(\"password\", getPassword()));\n        postData.add(new BasicNameValuePair(\"textpassword\", getUsername()));\n        postData.add(new BasicNameValuePair(\"userlogin\", \"\"));\n        postData.add(new BasicNameValuePair(\"user_guess\", userGuess));\n        return new LoginPackage(urlopen, postData, response, \"https://www.zidisha.org/process.php\");\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        response = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n        Matcher matcher;\n        response = urlopen.open(\"https://www.zidisha.org/index.php?p=19\");\n        matcher = reAccounts.matcher(response);\n\n        while (matcher.find()) {\n                        /*\n             * 1: Funds uploaded\n             * 2: Available for withdrawal\n             * 3: Lent by me\n             * 4: Total Impact\n             */\n            Account insattningar = new Account(\"Insättningar\",\n                    Helpers.parseBalance(matcher.group(1)), \"insattningar\");\n            Account tillgangligt = new Account(\"Tillgängligt\",\n                    Helpers.parseBalance(matcher.group(2)), \"tillgangligt\");\n            Account utlanat = new Account(\"Utlånat\", Helpers.parseBalance(matcher.group(3)),\n                    \"utlanat\");\n            Account balans = new Account(\"Påverkan\", Helpers.parseBalance(matcher.group(4)),\n                    \"impact\");\n\n            insattningar.setCurrency(\"USD\");\n            tillgangligt.setCurrency(\"USD\");\n            utlanat.setCurrency(\"USD\");\n            balans.setCurrency(\"USD\");\n\n            accounts.add(insattningar);\n            accounts.add(tillgangligt);\n            accounts.add(utlanat);\n            accounts.add(balans);\n\n            balance = balance.add(Helpers.parseBalance(matcher.group(4)));\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/AmericanExpress.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.americanexpress;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.banks.americanexpress.model.Card;\nimport com.liato.bankdroid.banking.banks.americanexpress.model.LoginRequest;\nimport com.liato.bankdroid.banking.banks.americanexpress.model.LoginResponse;\nimport com.liato.bankdroid.banking.banks.americanexpress.model.TransactionDetails;\nimport com.liato.bankdroid.banking.banks.americanexpress.model.TransactionsResponse;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IAccountTypes;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.protocol.HTTP;\nimport org.joda.time.format.DateTimeFormat;\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class AmericanExpress extends Bank {\n\n    private static final String NAME = \"American Express\";\n\n    private static final int BANKTYPE_ID = IBankTypes.AMERICANEXPRESS;\n\n    private static final ObjectMapper MAPPER = new ObjectMapper();\n\n    @Nullable\n    private LoginResponse loginResponse;\n\n    public AmericanExpress(Context context) {\n        super(context, R.drawable.logo_americanexpress);\n        super.webViewEnabled = false;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public AmericanExpress(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context,\n                R.raw.cert_americanexpress_global));\n        urlopen.setAllowCircularRedirects(true);\n        urlopen.setContentCharset(HTTP.UTF_8);\n        urlopen.addHeader(\"Face\", \"sv_SE\");\n        return new LoginPackage(urlopen, null, null,\n                \"https://global.americanexpress.com/myca/intl/moblclient/emea/svc/v1/loginSummary.do\");\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        loginResponse = parseLoginResponse(urlopen.openAsHttpResponse(\n                lp.getLoginTarget(),\n                new StringEntity(\n                        objectAsJson(new LoginRequest(\n                                getUsername(),\n                                getPassword())),\n                        HTTP.UTF_8),\n                true));\n\n        urlopen.addHeader(\"cupcake\", loginResponse.getLogonData().getCupcake());\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        for (Card card : loginResponse.getCards()) {\n            Account account = asAccount(card);\n            if (card.isTransactionsEnabled()) {\n                account.setTransactions(fetchTransactionsFor(card));\n            }\n            accounts.add(account);\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    private List<Transaction> fetchTransactionsFor(Card card) throws IOException, BankException {\n        HttpResponse response = urlopen.openAsHttpResponse(\n                \"https://global.americanexpress.com/myca/intl/moblclient/emea/svc/v1/transaction.do\",\n                new StringEntity(\"{\" +\n                        \"\\\"billingIndexList\\\": [\\\"0\\\"],\" +\n                        \"\\\"sortedIndex\\\":\" + card.getSortedIndex() +\n                        \"}\",\n                        HTTP.UTF_8), true);\n        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {\n            response.getEntity().consumeContent();\n            throw new BankException(\n                    res.getText(R.string.update_transactions_error).toString());\n        }\n\n        TransactionsResponse details = MAPPER.reader()\n                .withType(TransactionsResponse.class)\n                .readValue(response.getEntity().getContent());\n\n        if (details.getTransactionDetails() == null) {\n            throw new BankException(res.getText(R.string.server_error_try_again).toString());\n        }\n        if (details.getTransactionDetails().getStatus() != 0) {\n            throw new BankException(details.getTransactionDetails().getMessage());\n        }\n\n        return transactionsOf(details.getTransactionDetails());\n    }\n\n    private List<Transaction> transactionsOf(@Nullable TransactionDetails details) {\n        List<Transaction> transactions = new ArrayList<>();\n        if (details != null) {\n            for (com.liato.bankdroid.banking.banks.americanexpress.model.Transaction transaction : details.getTransactions()) {\n                transactions.add(asTransaction(transaction));\n            }\n        }\n        return transactions;\n    }\n\n    private Transaction asTransaction(com.liato.bankdroid.banking.banks.americanexpress.model.Transaction transaction) {\n        return new Transaction(\n                DateTimeFormat.forPattern(\"yyyyMMdd\")\n                        .parseDateTime(\n                                Long.toString(transaction.getChargeDate().getRawValue())\n                        ).toString(\"yyyy-MM-dd\"),\n                transaction.getDescription().get(0),\n                new BigDecimal(transaction.getAmount().getRawValue()).negate()\n        );\n    }\n\n    private Account asAccount(Card card) {\n        Account account = new Account(\n                card.getCardProductName(),\n                card.getBalance(),\n                card.getCardKey());\n        account.setType(IAccountTypes.CCARD);\n        return account;\n    }\n\n    private String objectAsJson(Object value) throws BankException {\n        try {\n            return MAPPER.writeValueAsString(value);\n        } catch (JsonProcessingException e) {\n            throw new BankException(e.getMessage(), e);\n        }\n    }\n\n    private LoginResponse parseLoginResponse(HttpResponse response) throws IOException, BankException {\n        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {\n            response.getEntity().consumeContent();\n            throw new BankException(res.getText(R.string.server_error_try_again).toString());\n        }\n        LoginResponse loginResponse = MAPPER.reader()\n                .withType(LoginResponse.class)\n                .readValue(response.getEntity().getContent());\n        if (loginResponse == null || loginResponse.getLogonData() == null) {\n            throw new BankException(res.getText(R.string.server_error_try_again).toString());\n        }\n        if (loginResponse.getLogonData().getStatus() != 0) {\n            throw new BankException(loginResponse.getLogonData().getMessage());\n        }\n\n        return loginResponse;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/AccountActivity.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java.util.Collections;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class AccountActivity {\n    List<Transaction> transactionList;\n\n    public List<Transaction> getTransactionList() {\n        return transactionList == null ?\n                Collections.<Transaction>emptyList() : transactionList;\n    }\n\n    public void setTransactionList(List<Transaction> transactionList) {\n        this.transactionList = transactionList;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Amount.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Amount {\n    public double getRawValue() {\n        return rawValue;\n    }\n\n    public void setRawValue(double rawValue) {\n        this.rawValue = rawValue;\n    }\n\n    private double rawValue;\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Capabilities.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Capabilities {\n\n    private TransactionCapabilities transactions;\n\n    public TransactionCapabilities getTransactions() {\n        return transactions;\n    }\n\n    public void setTransactions(TransactionCapabilities transactions) {\n        this.transactions = transactions;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Card.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.liato.bankdroid.Helpers;\n\nimport java.math.BigDecimal;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Card {\n    private String cardProductName;\n    private String cardKey;\n    private String cardNumberDisplay;\n    private int sortedIndex;\n\n    private Summary summary;\n    private Capabilities capabilities;\n\n    public String getCardProductName() {\n        return cardProductName;\n    }\n\n    public void setCardProductName(String cardProductName) {\n        this.cardProductName = cardProductName;\n    }\n\n    public String getCardKey() {\n        return cardKey;\n    }\n\n    public void setCardKey(String cardKey) {\n        this.cardKey = cardKey;\n    }\n\n    public String getCardNumberDisplay() {\n        return cardNumberDisplay;\n    }\n\n    public void setCardNumberDisplay(String cardNumberDisplay) {\n        this.cardNumberDisplay = cardNumberDisplay;\n    }\n\n    public Summary getSummary() {\n        return summary;\n    }\n\n    public void setSummary(Summary summary) {\n        this.summary = summary;\n    }\n\n    public Capabilities getCapabilities() {\n        return capabilities;\n    }\n\n    public void setCapabilities(Capabilities capabilities) {\n        this.capabilities = capabilities;\n    }\n\n    public int getSortedIndex() {\n        return sortedIndex;\n    }\n\n    public void setSortedIndex(int sortedIndex) {\n        this.sortedIndex = sortedIndex;\n    }\n\n    public boolean isTransactionsEnabled() {\n        return capabilities != null &&\n                capabilities.getTransactions() != null &&\n                capabilities.getTransactions().isEnabled();\n    }\n\n    public BigDecimal getBalance() {\n        if (summary != null && summary.getTotalBalance() != null) {\n            return Helpers.parseBalance(summary.getTotalBalance().getValue()).negate();\n        }\n        return BigDecimal.ZERO;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Date.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Date {\n    private long rawValue;\n\n    public long getRawValue() {\n        return rawValue;\n    }\n\n    public void setRawValue(long rawValue) {\n        this.rawValue = rawValue;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/LoginRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport org.joda.time.DateTime;\n\npublic class LoginRequest {\n\n    private String user;\n    private String password;\n    private long userTimeStampInMilli;\n\n    public LoginRequest(String username, String password) {\n        this.user = username;\n        this.password = password;\n        userTimeStampInMilli = DateTime.now().getMillis();\n    }\n\n    public String getUser() {\n        return user;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public long getUserTimeStampInMilli() {\n        return userTimeStampInMilli;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/LoginResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\n\nimport android.support.annotation.Nullable;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java.util.Collections;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class LoginResponse {\n\n    private int status;\n\n    @Nullable\n    private LogonData logonData;\n\n    public SummaryData getSummaryData() {\n        return summaryData;\n    }\n\n    public void setSummaryData(SummaryData summaryData) {\n        this.summaryData = summaryData;\n    }\n\n    private SummaryData summaryData;\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public LogonData getLogonData() {\n        return logonData;\n    }\n\n    public void setLogonData(LogonData logonData) {\n        this.logonData = logonData;\n    }\n\n    public List<Card> getCards() {\n        if (summaryData != null && summaryData.getCardList() != null) {\n            return summaryData.getCardList();\n        }\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/LogonData.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class LogonData {\n\n    private int status;\n    private String message;\n    private String cupcake;\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public String getCupcake() {\n        return cupcake;\n    }\n\n    public void setCupcake(String cupcake) {\n        this.cupcake = cupcake;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Summary.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Summary {\n    private TotalBalance totalBalance;\n\n    public TotalBalance getTotalBalance() {\n        return totalBalance;\n    }\n\n    public void setTotalBalance(TotalBalance totalBalance) {\n        this.totalBalance = totalBalance;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/SummaryData.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class SummaryData {\n\n    private int status;\n    private List<Card> cardList;\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public List<Card> getCardList() {\n        return cardList;\n    }\n\n    public void setCardList(List<Card> cardList) {\n        this.cardList = cardList;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/TotalBalance.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class TotalBalance {\n    private String value;\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/Transaction.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Transaction {\n    private Amount amount;\n    private Date chargeDate;\n    private List<String> description;\n\n    public Amount getAmount() {\n        return amount;\n    }\n\n    public void setAmount(Amount amount) {\n        this.amount = amount;\n    }\n\n    public Date getChargeDate() {\n        return chargeDate;\n    }\n\n    public void setChargeDate(Date chargeDate) {\n        this.chargeDate = chargeDate;\n    }\n\n    public List<String> getDescription() {\n        return description;\n    }\n\n    public void setDescription(List<String> description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/TransactionCapabilities.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class TransactionCapabilities {\n        private boolean enabled;\n\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/TransactionDetails.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class TransactionDetails {\n    private long status;\n    private String message;\n\n    private List<AccountActivity> activityList;\n\n    public long getStatus() {\n        return status;\n    }\n\n    public void setStatus(long status) {\n        this.status = status;\n    }\n\n    public List<AccountActivity> getActivityList() {\n        return activityList;\n    }\n\n    public void setActivityList(List<AccountActivity> activityList) {\n        this.activityList = activityList;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public List<Transaction> getTransactions() {\n        if (activityList != null) {\n            List<Transaction> transactions = new ArrayList<>();\n            for (AccountActivity activity : activityList) {\n                transactions.addAll(activity.getTransactionList());\n            }\n            return transactions;\n        }\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/americanexpress/model/TransactionsResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.americanexpress.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class TransactionsResponse {\n\n    private TransactionDetails transactionDetails;\n\n    public TransactionDetails getTransactionDetails() {\n        return transactionDetails;\n    }\n\n    public void setTransactionDetails(TransactionDetails transactionDetails) {\n        this.transactionDetails = transactionDetails;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/Bitcoin.java",
    "content": "/*\n * Copyright (C) 2013 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.bitcoin;\n\nimport com.fasterxml.jackson.core.JsonParseException;\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.banks.bitcoin.model.BlockchainResponse;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport android.content.Context;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.text.DecimalFormat;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Bitcoin extends Bank {\n\n    private static final String NAME = \"Bitcoin\";\n\n    private static final String URL = \"http://blockchain.info\";\n\n    private static final int BANKTYPE_ID = IBankTypes.BITCOIN;\n\n    private static final boolean STATIC_BALANCE = false;\n\n    private static final boolean INPUT_HIDDEN_PASSWORD = true;\n\n    private static final int INPUT_TITLETEXT_USERNAME = R.string.bitcoin_address;\n\n    private static final String API_URL = \"http://blockchain.info/rawaddr/\";\n\n    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat(\"#,##0.00000000 \");\n\n    public Bitcoin(Context context) {\n        super(context, R.drawable.logo_bitcoin);\n\n        super.url = URL;\n        super.staticBalance = STATIC_BALANCE;\n        super.currency = \"BTC\";\n        super.inputHiddenPassword = INPUT_HIDDEN_PASSWORD;\n        super.inputTitletextUsername = INPUT_TITLETEXT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Bitcoin(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        urlopen = new Urllib(context);\n\n        try {\n            String response = urlopen.open(API_URL + getUsername());\n            if (response == null || \"\".equals(response)) {\n                throw new LoginException(res.getText(\n                        R.string.invalid_username_password).toString());\n            }\n            ObjectMapper vObjectMapper = new ObjectMapper();\n            vObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);\n            vObjectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);\n            BlockchainResponse r = vObjectMapper.readValue(\n                    urlopen.open(API_URL + getUsername()), BlockchainResponse.class);\n            Account a = new Account(\"Bitcoin\",\n                    new BigDecimal(r.getFinalBalance()).divide(BigDecimal.valueOf(100000000)), \"1\");\n            a.setCurrency(\"BTC\");\n            accounts.add(a);\n            setCurrency(\"BTC\");\n        } catch (JsonParseException e) {\n            throw new BankException(res.getText(\n                    R.string.invalid_bitcoin_address).toString(), e);\n        }\n\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException,\n            BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty()) {\n            throw new LoginException(res.getText(\n                    R.string.invalid_bitcoin_address).toString());\n        }\n        login();\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public DecimalFormat getDecimalFormatter() {\n        return DECIMAL_FORMAT;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/model/BlockchainResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.bitcoin.model;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.io.Serializable;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class BlockchainResponse implements Serializable {\n\n    private static final long serialVersionUID = -5144109898538621019L;\n\n    @JsonProperty(\"total_sent\")\n    private long mTotalSent;\n\n    @JsonProperty(\"total_received\")\n    private long mTotalReceived;\n\n    @JsonProperty(\"final_balance\")\n    private long mFinalBalance;\n\n    @JsonProperty(\"address\")\n    private String mAddress;\n\n    @JsonProperty(\"hash160\")\n    private String mHash160;\n\n    @JsonProperty(\"txs\")\n    private List<Transfer> mTxs = Collections.emptyList();\n\n    @JsonProperty(\"n_tx\")\n    private long mNTx;\n\n    @JsonProperty(\"total_sent\")\n    public long getTotalSent() {\n        return mTotalSent;\n    }\n\n    @JsonProperty(\"total_received\")\n    public long getTotalReceived() {\n        return mTotalReceived;\n    }\n\n    @JsonProperty(\"final_balance\")\n    public long getFinalBalance() {\n        return mFinalBalance;\n    }\n\n    @JsonProperty(\"address\")\n    public String getAddress() {\n        return mAddress;\n    }\n\n    @JsonProperty(\"hash160\")\n    public String getHash160() {\n        return mHash160;\n    }\n\n    @JsonProperty(\"txs\")\n    public List<Transfer> getTxs() {\n        return mTxs;\n    }\n\n    @JsonProperty(\"n_tx\")\n    public long getNTx() {\n        return mNTx;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/model/Input.java",
    "content": "package com.liato.bankdroid.banking.banks.bitcoin.model;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.io.Serializable;\n\npublic class Input implements Serializable {\n\n    private static final long serialVersionUID = 7507419745749485877L;\n\n    @JsonProperty(\"prev_out\")\n    private PrevOut mPrevOut;\n\n    @JsonProperty(\"prev_out\")\n    public PrevOut getPrevOut() {\n        return mPrevOut;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/model/Out.java",
    "content": "package com.liato.bankdroid.banking.banks.bitcoin.model;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.io.Serializable;\n\npublic class Out implements Serializable {\n\n    private static final long serialVersionUID = 3773393008409837454L;\n\n    @JsonProperty(\"tx_index\")\n    private long mTxIndex;\n\n    @JsonProperty(\"type\")\n    private int mType;\n\n    @JsonProperty(\"addr\")\n    private String mAddr;\n\n    @JsonProperty(\"value\")\n    private long mValue;\n\n    @JsonProperty(\"n\")\n    private long mN;\n\n    @JsonProperty(\"tx_index\")\n    public long getTxIndex() {\n        return mTxIndex;\n    }\n\n    @JsonProperty(\"type\")\n    public int getType() {\n        return mType;\n    }\n\n    @JsonProperty(\"addr\")\n    public String getAddr() {\n        return mAddr;\n    }\n\n    @JsonProperty(\"value\")\n    public long getValue() {\n        return mValue;\n    }\n\n    @JsonProperty(\"n\")\n    public long getN() {\n        return mN;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/model/PrevOut.java",
    "content": "package com.liato.bankdroid.banking.banks.bitcoin.model;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.io.Serializable;\n\npublic class PrevOut implements Serializable {\n\n    private static final long serialVersionUID = 9102767809232718841L;\n\n    @JsonProperty(\"tx_index\")\n    private long mTxIndex;\n\n    @JsonProperty(\"type\")\n    private int mType;\n\n    @JsonProperty(\"addr\")\n    private String mAddr;\n\n    @JsonProperty(\"value\")\n    private long mValue;\n\n    @JsonProperty(\"n\")\n    private long mN;\n\n    @JsonProperty(\"tx_index\")\n    public long getTxIndex() {\n        return mTxIndex;\n    }\n\n    @JsonProperty(\"type\")\n    public int getType() {\n        return mType;\n    }\n\n    @JsonProperty(\"addr\")\n    public String getAddr() {\n        return mAddr;\n    }\n\n    @JsonProperty(\"value\")\n    public long getValue() {\n        return mValue;\n    }\n\n    @JsonProperty(\"n\")\n    public long getN() {\n        return mN;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/bitcoin/model/Transfer.java",
    "content": "package com.liato.bankdroid.banking.banks.bitcoin.model;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.io.Serializable;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class Transfer implements Serializable {\n\n    private static final long serialVersionUID = -2558362412750999606L;\n\n    @JsonProperty(\"size\")\n    private long mSize;\n\n    @JsonProperty(\"inputs\")\n    private List<Input> mInputs = Collections.emptyList();\n\n    @JsonProperty(\"hash\")\n    private String mHash;\n\n    @JsonProperty(\"tx_index\")\n    private long mTxIndex;\n\n    @JsonProperty(\"relayed_by\")\n    private String mRelayedBy;\n\n    @JsonProperty(\"block_height\")\n    private long mBlockHeight;\n\n    @JsonProperty(\"vin_sz\")\n    private long mVinSz;\n\n    @JsonProperty(\"vout_sz\")\n    private long mVoutSz;\n\n    @JsonProperty(\"time\")\n    private long mTime;\n\n    @JsonProperty(\"ver\")\n    private long mVer;\n\n    @JsonProperty(\"out\")\n    private List<Out> mOut = Collections.emptyList();\n\n    @JsonProperty(\"result\")\n    private long mResult;\n\n    @JsonProperty(\"note\")\n    private String mNote;\n\n\n    @JsonProperty(\"size\")\n    public long getSize() {\n        return mSize;\n    }\n\n    @JsonProperty(\"inputs\")\n    public List<Input> getInputs() {\n        return mInputs;\n    }\n\n    @JsonProperty(\"hash\")\n    public String getHash() {\n        return mHash;\n    }\n\n    @JsonProperty(\"tx_index\")\n    public long getTxIndex() {\n        return mTxIndex;\n    }\n\n    @JsonProperty(\"relayed_by\")\n    public String getRelayedBy() {\n        return mRelayedBy;\n    }\n\n    @JsonProperty(\"block_height\")\n    public long getBlockHeight() {\n        return mBlockHeight;\n    }\n\n    @JsonProperty(\"vin_sz\")\n    public long getVinSz() {\n        return mVinSz;\n    }\n\n    @JsonProperty(\"vout_sz\")\n    public long getVoutSz() {\n        return mVoutSz;\n    }\n\n    @JsonProperty(\"time\")\n    public long getTime() {\n        return mTime;\n    }\n\n    @JsonProperty(\"ver\")\n    public long getVer() {\n        return mVer;\n    }\n\n    @JsonProperty(\"out\")\n    public List<Out> getOut() {\n        return mOut;\n    }\n\n    @JsonProperty(\"result\")\n    public long getResult() {\n        return mResult;\n    }\n\n    @JsonProperty(\"note\")\n    public String getNote() {\n        return mNote;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/coop/Coop.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.coop;\n\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.banks.coop.model.web.Result;\nimport com.liato.bankdroid.banking.banks.coop.model.web.WebTransactionHistoryResponse;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.entity.StringEntity;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Coop extends Bank {\n\n    private static final String NAME = \"Coop\";\n\n    private static final String URL = \"https://www.coop.se/mina-sidor/oversikt/\";\n\n    private static final int BANKTYPE_ID = IBankTypes.COOP;\n\n    private static final Map<String, String> MONTHS = new HashMap<>();\n\n    static {\n        String[] ms = new String[]{\"januari\", \"februari\", \"mars\", \"april\", \"maj\", \"juni\", \"juli\",\n                \"augusti\", \"september\", \"oktober\", \"november\", \"december\"};\n        for (int i = 0; i < ms.length; i++) {\n            MONTHS.put(ms[i], String.format(\"%02d\", i + 1));\n        }\n    }\n\n    private final Pattern rePageGuid = Pattern\n            .compile(\"pageGuid\\\"\\\\s*:\\\\s*\\\"([^\\\"]+)\", Pattern.CASE_INSENSITIVE);\n\n    private final Map<AccountType, TransactionParams> mTransactionParams = new HashMap<>();\n\n    private ObjectMapper mObjectMapper;\n\n    public Coop(Context context) {\n        super(context, R.drawable.logo_coop);\n\n        super.url = URL;\n        super.staticBalance = true;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Coop(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException,\n            IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_coop));\n\n        String response = urlopen.open(\"https://www.coop.se\");\n        Document dResponse = Jsoup.parse(response);\n        String token = dResponse.select(\"[name=token]\").attr(\"value\");\n\n        urlopen.addHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n        HttpResponse httpResponse = urlopen\n                .openAsHttpResponse(\"https://www.coop.se/Personliga-Baren/Logga-in/?method=Login\",\n                        new StringEntity(\"{\\\"isBar\\\":\\\"true\\\",\\\"token\\\":\\\"\" + token\n                                 + \"\\\",\\\"username\\\":\\\"\" + getUsername()\n                                + \"\\\",\\\"password\\\":\\\"\" + getPassword() + \"\\\"}\"),\n                        true);\n        urlopen.removeHeader(\"X-Requested-With\");\n        LoginPackage lp = new LoginPackage(urlopen, null, response,\n                \"https://www.coop.se/Mina-sidor/Oversikt/\");\n        if (httpResponse.getStatusLine().getStatusCode() == 200) {\n            lp.setIsLoggedIn(true);\n        }\n        return lp;\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        if (!lp.isLoggedIn()) {\n            throw new LoginException(res.getString(R.string.invalid_username_password));\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        login();\n\n        String response = urlopen.open(\"https://www.coop.se/Mina-sidor/Oversikt/Mina-poang/\");\n        Document dResponse = Jsoup.parse(response);\n        Account poang = new Account(\"\\u2014  Poäng\",\n                Helpers.parseBalance(dResponse.select(\".Grid-cell--1 p\").text()),\n                \"poang\", Account.OTHER, \"\");\n        List<Transaction> transactions = new ArrayList<>();\n        poang.setTransactions(transactions);\n        for (Element e : dResponse.select(\".Timeline-item\")) {\n            try {\n                if (e.parent().hasClass(\"Timeline-group--emphasized\")) {\n                    transactions.add(new Transaction(\n                            formatDate(e.ownText()),\n                            e.select(\".Timeline-label\").text(),\n                            Helpers.parseBalance(e.select(\".Timeline-title\").first().text()), \"\"));\n\n                } else {\n                    transactions.add(new Transaction(\n                            formatDate(e.select(\".Timeline-header .u-nbfcAlt span\").text()),\n                            e.select(\".u-block\").text(),\n                            Helpers.parseBalance(\n                                    e.select(\".Timeline-header .Timeline-title\").first().ownText()),\n                            \"\"));\n                }\n            } finally {\n                continue;\n            }\n        }\n        accounts.add(poang);\n        for (AccountType at : AccountType.values()) {\n            response = urlopen.open(at.getUrl());\n            Document d = Jsoup.parse(response);\n            Elements historik = d.select(\"#historik section\");\n            TransactionParams params = new TransactionParams();\n            mTransactionParams.put(at, params);\n            if (historik != null && !historik.isEmpty()) {\n                String data = historik.first().attr(\"data-controller\");\n                Matcher m = rePageGuid.matcher(data);\n                if (m.find()) {\n                    params.setPageGuid(m.group(1));\n                }\n            }\n            Element date = d.getElementById(\"dateFrom\");\n            if (date != null) {\n                params.setMinDate(date.hasAttr(\"min\") ? date.attr(\"min\") : null);\n                params.setMaxDate(date.hasAttr(\"max\") ? date.attr(\"max\") : null);\n            }\n            Elements es = d.select(\".List:contains(Saldo)\");\n            if (es != null && !es.isEmpty()) {\n                List<String> names = new ArrayList<>();\n                List<String> values = new ArrayList<>();\n                for (Element e : es.first().select(\"dt\")) {\n                    names.add(e.text().replaceAll(\":\", \"\").trim());\n                }\n                for (Element e : es.first().select(\"dd\")) {\n                    values.add(e.text().trim());\n                }\n                for (int i = 0; i < Math.min(names.size(), values.size()); i++) {\n                    Account a = new Account(names.get(i), Helpers.parseBalance(values.get(i)),\n                            String.format(\"%s%d\", at.getPrefix(), i));\n                    a.setCurrency(Helpers.parseCurrency(values.get(i), \"SEK\"));\n                    if (a.getName().toLowerCase().contains(\"disponibelt\")) {\n                        a.setType(Account.REGULAR);\n                        balance = a.getBalance();\n                        setCurrency(a.getCurrency());\n                    } else {\n                        a.setType(Account.OTHER);\n                    }\n\n                    if (i > 0) {\n                        a.setAliasfor(String.format(\"%s%d\", at.getPrefix(), 0));\n                    }\n                    accounts.add(a);\n                }\n            }\n        }\n\n        response = urlopen\n                .open(\"https://www.coop.se/Mina-sidor/Oversikt/Information-om-aterbaringen/\");\n        dResponse = Jsoup.parse(response);\n        Elements refound = dResponse.select(\".Heading--coopNew\");\n        if (refound.hasText()) {\n            BigDecimal balance = Helpers.parseBalance(refound.text());\n            if (balance.compareTo(BigDecimal.ZERO) >= 0) {\n                Account a = new Account(\"Återbäring\", balance, \"refound\", Account.OTHER, \"SEK\");\n                accounts.add(a);\n            }\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    private ObjectMapper getObjectmapper() {\n        if (mObjectMapper == null) {\n            mObjectMapper = new ObjectMapper();\n            mObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);\n            mObjectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);\n        }\n        return mObjectMapper;\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen)\n            throws LoginException, BankException, IOException {\n        AccountType at = getAccuntType(account.getId());\n        TransactionParams tp = mTransactionParams.get(at);\n        if (at == null || tp == null || !tp.isValid() || !isFirstAccountForType(account.getId())) {\n            return;\n        }\n\n        String data = URLEncoder.encode(String\n                .format(\"{\\\"page\\\":1,\\\"pageSize\\\":15,\\\"from\\\":\\\"%s\\\",\\\"to\\\":\\\"%s\\\"}\",\n                        tp.getMinDate(), tp.getMaxDate()), \"utf-8\");\n        String url = String\n                .format(\"https://www.coop.se/Services/PlainService.svc/JsonExecuteGet?pageGuid=%s&method=GetTransactions&data=%s&_=%s\",\n                        tp.getPageGuid(), data, System.currentTimeMillis());\n        WebTransactionHistoryResponse transactionsResponse = getObjectmapper()\n                .readValue(urlopen.openStream(url), WebTransactionHistoryResponse.class);\n        if (transactionsResponse != null && transactionsResponse.getModel() != null) {\n            List<Transaction> transactions = new ArrayList<>();\n            account.setTransactions(transactions);\n            for (Result r : transactionsResponse.getModel().getResults()) {\n                StringBuilder title = new StringBuilder(\n                        !TextUtils.isEmpty(r.getLocation()) ? r.getLocation() : r.getTitle());\n                if (!TextUtils.isEmpty(r.getCardholder())) {\n                    title.append(\" (\").append(r.getCardholder()).append(\")\");\n                }\n                if (r.getDate() != null) {\n                    transactions.add(new Transaction(formatDate(r.getDate()), title.toString(),\n                            BigDecimal.valueOf(r.getSum())));\n                }\n            }\n        }\n    }\n\n    private String formatDate(String date) {\n        String[] parts = date.split(\" \");\n        if (parts.length < 3) {\n            return \"\";\n        }\n        return String.format(\"%s-%s-%02d\", parts[2],\n                MONTHS.containsKey(parts[1].toLowerCase()) ? MONTHS.get(parts[1].toLowerCase())\n                        : \"01\", Integer.parseInt(parts[0]));\n    }\n\n    private boolean isFirstAccountForType(String accountId) {\n        for (AccountType at : AccountType.values()) {\n            if (accountId.equals(String.format(\"%s%d\", at.getPrefix(), 0))) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private AccountType getAccuntType(String accountId) {\n        for (AccountType at : AccountType.values()) {\n            if (accountId.startsWith(at.getPrefix())) {\n                return at;\n            }\n        }\n        return null;\n    }\n\n    enum AccountType {\n        MEDMERA_KONTO(\"konto_\", \"https://www.coop.se/Mina-sidor/Oversikt/MedMera-Konto/\"),\n        MEDMERA_EFTER(\"efter_\",\n                \"https://www.coop.se/Mina-sidor/Oversikt/Kontoutdrag-MedMera-Efter/\"),\n        MEDMERA_EFTER1(\"efter1_\",\n                \"https://www.coop.se/Mina-sidor/Oversikt/Kontoutdrag-MedMera-Efter1/\"),\n        MEDMERA_FORE(\"fore_\", \"https://www.coop.se/Mina-sidor/Oversikt/Kontoutdrag-MedMera-Fore/\"),\n        MEDMERA_MER(\"mer_\", \"https://www.coop.se/Mina-sidor/Oversikt/Kontoutdrag-MedMera-Mer/\"),\n        MEDMERA_VISA(\"visa_\", \"https://www.coop.se/Mina-sidor/Oversikt/Kontoutdrag-MedMera-Visa/\");\n\n        final String prefix;\n\n        final String url;\n\n        private AccountType(String prefix, String url) {\n            this.prefix = prefix;\n            this.url = url;\n        }\n\n        public String getPrefix() {\n            return prefix;\n        }\n\n        public String getUrl() {\n            return url;\n        }\n    }\n\n    class TransactionParams {\n\n        String pageGuid;\n\n        String minDate;\n\n        String maxDate;\n\n        public String getPageGuid() {\n            return pageGuid;\n        }\n\n        public void setPageGuid(String pageGuid) {\n            this.pageGuid = pageGuid;\n        }\n\n        public String getMinDate() {\n            return minDate;\n        }\n\n        public void setMinDate(String minDate) {\n            this.minDate = minDate;\n        }\n\n        public String getMaxDate() {\n            return maxDate;\n        }\n\n        public void setMaxDate(String maxDate) {\n            this.maxDate = maxDate;\n        }\n\n        public boolean isValid() {\n            return pageGuid != null && minDate != null && maxDate != null;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/coop/model/web/D.java",
    "content": "package com.liato.bankdroid.banking.banks.coop.model.web;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class D {\n\n    @JsonProperty(\"template\")\n    private String template;\n\n    @JsonProperty(\"model\")\n    private Model model;\n\n    @JsonProperty(\"template\")\n    public String getTemplate() {\n        return template;\n    }\n\n    @JsonProperty(\"template\")\n    public void setTemplate(String template) {\n        this.template = template;\n    }\n\n    @JsonProperty(\"model\")\n    public Model getModel() {\n        return model;\n    }\n\n    @JsonProperty(\"model\")\n    public void setModel(Model model) {\n        this.model = model;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/coop/model/web/Model.java",
    "content": "package com.liato.bankdroid.banking.banks.coop.model.web;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Model {\n\n    @JsonProperty(\"results\")\n    private List<Result> results = new ArrayList<Result>();\n\n    @JsonProperty(\"from\")\n    private String from;\n\n    @JsonProperty(\"to\")\n    private String to;\n\n    @JsonProperty(\"id\")\n    private String id;\n\n    @JsonProperty(\"page\")\n    private int page;\n\n    @JsonProperty(\"pageCount\")\n    private int pageCount;\n\n    @JsonProperty(\"pageSize\")\n    private int pageSize;\n\n    @JsonProperty(\"results\")\n    public List<Result> getResults() {\n        return results;\n    }\n\n    @JsonProperty(\"results\")\n    public void setResults(List<Result> results) {\n        this.results = results;\n    }\n\n    @JsonProperty(\"from\")\n    public String getFrom() {\n        return from;\n    }\n\n    @JsonProperty(\"from\")\n    public void setFrom(String from) {\n        this.from = from;\n    }\n\n    @JsonProperty(\"to\")\n    public String getTo() {\n        return to;\n    }\n\n    @JsonProperty(\"to\")\n    public void setTo(String to) {\n        this.to = to;\n    }\n\n    @JsonProperty(\"id\")\n    public String getId() {\n        return id;\n    }\n\n    @JsonProperty(\"id\")\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    @JsonProperty(\"page\")\n    public int getPage() {\n        return page;\n    }\n\n    @JsonProperty(\"page\")\n    public void setPage(int page) {\n        this.page = page;\n    }\n\n    @JsonProperty(\"pageCount\")\n    public int getPageCount() {\n        return pageCount;\n    }\n\n    @JsonProperty(\"pageCount\")\n    public void setPageCount(int pageCount) {\n        this.pageCount = pageCount;\n    }\n\n    @JsonProperty(\"pageSize\")\n    public int getPageSize() {\n        return pageSize;\n    }\n\n    @JsonProperty(\"pageSize\")\n    public void setPageSize(int pageSize) {\n        this.pageSize = pageSize;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/coop/model/web/Result.java",
    "content": "package com.liato.bankdroid.banking.banks.coop.model.web;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Result {\n\n    @JsonProperty(\"date\")\n    private String date;\n\n    @JsonProperty(\"icon\")\n    private boolean icon;\n\n    @JsonProperty(\"title\")\n    private String title;\n\n    @JsonProperty(\"cardholder\")\n    private String cardholder;\n\n    @JsonProperty(\"location\")\n    private String location;\n\n    @JsonProperty(\"sum\")\n    private double sum;\n\n    @JsonProperty(\"charity\")\n    private boolean charity;\n\n    @JsonProperty(\"hasdetails\")\n    private boolean hasdetails;\n\n    @JsonProperty(\"detailsurl\")\n    private String detailsurl;\n\n    @JsonProperty(\"batchnumber\")\n    private int batchnumber;\n\n    @JsonProperty(\"sequencenumber\")\n    private int sequencenumber;\n\n    @JsonProperty(\"date\")\n    public String getDate() {\n        return date;\n    }\n\n    @JsonProperty(\"date\")\n    public void setDate(String date) {\n        this.date = date;\n    }\n\n    @JsonProperty(\"icon\")\n    public boolean getIcon() {\n        return icon;\n    }\n\n    @JsonProperty(\"icon\")\n    public void setIcon(boolean icon) {\n        this.icon = icon;\n    }\n\n    @JsonProperty(\"title\")\n    public String getTitle() {\n        return title;\n    }\n\n    @JsonProperty(\"title\")\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    @JsonProperty(\"cardholder\")\n    public String getCardholder() {\n        return cardholder;\n    }\n\n    @JsonProperty(\"cardholder\")\n    public void setCardholder(String cardholder) {\n        this.cardholder = cardholder;\n    }\n\n    @JsonProperty(\"location\")\n    public String getLocation() {\n        return location;\n    }\n\n    @JsonProperty(\"location\")\n    public void setLocation(String location) {\n        this.location = location;\n    }\n\n    @JsonProperty(\"sum\")\n    public double getSum() {\n        return sum;\n    }\n\n    @JsonProperty(\"sum\")\n    public void setSum(double sum) {\n        this.sum = sum;\n    }\n\n    @JsonProperty(\"charity\")\n    public boolean getCharity() {\n        return charity;\n    }\n\n    @JsonProperty(\"charity\")\n    public void setCharity(boolean charity) {\n        this.charity = charity;\n    }\n\n    @JsonProperty(\"hasdetails\")\n    public boolean getHasdetails() {\n        return hasdetails;\n    }\n\n    @JsonProperty(\"hasdetails\")\n    public void setHasdetails(boolean hasdetails) {\n        this.hasdetails = hasdetails;\n    }\n\n    @JsonProperty(\"detailsurl\")\n    public String getDetailsurl() {\n        return detailsurl;\n    }\n\n    @JsonProperty(\"detailsurl\")\n    public void setDetailsurl(String detailsurl) {\n        this.detailsurl = detailsurl;\n    }\n\n    @JsonProperty(\"batchnumber\")\n    public int getBatchnumber() {\n        return batchnumber;\n    }\n\n    @JsonProperty(\"batchnumber\")\n    public void setBatchnumber(int batchnumber) {\n        this.batchnumber = batchnumber;\n    }\n\n    @JsonProperty(\"sequencenumber\")\n    public int getSequencenumber() {\n        return sequencenumber;\n    }\n\n    @JsonProperty(\"sequencenumber\")\n    public void setSequencenumber(int sequencenumber) {\n        this.sequencenumber = sequencenumber;\n    }\n\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/coop/model/web/WebTransactionHistoryResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.coop.model.web;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class WebTransactionHistoryResponse {\n\n    @JsonProperty(\"d\")\n    private D d;\n\n    @JsonProperty(\"d\")\n    public D getD() {\n        return d;\n    }\n\n    @JsonProperty(\"d\")\n    public void setD(D d) {\n        this.d = d;\n    }\n\n    public Model getModel() {\n        return this.d != null ? this.d.getModel() : null;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/ICA.java",
    "content": "/*\n * Copyright (C) 2014 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.ica;\n\nimport com.fasterxml.jackson.core.JsonParseException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.banks.ica.model.LoginError;\nimport com.liato.bankdroid.banking.banks.ica.model.Overview;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\nimport com.liato.bankdroid.utils.StringUtils;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\n\nimport android.content.Context;\nimport android.text.InputType;\nimport android.text.TextUtils;\nimport android.util.Base64;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class ICA extends Bank {\n\n    private static final String API_URL = \"https://api.ica.se/api/\";\n\n    private static final String AUTHENTICATION_TICKET_HEADER = \"AuthenticationTicket\";\n\n    private static final String SESSION_TICKET_HEADER = \"SessionTicket\";\n\n    private static final String LOGOUT_KEY_HEADER = \"LogoutKey\";\n\n    private ObjectMapper mObjectMapper = new ObjectMapper();\n\n    private Map<String, String> mHeaders = new HashMap<String, String>();\n\n    public ICA(Context context) {\n        super(context, R.drawable.logo_ica);\n        url = \"http://mobil.ica.se/\";\n        inputTypeUsername = InputType.TYPE_CLASS_PHONE;\n        inputTypePassword = InputType.TYPE_CLASS_PHONE;\n        inputHintUsername = \"ÅÅMMDDXXXX\";\n        mHeaders.put(AUTHENTICATION_TICKET_HEADER, null);\n        mHeaders.put(SESSION_TICKET_HEADER, null);\n        mHeaders.put(LOGOUT_KEY_HEADER, null);\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return IBankTypes.ICA;\n    }\n\n    @Override\n    public String getName() {\n        return \"ICA\";\n    }\n\n    public ICA(String username, String password, Context context)\n            throws BankException, LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        urlopen = new Urllib(context, CertificateReader.getCertificates(context, R.raw.cert_ica));\n        urlopen.addHeader(\"Accept\", \"application/json;charset=UTF-8\");\n        urlopen.addHeader(\"Content-Type\", \"application/json;charset=UTF-8\");\n        urlopen.addHeader(\"Authorization\", \"Basic \" + Base64.encodeToString(\n                StringUtils.getBytes(getUsername() + \":\" + getPassword()), Base64.NO_WRAP));\n\n        try {\n            HttpResponse httpResponse = urlopen.openAsHttpResponse(API_URL + \"login\",\n                    new ArrayList<NameValuePair>(), false);\n            if (httpResponse.getStatusLine().getStatusCode() == 401) {\n                LoginError le = readJsonValue(httpResponse, LoginError.class);\n                if (le != null && \"UsernamePassword\".equals(le.getMessageCode())) {\n                    if (!TextUtils.isEmpty(le.getMessage())) {\n                        throw new LoginException(le.getMessage());\n                    } else {\n                        throw new LoginException(context.getText(\n                                R.string.invalid_username_password).toString());\n                    }\n                } else {\n                    throw new BankException(context.getText(\n                            R.string.invalid_username_password).toString());\n                }\n            }\n\n            for (Map.Entry<String, String> entry : mHeaders.entrySet()) {\n                Header header = httpResponse.getFirstHeader(entry.getKey());\n                if (header == null || TextUtils.isEmpty(header.getValue())) {\n                    throw new BankException(context.getString(\n                            R.string.unable_to_find).toString() + \" \" + entry.getKey());\n                }\n                mHeaders.put(entry.getKey(), header.getValue());\n            }\n\n            urlopen.addHeader(AUTHENTICATION_TICKET_HEADER,\n                    mHeaders.get(AUTHENTICATION_TICKET_HEADER));\n            httpResponse = urlopen.openAsHttpResponse(API_URL + \"user/minasidor\",\n                    new ArrayList<NameValuePair>(), false);\n            Overview overview = readJsonValue(httpResponse, Overview.class);\n\n            if (overview == null) {\n                throw new BankException(context.getString(R.string.unable_to_find) + \" overview.\");\n            }\n\n            if (!TextUtils.isEmpty(overview.getAccountName())) {\n                Account account = new Account(overview.getAccountName(),\n                        BigDecimal.valueOf(overview.getAvailableAmount()),\n                        overview.getAccountNumber());\n                balance = balance.add(account.getBalance());\n                accounts.add(account);\n                List<Transaction> transactions = new ArrayList<Transaction>();\n                for (com.liato.bankdroid.banking.banks.ica.model.Transaction t : overview\n                        .getTransactions()) {\n                    transactions.add(new Transaction(t.getTransactionDate(), t.getDescription(),\n                            BigDecimal.valueOf(t.getAmount())));\n                }\n                account.setTransactions(transactions);\n            }\n            for (com.liato.bankdroid.banking.banks.ica.model.Account a : overview.getAccounts()) {\n                Account account = new Account(a.getName(),\n                        BigDecimal.valueOf(a.getAvailableAmount()), a.getAccountNumber());\n                balance = balance.add(account.getBalance());\n                accounts.add(account);\n                List<Transaction> transactions = new ArrayList<Transaction>();\n                for (com.liato.bankdroid.banking.banks.ica.model.Transaction t : a\n                        .getTransactions()) {\n                    transactions.add(new Transaction(t.getTransactionDate(), t.getDescription(),\n                            BigDecimal.valueOf(t.getAmount())));\n                }\n                account.setTransactions(transactions);\n            }\n\n            Account account = new Account(\"Erhållen bonus i år\",\n                    BigDecimal.valueOf(overview.getAcquiredBonus()), \"bonus\");\n            account.setType(Account.OTHER);\n            accounts.add(account);\n            account = new Account(\"Årets totala inköp på ICA\",\n                    BigDecimal.valueOf(overview.getYearlyTotalPurchased()), \"totalpurchased\");\n            account.setType(Account.OTHER);\n            accounts.add(account);\n\n            if (accounts.isEmpty()) {\n                throw new BankException(res.getText(R.string.no_accounts_found).toString());\n            }\n\n            urlopen.addHeader(LOGOUT_KEY_HEADER, mHeaders.get(LOGOUT_KEY_HEADER));\n            httpResponse = urlopen.openAsHttpResponse(API_URL + \"logout\",\n                    new ArrayList<NameValuePair>(), false);\n            httpResponse.getStatusLine();\n        } catch (JsonParseException e) {\n            throw new BankException(e.getMessage(), e);\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException,\n            BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(\n                    R.string.invalid_username_password).toString());\n        }\n        login();\n        super.updateComplete();\n    }\n\n    private <T> T readJsonValue(HttpResponse response, Class<T> valueType) throws BankException {\n        try {\n            return readJsonValue(response.getEntity().getContent(), valueType);\n        } catch (IOException e) {\n            return null;\n        }\n    }\n\n    private <T> T readJsonValue(InputStream is, Class<T> valueType) throws BankException {\n        try {\n            return mObjectMapper.readValue(is, valueType);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/model/Account.java",
    "content": "package com.liato.bankdroid.banking.banks.ica.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Account {\n\n    @JsonProperty(\"Name\")\n    private String name;\n\n    @JsonProperty(\"AccountNumber\")\n    private String accountNumber;\n\n    @JsonProperty(\"AvailableAmount\")\n    private double availableAmount;\n\n    @JsonProperty(\"ReservedAmount\")\n    private double reservedAmount;\n\n    @JsonProperty(\"Saldo\")\n    private double saldo;\n\n    @JsonProperty(\"CreditLimit\")\n    private double creditLimit;\n\n    @JsonProperty(\"Transactions\")\n    private List<Transaction> transactions = new ArrayList<>();\n\n    @JsonProperty(\"Name\")\n    public String getName() {\n        return name;\n    }\n\n    @JsonProperty(\"Name\")\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @JsonProperty(\"AccountNumber\")\n    public String getAccountNumber() {\n        return accountNumber;\n    }\n\n    @JsonProperty(\"AccountNumber\")\n    public void setAccountNumber(String accountNumber) {\n        this.accountNumber = accountNumber;\n    }\n\n    @JsonProperty(\"AvailableAmount\")\n    public double getAvailableAmount() {\n        return availableAmount;\n    }\n\n    @JsonProperty(\"AvailableAmount\")\n    public void setAvailableAmount(double availableAmount) {\n        this.availableAmount = availableAmount;\n    }\n\n    @JsonProperty(\"ReservedAmount\")\n    public double getReservedAmount() {\n        return reservedAmount;\n    }\n\n    @JsonProperty(\"ReservedAmount\")\n    public void setReservedAmount(double reservedAmount) {\n        this.reservedAmount = reservedAmount;\n    }\n\n    @JsonProperty(\"Saldo\")\n    public double getSaldo() {\n        return saldo;\n    }\n\n    @JsonProperty(\"Saldo\")\n    public void setSaldo(double saldo) {\n        this.saldo = saldo;\n    }\n\n    @JsonProperty(\"CreditLimit\")\n    public double getCreditLimit() {\n        return creditLimit;\n    }\n\n    @JsonProperty(\"CreditLimit\")\n    public void setCreditLimit(double creditLimit) {\n        this.creditLimit = creditLimit;\n    }\n\n    @JsonProperty(\"Transactions\")\n    public List<Transaction> getTransactions() {\n        return transactions;\n    }\n\n    @JsonProperty(\"Transactions\")\n    public void setTransactions(List<Transaction> transactions) {\n        this.transactions = transactions;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/model/LoginError.java",
    "content": "package com.liato.bankdroid.banking.banks.ica.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class LoginError {\n\n    @JsonProperty(\"Title\")\n    private String title;\n\n    @JsonProperty(\"MessageCode\")\n    private String messageCode;\n\n    @JsonProperty(\"PhoneNumber\")\n    private String phoneNumber;\n\n    @JsonProperty(\"Message\")\n    private String message;\n\n    @JsonProperty(\"Title\")\n    public String getTitle() {\n        return title;\n    }\n\n    @JsonProperty(\"Title\")\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    @JsonProperty(\"MessageCode\")\n    public String getMessageCode() {\n        return messageCode;\n    }\n\n    @JsonProperty(\"MessageCode\")\n    public void setMessageCode(String messageCode) {\n        this.messageCode = messageCode;\n    }\n\n    @JsonProperty(\"PhoneNumber\")\n    public String getPhoneNumber() {\n        return phoneNumber;\n    }\n\n    @JsonProperty(\"PhoneNumber\")\n    public void setPhoneNumber(String phoneNumber) {\n        this.phoneNumber = phoneNumber;\n    }\n\n    @JsonProperty(\"Message\")\n    public String getMessage() {\n        return message;\n    }\n\n    @JsonProperty(\"Message\")\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/model/Overview.java",
    "content": "package com.liato.bankdroid.banking.banks.ica.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Overview {\n\n    @JsonProperty(\"Saldo\")\n    private double saldo;\n\n    @JsonProperty(\"YearlyTotalPurchased\")\n    private double yearlyTotalPurchased;\n\n    @JsonProperty(\"PurchaseToDate\")\n    private String purchaseToDate;\n\n    @JsonProperty(\"AcquiredDiscount\")\n    private double acquiredDiscount;\n\n    @JsonProperty(\"AmountSinceLastBonusCheck\")\n    private double amountSinceLastBonusCheck;\n\n    @JsonProperty(\"AmountLeftUntilNextBonusCheck\")\n    private double amountLeftUntilNextBonusCheck;\n\n    @JsonProperty(\"NextBonusCheckValue\")\n    private double nextBonusCheckValue;\n\n    @JsonProperty(\"AcquiredBonus\")\n    private double acquiredBonus;\n\n    @JsonProperty(\"BonusToDate\")\n    private String bonusToDate;\n\n    @JsonProperty(\"IcaBankUrl\")\n    private String icaBankUrl;\n\n    @JsonProperty(\"AccountNumber\")\n    private String accountNumber;\n\n    @JsonProperty(\"AccountName\")\n    private String accountName;\n\n    @JsonProperty(\"AvailableAmount\")\n    private double availableAmount;\n\n    @JsonProperty(\"CreditLimit\")\n    private double creditLimit;\n\n    @JsonProperty(\"Accounts\")\n    private List<Account> accounts = new ArrayList<Account>();\n\n    @JsonProperty(\"Transactions\")\n    private List<Transaction> transactions = new ArrayList<Transaction>();\n\n    @JsonProperty(\"Saldo\")\n    public double getSaldo() {\n        return saldo;\n    }\n\n    @JsonProperty(\"Saldo\")\n    public void setSaldo(double saldo) {\n        this.saldo = saldo;\n    }\n\n    @JsonProperty(\"YearlyTotalPurchased\")\n    public double getYearlyTotalPurchased() {\n        return yearlyTotalPurchased;\n    }\n\n    @JsonProperty(\"YearlyTotalPurchased\")\n    public void setYearlyTotalPurchased(double yearlyTotalPurchased) {\n        this.yearlyTotalPurchased = yearlyTotalPurchased;\n    }\n\n    @JsonProperty(\"PurchaseToDate\")\n    public String getPurchaseToDate() {\n        return purchaseToDate;\n    }\n\n    @JsonProperty(\"PurchaseToDate\")\n    public void setPurchaseToDate(String purchaseToDate) {\n        this.purchaseToDate = purchaseToDate;\n    }\n\n    @JsonProperty(\"AcquiredDiscount\")\n    public double getAcquiredDiscount() {\n        return acquiredDiscount;\n    }\n\n    @JsonProperty(\"AcquiredDiscount\")\n    public void setAcquiredDiscount(double acquiredDiscount) {\n        this.acquiredDiscount = acquiredDiscount;\n    }\n\n    @JsonProperty(\"AmountSinceLastBonusCheck\")\n    public double getAmountSinceLastBonusCheck() {\n        return amountSinceLastBonusCheck;\n    }\n\n    @JsonProperty(\"AmountSinceLastBonusCheck\")\n    public void setAmountSinceLastBonusCheck(double amountSinceLastBonusCheck) {\n        this.amountSinceLastBonusCheck = amountSinceLastBonusCheck;\n    }\n\n    @JsonProperty(\"AmountLeftUntilNextBonusCheck\")\n    public double getAmountLeftUntilNextBonusCheck() {\n        return amountLeftUntilNextBonusCheck;\n    }\n\n    @JsonProperty(\"AmountLeftUntilNextBonusCheck\")\n    public void setAmountLeftUntilNextBonusCheck(double amountLeftUntilNextBonusCheck) {\n        this.amountLeftUntilNextBonusCheck = amountLeftUntilNextBonusCheck;\n    }\n\n    @JsonProperty(\"NextBonusCheckValue\")\n    public double getNextBonusCheckValue() {\n        return nextBonusCheckValue;\n    }\n\n    @JsonProperty(\"NextBonusCheckValue\")\n    public void setNextBonusCheckValue(double nextBonusCheckValue) {\n        this.nextBonusCheckValue = nextBonusCheckValue;\n    }\n\n    @JsonProperty(\"AcquiredBonus\")\n    public double getAcquiredBonus() {\n        return acquiredBonus;\n    }\n\n    @JsonProperty(\"AcquiredBonus\")\n    public void setAcquiredBonus(double acquiredBonus) {\n        this.acquiredBonus = acquiredBonus;\n    }\n\n    @JsonProperty(\"BonusToDate\")\n    public String getBonusToDate() {\n        return bonusToDate;\n    }\n\n    @JsonProperty(\"BonusToDate\")\n    public void setBonusToDate(String bonusToDate) {\n        this.bonusToDate = bonusToDate;\n    }\n\n    @JsonProperty(\"IcaBankUrl\")\n    public String getIcaBankUrl() {\n        return icaBankUrl;\n    }\n\n    @JsonProperty(\"IcaBankUrl\")\n    public void setIcaBankUrl(String icaBankUrl) {\n        this.icaBankUrl = icaBankUrl;\n    }\n\n    @JsonProperty(\"AccountNumber\")\n    public String getAccountNumber() {\n        return accountNumber;\n    }\n\n    @JsonProperty(\"AccountNumber\")\n    public void setAccountNumber(String accountNumber) {\n        this.accountNumber = accountNumber;\n    }\n\n    @JsonProperty(\"AccountName\")\n    public String getAccountName() {\n        return accountName;\n    }\n\n    @JsonProperty(\"AccountName\")\n    public void setAccountName(String accountName) {\n        this.accountName = accountName;\n    }\n\n    @JsonProperty(\"AvailableAmount\")\n    public double getAvailableAmount() {\n        return availableAmount;\n    }\n\n    @JsonProperty(\"AvailableAmount\")\n    public void setAvailableAmount(double availableAmount) {\n        this.availableAmount = availableAmount;\n    }\n\n    @JsonProperty(\"CreditLimit\")\n    public double getCreditLimit() {\n        return creditLimit;\n    }\n\n    @JsonProperty(\"CreditLimit\")\n    public void setCreditLimit(double creditLimit) {\n        this.creditLimit = creditLimit;\n    }\n\n    @JsonProperty(\"Accounts\")\n    public List<Account> getAccounts() {\n        return accounts;\n    }\n\n    @JsonProperty(\"Accounts\")\n    public void setAccounts(List<Account> accounts) {\n        this.accounts = accounts;\n    }\n\n    @JsonProperty(\"Transactions\")\n    public List<Transaction> getTransactions() {\n        return transactions;\n    }\n\n    @JsonProperty(\"Transactions\")\n    public void setTransactions(List<Transaction> transactions) {\n        this.transactions = transactions;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/model/Transaction.java",
    "content": "package com.liato.bankdroid.banking.banks.ica.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class Transaction {\n\n    @JsonProperty(\"TransactionDate\")\n    private String transactionDate;\n\n    @JsonProperty(\"Amount\")\n    private double amount;\n\n    @JsonProperty(\"Description\")\n    private String description;\n\n    @JsonProperty(\"TransactionDate\")\n    public String getTransactionDate() {\n        return transactionDate;\n    }\n\n    @JsonProperty(\"TransactionDate\")\n    public void setTransactionDate(String transactionDate) {\n        this.transactionDate = transactionDate;\n    }\n\n    @JsonProperty(\"Amount\")\n    public double getAmount() {\n        return amount;\n    }\n\n    @JsonProperty(\"Amount\")\n    public void setAmount(double amount) {\n        this.amount = amount;\n    }\n\n    @JsonProperty(\"Description\")\n    public String getDescription() {\n        return description;\n    }\n\n    @JsonProperty(\"Description\")\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/ica/model/User.java",
    "content": "package com.liato.bankdroid.banking.banks.ica.model;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class User {\n\n    @JsonProperty(\"FirstName\")\n    private String firstName;\n\n    @JsonProperty(\"LastName\")\n    private String lastName;\n\n    @JsonProperty(\"Ttl\")\n    private int ttl;\n\n    @JsonProperty(\"FirstName\")\n    public String getFirstName() {\n        return firstName;\n    }\n\n    @JsonProperty(\"FirstName\")\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    @JsonProperty(\"LastName\")\n    public String getLastName() {\n        return lastName;\n    }\n\n    @JsonProperty(\"LastName\")\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    @JsonProperty(\"Ttl\")\n    public int getTtl() {\n        return ttl;\n    }\n\n    @JsonProperty(\"Ttl\")\n    public void setTtl(int ttl) {\n        this.ttl = ttl;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/Lansforsakringar.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.lansforsakringar;\n\nimport com.fasterxml.jackson.core.JsonParseException;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.request.AccountsRequest;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.request.ChallengeRequest;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.request.LoginRequest;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.request.TransactionsRequest;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.response.AccountsResponse;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.response.ChallengeResponse;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.response.LoginResponse;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.response.NumberResponse;\nimport com.liato.bankdroid.banking.banks.lansforsakringar.model.response.TransactionsResponse;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\nimport com.liato.bankdroid.utils.StringUtils;\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.UUID;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\nimport timber.log.Timber;\n\npublic class Lansforsakringar extends Bank {\n\n    private static final String NAME = \"Länsförsäkringar\";\n\n    private static final int BANKTYPE_ID = IBankTypes.LANSFORSAKRINGAR;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅÅÅMMDDXXXX\";\n\n    private static final String API_BASEURL = \"https://mobil.lansforsakringar.se/appoutlet/\";\n\n    private ObjectMapper mObjectMapper = new ObjectMapper();\n\n    private HashMap<String, String> mAccountLedger = new HashMap<>();\n\n    public Lansforsakringar(Context context) {\n        super(context, R.drawable.logo_lansforsakringar);\n\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n        mObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);\n        mObjectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);\n        mObjectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Urllib login() throws LoginException, BankException, IOException {\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_lansforsakringar));\n        urlopen.addHeader(\"Content-Type\", \"application/json; charset=UTF-8\");\n        urlopen.addHeader(\"DeviceId\", UUID.randomUUID().toString());\n        urlopen.addHeader(\"deviceInfo\", \"Galaxy Nexus;4.1.1;1.8;Portrait\");\n        urlopen.addHeader(\"Accept\", \"application/json; charset=UTF-8\");\n        //TODO: Change user-agent to \"lf-android-app\" if they block Bankdroid\n        //urlopen.setUserAgent(\"lf-android-app\");\n\n        NumberResponse nr = readJsonValue(API_BASEURL + \"security/client\", null,\n                NumberResponse.class);\n        ChallengeResponse cr = readJsonValue(API_BASEURL + \"security/client\", objectAsJson(\n                new ChallengeRequest(nr.getNumber(), nr.getNumberPair(),\n                        generateChallenge(nr.getNumber()))), ChallengeResponse.class);\n        urlopen.addHeader(\"Ctoken\", cr.getToken());\n        try {\n            LoginResponse lr = readJsonValue(API_BASEURL + \"security/user\",\n                    objectAsJson(new LoginRequest(getUsername(), getPassword())), LoginResponse.class);\n            urlopen.addHeader(\"Utoken\", lr.getTicket());\n        } catch (Exception e) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString(), e);\n        }\n        return urlopen;\n    }\n\n\n    private <T> T readJsonValue(InputStream is, Class<T> valueType) throws BankException, IOException {\n        try {\n            return mObjectMapper.readValue(is, valueType);\n        } catch (JsonParseException | JsonMappingException e) {\n            throw new BankException(e.getMessage(), e);\n        } finally {\n            try {\n                is.close();\n            } catch (IOException e) {\n                Timber.w(e, \"Closing JSON stream failed\");\n            }\n        }\n    }\n\n    private <T> T readJsonValue(String url, String postData, Class<T> valueType)\n            throws BankException, IOException {\n        return readJsonValue(urlopen.openStream(url, postData, false), valueType);\n    }\n\n    @Nullable\n    private String objectAsJson(Object value) {\n        try {\n            return mObjectMapper.writeValueAsString(value);\n        } catch (JsonProcessingException e) {\n            Timber.w(e, \"Failed converting Object to JSON\");\n        }\n        return null;\n    }\n\n    private String generateChallenge(int originalChallenge) {\n        try {\n            String h = Integer.toHexString(\n                    originalChallenge + (1000 * 20 / 4) + 100 * (18 / 3) + 10 * (2 / 2) + 6);\n            MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n            byte[] messageDigest = md.digest(StringUtils.getBytes(h));\n            BigInteger number = new BigInteger(1, messageDigest);\n            String md5 = number.toString(16);\n            while (md5.length() < 40) {\n                md5 = \"0\" + md5;\n            }\n            return md5;\n        } catch (NoSuchAlgorithmException e) {\n            Timber.w(e, \"Länsförsäkringar: Error generating challenge\");\n        }\n        return \"\";\n\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        urlopen = login();\n\n        mAccountLedger.clear();\n        AccountsResponse ar = readJsonValue(API_BASEURL + \"account/bytype\",\n                objectAsJson(new AccountsRequest(AccountsRequest.Type.CHECKING)),\n                AccountsResponse.class);\n        for (com.liato.bankdroid.banking.banks.lansforsakringar.model.response.Account a : ar\n                .getAccounts()) {\n            accounts.add(new Account(a.getAccountName(), new BigDecimal(a.getBalance()),\n                    a.getAccountNumber()));\n            //a.getLedger() should be saved to database, used when fetching transactions\n            mAccountLedger.put(a.getAccountNumber(), a.getLedger());\n            balance = balance.add(new BigDecimal(a.getBalance()));\n        }\n        ar = readJsonValue(API_BASEURL + \"account/bytype\",\n                objectAsJson(new AccountsRequest(AccountsRequest.Type.SAVING)),\n                AccountsResponse.class);\n        for (com.liato.bankdroid.banking.banks.lansforsakringar.model.response.Account a : ar\n                .getAccounts()) {\n            accounts.add(new Account(a.getAccountName(), new BigDecimal(a.getBalance()),\n                    a.getAccountNumber()));\n            mAccountLedger.put(a.getAccountNumber(), a.getLedger());\n            balance = balance.add(new BigDecimal(a.getBalance()));\n        }\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n        // No transaction history for funds and loans\n        if (account.getType() != Account.REGULAR) {\n            return;\n        }\n\n        ArrayList<Transaction> transactions = new ArrayList<>();\n        //TODO: Get upcoming transactions?\n        //TransactionsResponse tr = readJsonValue(API_BASEURL + \"account/upcoming\", objectAsJson(new UpcomingTransactionsRequest(account.getId())), TransactionsResponse.class);\n\n        try {\n            TransactionsResponse tr = readJsonValue(API_BASEURL + \"account/transaction\",\n                    objectAsJson(new TransactionsRequest(0,\n                            mAccountLedger.containsKey(account.getId()) ? mAccountLedger\n                                    .get(account.getId()) : \"DEPIOSIT\", account.getId())),\n                    TransactionsResponse.class);\n            for (com.liato.bankdroid.banking.banks.lansforsakringar.model.response.Transaction t : tr\n                    .getTransactions()) {\n                //TODO: Set locale to Europe/Stockholm on date?\n                transactions\n                        .add(new Transaction(Helpers.formatDate(new Date(t.getTransactiondate())),\n                                t.getText(), new BigDecimal(t.getAmmount())));\n            }\n            account.setTransactions(transactions);\n        } catch (BankException e) {\n            Timber.e(e, \"Failed updating Länsförsäkringar transactions\");\n        }\n\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/request/AccountsRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.request;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class AccountsRequest {\n\n    private String mAccountType;\n\n    public AccountsRequest(Type accountType) {\n        mAccountType = accountType.toString();\n    }\n\n    @JsonProperty(\"accountType\")\n    public String getAccountType() {\n        return mAccountType;\n    }\n\n    @JsonSetter(\"accountType\")\n    public void setAccountType(String a) {\n        mAccountType = a;\n    }\n\n    public enum Type {\n        CHECKING(\"CHECKING\"),\n        SAVING(\"SAVING\");\n\n        private String name;\n\n        private Type(String name) {\n            this.name = name;\n        }\n\n        @Override\n        public String toString() {\n            return this.name;\n        }\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/request/ChallengeRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.request;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class ChallengeRequest {\n\n    private int mOriginalChallenge;\n\n    private String mChallengePair;\n\n    private String mHash;\n\n\n    public ChallengeRequest(int originalChallenge, String challengePair, String hash) {\n        mOriginalChallenge = originalChallenge;\n        mChallengePair = challengePair;\n        mHash = hash;\n    }\n\n    @JsonProperty(\"originalChallenge\")\n    public int getOriginalChallenge() {\n        return mOriginalChallenge;\n    }\n\n    @JsonSetter(\"originalChallenge\")\n    public void setOriginalChallenge(int o) {\n        mOriginalChallenge = o;\n    }\n\n    @JsonProperty(\"challengePair\")\n    public String getChallengePair() {\n        return mChallengePair;\n    }\n\n    @JsonSetter(\"challengePair\")\n    public void setChallengePair(String c) {\n        mChallengePair = c;\n    }\n\n    @JsonProperty(\"hash\")\n    public String getHash() {\n        return mHash;\n    }\n\n    @JsonSetter(\"hash\")\n    public void setHash(String h) {\n        mHash = h;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/request/LoginRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.request;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class LoginRequest {\n\n    private String mSsn;\n\n    private String mPin;\n\n\n    public LoginRequest(String ssn, String pin) {\n        mSsn = ssn;\n        mPin = pin;\n    }\n\n    @JsonProperty(\"ssn\")\n    public String getSsn() {\n        return mSsn;\n    }\n\n    @JsonSetter(\"ssn\")\n    public void setSsn(String s) {\n        mSsn = s;\n    }\n\n    @JsonProperty(\"pin\")\n    public String getPin() {\n        return mPin;\n    }\n\n    @JsonSetter(\"pin\")\n    public void setPin(String p) {\n        mPin = p;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/request/TransactionsRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.request;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class TransactionsRequest {\n\n    private int mRequestedPage;\n\n    private String mLedger;\n\n    private String mAccountNumber;\n\n\n    public TransactionsRequest(int requestedPage, String ledger, String accountNumber) {\n        mRequestedPage = requestedPage;\n        mLedger = ledger;\n        mAccountNumber = accountNumber;\n    }\n\n    @JsonProperty(\"requestedPage\")\n    public int getRequestedPage() {\n        return mRequestedPage;\n    }\n\n    @JsonSetter(\"requestedPage\")\n    public void setRequestedPage(int r) {\n        mRequestedPage = r;\n    }\n\n    @JsonProperty(\"ledger\")\n    public String getLedger() {\n        return mLedger;\n    }\n\n    @JsonSetter(\"ledger\")\n    public void setLedger(String l) {\n        mLedger = l;\n    }\n\n    @JsonProperty(\"accountNumber\")\n    public String getAccountNumber() {\n        return mAccountNumber;\n    }\n\n    @JsonSetter(\"accountNumber\")\n    public void setAccountNumber(String a) {\n        mAccountNumber = a;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/request/UpcomingTransactionsRequest.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.request;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class UpcomingTransactionsRequest {\n\n    private String mAccountNumber;\n\n\n    public UpcomingTransactionsRequest(String accountNumber) {\n        mAccountNumber = accountNumber;\n    }\n\n    @JsonProperty(\"accountNumber\")\n    public String getAccountNumber() {\n        return mAccountNumber;\n    }\n\n    @JsonSetter(\"accountNumber\")\n    public void setAccountNumber(String a) {\n        mAccountNumber = a;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/Account.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class Account {\n\n    private boolean mTransferTo;\n\n    private String mProductCode;\n\n    private boolean mYouthAccount;\n\n    private String mAccountNumber;\n\n    private String mClearingNumber;\n\n    private boolean mTransferFrom;\n\n    private String mLedger;\n\n    private String mAccountName;\n\n    private float mDispoibleAmount;\n\n    private float mBalance;\n\n    @JsonProperty(\"transferTo\")\n    public boolean getTransferTo() {\n        return mTransferTo;\n    }\n\n    @JsonSetter(\"transferTo\")\n    public void setTransferTo(boolean t) {\n        mTransferTo = t;\n    }\n\n    @JsonProperty(\"productCode\")\n    public String getProductCode() {\n        return mProductCode;\n    }\n\n    @JsonSetter(\"productCode\")\n    public void setProductCode(String p) {\n        mProductCode = p;\n    }\n\n    @JsonProperty(\"youthAccount\")\n    public boolean getYouthAccount() {\n        return mYouthAccount;\n    }\n\n    @JsonSetter(\"youthAccount\")\n    public void setYouthAccount(boolean y) {\n        mYouthAccount = y;\n    }\n\n    @JsonProperty(\"accountNumber\")\n    public String getAccountNumber() {\n        return mAccountNumber;\n    }\n\n    @JsonSetter(\"accountNumber\")\n    public void setAccountNumber(String a) {\n        mAccountNumber = a;\n    }\n\n    @JsonProperty(\"clearingNumber\")\n    public String getClearingNumber() {\n        return mClearingNumber;\n    }\n\n    @JsonSetter(\"clearingNumber\")\n    public void setClearingNumber(String c) {\n        mClearingNumber = c;\n    }\n\n    @JsonProperty(\"transferFrom\")\n    public boolean getTransferFrom() {\n        return mTransferFrom;\n    }\n\n    @JsonSetter(\"transferFrom\")\n    public void setTransferFrom(boolean t) {\n        mTransferFrom = t;\n    }\n\n    @JsonProperty(\"ledger\")\n    public String getLedger() {\n        return mLedger;\n    }\n\n    @JsonSetter(\"ledger\")\n    public void setLedger(String l) {\n        mLedger = l;\n    }\n\n    @JsonProperty(\"accountName\")\n    public String getAccountName() {\n        return mAccountName;\n    }\n\n    @JsonSetter(\"accountName\")\n    public void setAccountName(String a) {\n        mAccountName = a;\n    }\n\n    @JsonProperty(\"dispoibleAmount\")\n    public float getDispoibleAmount() {\n        return mDispoibleAmount;\n    }\n\n    @JsonSetter(\"dispoibleAmount\")\n    public void setDispoibleAmount(float d) {\n        mDispoibleAmount = d;\n    }\n\n    @JsonProperty(\"balance\")\n    public float getBalance() {\n        return mBalance;\n    }\n\n    @JsonSetter(\"balance\")\n    public void setBalance(float b) {\n        mBalance = b;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/AccountsResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\nimport java.util.ArrayList;\n\npublic class AccountsResponse {\n\n    private ArrayList<Account> mAccounts = new ArrayList<Account>();\n\n    @JsonProperty(\"accounts\")\n    public ArrayList<Account> getAccounts() {\n        return mAccounts;\n    }\n\n    @JsonSetter(\"accounts\")\n    public void setAccounts(ArrayList<Account> a) {\n        mAccounts = a;\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/ChallengeResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class ChallengeResponse {\n\n    private int mLifetime;\n\n    private String mToken;\n\n    @JsonProperty(\"lifetime\")\n    public int getLifetime() {\n        return mLifetime;\n    }\n\n    @JsonSetter(\"lifetime\")\n    public void setLifetime(int l) {\n        mLifetime = l;\n    }\n\n    @JsonProperty(\"token\")\n    public String getToken() {\n        return mToken;\n    }\n\n    @JsonSetter(\"token\")\n    public void setToken(String t) {\n        mToken = t;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/LoginResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class LoginResponse {\n\n    private String mName;\n\n    private String mLfCompanyBelonging;\n\n    private String mSsn;\n\n    private int mTicketLifetime;\n\n    private boolean mPinPadAvailable;\n\n    private String mTicket;\n\n    @JsonProperty(\"name\")\n    public String getName() {\n        return mName;\n    }\n\n    @JsonSetter(\"name\")\n    public void setName(String n) {\n        mName = n;\n    }\n\n    @JsonProperty(\"lfCompanyBelonging\")\n    public String getLfCompanyBelonging() {\n        return mLfCompanyBelonging;\n    }\n\n    @JsonSetter(\"lfCompanyBelonging\")\n    public void setLfCompanyBelonging(String l) {\n        mLfCompanyBelonging = l;\n    }\n\n    @JsonProperty(\"ssn\")\n    public String getSsn() {\n        return mSsn;\n    }\n\n    @JsonSetter(\"ssn\")\n    public void setSsn(String s) {\n        mSsn = s;\n    }\n\n    @JsonProperty(\"ticketLifetime\")\n    public int getTicketLifetime() {\n        return mTicketLifetime;\n    }\n\n    @JsonSetter(\"ticketLifetime\")\n    public void setTicketLifetime(int t) {\n        mTicketLifetime = t;\n    }\n\n    @JsonProperty(\"pinPadAvailable\")\n    public boolean getPinPadAvailable() {\n        return mPinPadAvailable;\n    }\n\n    @JsonSetter(\"pinPadAvailable\")\n    public void setPinPadAvailable(boolean p) {\n        mPinPadAvailable = p;\n    }\n\n    @JsonProperty(\"ticket\")\n    public String getTicket() {\n        return mTicket;\n    }\n\n    @JsonSetter(\"ticket\")\n    public void setTicket(String t) {\n        mTicket = t;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/NumberResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class NumberResponse {\n\n    private int mNumber;\n\n    private String mNumberPair;\n\n    @JsonProperty(\"number\")\n    public int getNumber() {\n        return mNumber;\n    }\n\n    @JsonSetter(\"number\")\n    public void setNumber(int n) {\n        mNumber = n;\n    }\n\n    @JsonProperty(\"numberPair\")\n    public String getNumberPair() {\n        return mNumberPair;\n    }\n\n    @JsonSetter(\"numberPair\")\n    public void setNumberPair(String n) {\n        mNumberPair = n;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/Transaction.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\npublic class Transaction {\n\n    private String mText;\n\n    private long mTransactiondate;\n\n    private float mAmmount;\n\n    @JsonProperty(\"text\")\n    public String getText() {\n        return mText;\n    }\n\n    @JsonSetter(\"text\")\n    public void setText(String t) {\n        mText = t;\n    }\n\n    @JsonProperty(\"transactiondate\")\n    public long getTransactiondate() {\n        return mTransactiondate;\n    }\n\n    @JsonSetter(\"transactiondate\")\n    public void setTransactiondate(long t) {\n        mTransactiondate = t;\n    }\n\n    @JsonProperty(\"ammount\")\n    public float getAmmount() {\n        return mAmmount;\n    }\n\n    @JsonSetter(\"ammount\")\n    public void setAmmount(float a) {\n        mAmmount = a;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/lansforsakringar/model/response/TransactionsResponse.java",
    "content": "package com.liato.bankdroid.banking.banks.lansforsakringar.model.response;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonSetter;\n\nimport java.util.ArrayList;\n\npublic class TransactionsResponse {\n\n    private boolean mHasMore;\n\n    private int mNextSequenceNumber;\n\n    private ArrayList<Transaction> mTransactions = new ArrayList<Transaction>();\n\n    @JsonProperty(\"hasMore\")\n    public boolean getHasMore() {\n        return mHasMore;\n    }\n\n    @JsonSetter(\"hasMore\")\n    public void setHasMore(boolean h) {\n        mHasMore = h;\n    }\n\n    @JsonProperty(\"nextSequenceNumber\")\n    public int getNextSequenceNumber() {\n        return mNextSequenceNumber;\n    }\n\n    @JsonSetter(\"nextSequenceNumber\")\n    public void setNextSequenceNumber(int n) {\n        mNextSequenceNumber = n;\n    }\n\n    @JsonProperty(\"transactions\")\n    public ArrayList<Transaction> getTransactions() {\n        return mTransactions;\n    }\n\n    @JsonSetter(\"transactions\")\n    public void setTransactions(ArrayList<Transaction> t) {\n        mTransactions = t;\n    }\n\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/nordea/CaptchaBreaker.java",
    "content": "package com.liato.bankdroid.banking.banks.nordea;\n\nimport android.graphics.Bitmap;\n\nimport java.util.ArrayList;\n\npublic class CaptchaBreaker {\n\n    private final static int[][][] NUMBERS = CaptchaBreakerNumbers.NUMBERS;\n\n    public static String iMustBreakYou(Bitmap bitmap) {\n        int width = bitmap.getWidth();\n        int height = bitmap.getHeight();\n\n        ArrayList<Segment> segments = new ArrayList<Segment>();\n\n        boolean numberpart = false;\n        Segment segment = new Segment();\n        for (int x = 0; x < width; x++) {\n            boolean numberpartcol = false;\n            for (int y = 0; y < height; y++) {\n                int color = bitmap.getPixel(x, y);\n                if (color != 0xffffffff) {\n                    if (!numberpart) {\n                        segment.start = x;\n                    }\n                    numberpartcol = true;\n                    numberpart = true;\n                    break;\n                }\n            }\n            if (numberpart && !numberpartcol) {\n                numberpart = false;\n                segment.end = x - 1;\n                segments.add(segment);\n                segment = new Segment();\n            }\n        }\n        if (segment.end == -1 && segment.start >= 0) {\n            segment.end = width - 1;\n            segments.add(segment);\n        }\n        StringBuilder sb = new StringBuilder(segments.size());\n        for (Segment s : segments) {\n            Bitmap numberSegment = Bitmap.createBitmap(bitmap, s.start, 0, s.end - s.start, height);\n            sb.append(extractNumber(numberSegment));\n            numberSegment.recycle();\n            numberSegment = null;\n        }\n        return sb.toString();\n\n    }\n\n    private static String extractNumber(Bitmap bitmap) {\n        int width = bitmap.getWidth();\n        for (int i = 0; i < NUMBERS.length; i++) {\n            int matches = 0;\n            int[][] number = NUMBERS[i];\n            for (int pi = 0; pi < number.length; pi++) {\n                int[] point = number[pi];\n                if (point[0] >= width) {\n                    break;\n                }\n                int color = bitmap.getPixel(point[0], point[1]);\n                if ((color == 0xffffffff && point[2] == 0) || (color != 0xffffffff\n                        && point[2] == 1)) {\n                    matches++;\n                }\n            }\n            if (matches == number.length) {\n                return Integer.toString(i);\n            }\n        }\n        return \"?\";\n    }\n\n\n}\n\nclass Segment {\n\n    public int start = -1;\n\n    public int end = -1;\n\n    @Override\n    public String toString() {\n        return String.format(\"Segment {start=%d, end=%d}\", start, end);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/nordea/CaptchaBreakerNumbers.java",
    "content": "package com.liato.bankdroid.banking.banks.nordea;\n\n/**\n * Autogenerated captcha numbers for Nordea.\n *\n * @since 2012-07-08 05:51:25\n */\npublic class CaptchaBreakerNumbers {\n\n    public final static int[][][] NUMBERS = {\n            {{7, 12, 0}, {6, 22, 1}, {11, 18, 0}, {4, 9, 1},\n                    {0, 14, 1}, {5, 27, 0}, {2, 27, 0}, {5, 17, 1},\n                    {9, 17, 0}, {17, 1, 0}, {8, 9, 0}, {11, 15, 0},\n                    {1, 15, 1}, {15, 1, 0}, {15, 3, 1}, {8, 0, 1},\n                    {4, 0, 0}, {9, 3, 0}, {14, 1, 1}, {16, 20, 1},\n                    {9, 6, 0}, {9, 18, 0}, {15, 5, 1}, {0, 13, 1},\n                    {5, 18, 1}, {15, 17, 1}, {12, 25, 1}, {6, 16, 0},\n                    {11, 16, 0}, {16, 28, 0}, {16, 27, 0}, {6, 1, 1}},\n            {{7, 27, 0}, {8, 4, 1}, {5, 5, 1}, {12, 25, 1},\n                    {0, 25, 1}, {11, 16, 0}, {8, 26, 0}, {3, 27, 0},\n                    {2, 27, 0}, {9, 4, 1}, {5, 0, 0}, {7, 7, 1},\n                    {10, 20, 0}, {12, 11, 0}, {1, 11, 0}, {3, 1, 1},\n                    {4, 18, 0}, {0, 24, 1}, {1, 16, 0}, {9, 27, 0},\n                    {3, 22, 0}, {7, 21, 1}, {11, 18, 0}, {6, 24, 1},\n                    {0, 20, 0}, {13, 16, 0}, {7, 11, 1}, {8, 12, 1},\n                    {10, 22, 0}, {3, 24, 1}, {3, 12, 0}, {8, 27, 0}},\n            {{3, 10, 0}, {12, 18, 0}, {14, 25, 1}, {13, 10, 1},\n                    {10, 19, 0}, {11, 21, 0}, {1, 15, 0}, {1, 27, 0},\n                    {10, 10, 1}, {0, 14, 0}, {10, 21, 0}, {12, 1, 1},\n                    {5, 9, 0}, {9, 27, 0}, {7, 18, 1}, {12, 0, 1},\n                    {11, 18, 0}, {2, 10, 0}, {1, 7, 0}, {6, 27, 0},\n                    {3, 25, 1}, {9, 25, 1}, {12, 23, 1}, {2, 1, 1},\n                    {8, 25, 1}, {0, 20, 1}, {12, 16, 0}, {8, 8, 0},\n                    {11, 5, 1}, {11, 17, 0}, {0, 3, 0}, {1, 18, 0}},\n            {{10, 9, 1}, {3, 11, 1}, {2, 2, 1}, {7, 20, 0},\n                    {8, 24, 1}, {5, 14, 1}, {12, 25, 1}, {1, 17, 0},\n                    {0, 15, 0}, {2, 18, 0}, {6, 27, 0}, {0, 22, 1},\n                    {13, 8, 1}, {2, 21, 0}, {13, 23, 1}, {11, 7, 1},\n                    {13, 26, 0}, {2, 18, 0}, {5, 27, 0}, {2, 27, 0},\n                    {0, 1, 1}, {4, 18, 0}, {4, 7, 0}, {13, 27, 0},\n                    {10, 17, 0}, {9, 2, 1}, {7, 1, 1}, {8, 20, 0},\n                    {13, 25, 0}, {13, 26, 0}, {6, 0, 1}, {2, 0, 1}},\n            {{10, 5, 1}, {18, 3, 0}, {6, 16, 1}, {16, 6, 1},\n                    {17, 20, 0}, {16, 22, 1}, {3, 19, 0}, {15, 28, 0},\n                    {10, 7, 1}, {16, 23, 1}, {11, 9, 0}, {13, 24, 1},\n                    {15, 7, 1}, {3, 19, 0}, {9, 12, 0}, {3, 8, 0},\n                    {10, 10, 0}, {13, 0, 1}, {15, 3, 1}, {12, 2, 1},\n                    {13, 8, 1}, {16, 3, 1}, {2, 14, 1}, {9, 9, 0},\n                    {8, 23, 0}, {6, 27, 0}, {8, 0, 0}, {0, 16, 1},\n                    {10, 2, 1}, {13, 13, 1}, {13, 10, 1}, {8, 5, 1}},\n            {{2, 14, 0}, {3, 20, 0}, {3, 4, 0}, {13, 13, 1},\n                    {1, 15, 0}, {2, 13, 0}, {6, 21, 0}, {3, 20, 0},\n                    {11, 0, 1}, {4, 16, 0}, {13, 14, 1}, {11, 2, 1},\n                    {2, 23, 1}, {0, 22, 1}, {7, 20, 0}, {11, 9, 0},\n                    {0, 23, 1}, {14, 7, 0}, {9, 8, 0}, {8, 22, 1},\n                    {6, 2, 1}, {1, 0, 1}, {13, 19, 1}, {7, 20, 0},\n                    {9, 14, 1}, {4, 5, 0}, {8, 25, 1}, {0, 26, 0},\n                    {3, 5, 0}, {11, 17, 1}, {4, 18, 0}, {4, 3, 1}},\n            {{0, 5, 0}, {2, 3, 1}, {10, 0, 1}, {4, 8, 1}, {3, 6, 1},\n                    {12, 10, 1}, {13, 1, 1}, {7, 12, 1}, {5, 7, 1},\n                    {9, 21, 0}, {0, 4, 0}, {3, 28, 0}, {13, 9, 1},\n                    {10, 12, 1}, {4, 4, 1}, {13, 22, 1}, {13, 10, 1},\n                    {7, 1, 1}, {6, 22, 1}, {11, 16, 0}, {4, 9, 1},\n                    {15, 14, 1}, {12, 18, 0}, {13, 1, 1}, {4, 27, 0},\n                    {9, 0, 1}, {12, 13, 1}, {4, 13, 1}, {17, 4, 0},\n                    {16, 6, 0}, {14, 12, 1}, {7, 23, 1}},\n            {{12, 3, 1}, {0, 22, 0}, {8, 27, 0}, {15, 19, 0},\n                    {12, 3, 1}, {9, 7, 0}, {4, 6, 0}, {7, 4, 0},\n                    {9, 23, 0}, {14, 0, 1}, {2, 15, 0}, {7, 0, 1},\n                    {6, 18, 1}, {11, 11, 1}, {6, 10, 0}, {11, 20, 0},\n                    {13, 10, 0}, {13, 2, 1}, {15, 5, 1}, {5, 13, 0},\n                    {10, 8, 1}, {10, 16, 0}, {4, 19, 1}, {8, 28, 0},\n                    {8, 16, 1}, {13, 4, 1}, {15, 22, 0}, {15, 10, 0},\n                    {3, 12, 0}, {13, 6, 1}, {3, 5, 0}, {12, 23, 0}},\n            {{5, 27, 0}, {5, 3, 1}, {5, 24, 1}, {17, 18, 1},\n                    {8, 13, 1}, {1, 14, 1}, {9, 19, 0}, {2, 26, 0},\n                    {3, 13, 1}, {4, 19, 1}, {12, 15, 1}, {7, 28, 0},\n                    {13, 0, 1}, {8, 22, 1}, {11, 25, 1}, {11, 5, 0},\n                    {6, 23, 1}, {0, 16, 1}, {4, 0, 0}, {17, 25, 0},\n                    {12, 22, 1}, {6, 13, 1}, {7, 19, 0}, {9, 19, 0},\n                    {11, 23, 1}, {11, 8, 0}, {17, 11, 0}, {12, 25, 1},\n                    {1, 26, 0}, {15, 5, 1}, {0, 18, 1}, {7, 11, 1}},\n            {{6, 24, 1}, {14, 13, 1}, {0, 3, 0}, {8, 6, 0},\n                    {3, 12, 1}, {7, 21, 0}, {7, 26, 0}, {10, 28, 0},\n                    {3, 23, 1}, {7, 1, 1}, {6, 0, 1}, {13, 0, 1},\n                    {12, 28, 0}, {15, 15, 1}, {6, 24, 1}, {11, 5, 0},\n                    {3, 20, 0}, {9, 12, 0}, {2, 15, 1}, {4, 21, 0},\n                    {13, 11, 1}, {3, 8, 1}, {17, 16, 1}, {13, 9, 0},\n                    {3, 1, 1}, {14, 10, 1}, {3, 19, 0}, {14, 7, 1},\n                    {15, 19, 1}, {3, 1, 1}, {8, 19, 0}, {11, 13, 1}}};\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/nordea/Nordea.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.banks.nordea;\n\nimport com.liato.bankdroid.Helpers;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.Transaction;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.provider.IBankTypes;\n\nimport org.apache.http.NameValuePair;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport android.content.Context;\nimport android.text.Html;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Nordea extends Bank {\n\n    private static final String NAME = \"Nordea\";\n\n    private static final String BASE_URL = \"https://internetbanken.privat.nordea.se/nsp/\";\n\n    private static final String LOGIN_URL = BASE_URL + \"login\";\n\n    private static final int BANKTYPE_ID = IBankTypes.NORDEA;\n\n    private static final int INPUT_TYPE_USERNAME = InputType.TYPE_CLASS_PHONE;\n\n    private static final int INPUT_TYPE_PASSWORD = InputType.TYPE_CLASS_PHONE;\n\n    private static final String INPUT_HINT_USERNAME = \"ÅÅÅÅMMDDXXXX\";\n\n    private static final int MAX_TRANSACTIONS = 50;\n\n    private Pattern reSimpleLoginLink = Pattern.compile(\n            \"href=\\\"(login\\\\?\" +\n                    \"(?=[^\\\"]*usecase=commonlogin)\" +\n                    \"(?=[^\\\"]*command=commonlogintabcommand)\" +\n                    \"(?=[^\\\"]*guid=([\\\\w]*))\" +\n                    \"(?=[^\\\"]*fpid=([\\\\w]*))\" +\n                    \"(?=[^\\\"]*commonlogintab=2)\" +\n                    \"(?=[^\\\"]*hash=([\\\\w]*))\" +\n                    \"[^\\\"]*)\",\n            Pattern.CASE_INSENSITIVE\n    );\n\n    private Pattern reLoginFormContents = Pattern.compile(\n            \"<form[^>]+id=\\\"commonlogin\\\"[^>]*>(.*?)</form>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reNonTextInputField = Pattern.compile(\n            \"<input(?=[^>]+type=\\\"((?!text)[^\\\"]*)\\\")(?=[^>]+name=\\\"([^\\\"]+)\\\")(?=[^>]+value=\\\"([^\\\"]+)\\\")\",\n            Pattern.CASE_INSENSITIVE);\n\n    private Pattern reNonTelInputField = Pattern.compile(\n            \"<input(?=[^>]+type=\\\"((?!tel)[^\\\"]*)\\\")(?=[^>]+name=\\\"([^\\\"]+)\\\")(?=[^>]+value=\\\"([^\\\"]+)\\\")\",\n            Pattern.CASE_INSENSITIVE);\n\n    // Link to home/overview - PageType.ENTRY\n    private Pattern reHomeLink = Pattern.compile(\n            \"href=\\\"(core[^\\\"#]*)#?\\\"\" + // The actual url (trim the '#')\n                    \"[^>]*>\" +\n                    \"[^<]*\" +\n                    \"<img[^>]+id=\\\"home\\\"\" // Identificator\n    );\n\n    private Pattern reTransactionFormContents = Pattern.compile(\n            \"<form(?=[^>]+id=\\\"accountTransactions\\\")(?=[^>]+action=\\\"([^\\\"]*)\\\").*?>(.*?)</form>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reAccountLink = Pattern.compile(\n            \"href=\\\"(core\\\\?\" +\n                    \"(?=[^\\\"]*usecase=accountsoverview)\" +\n                    \"(?=[^\\\"]*command=getcurrenttransactions)\" +\n                    \"(?=[^\\\"]*currentaccountsoverviewtable=([\\\\d]+))\" +\n                    \"[^\\\"]*)[^>]*>\" + // End of link attributes\n                    \"(.*?)\" + // Link contents - account name\n                    \"</a>\" +\n                    \".*?\" + // fast forward\n                    \"([*\\\\d]+)\" + // censured account number (account identifier)\n                    \".*?\" + // fast forward\n                    \"<td.*?>(.*?)</td>\", // account balance\n            Pattern.DOTALL\n    );\n\n    private Pattern reTransaction = Pattern.compile(\n            \"(\\\\d{4}-\\\\d{2}-\\\\d{2})[\\n\\r <].*?<td.*?>(.*?)</td>.*?<td.*?>.*?</td>.*?<td.*?>([\\\\s\\\\d+,.-]*)\",\n            Pattern.DOTALL);\n\n    private Pattern reCurrency = Pattern.compile(\n            \"Saldo:.*?[\\\\d\\\\.,-]+[\\\\s]*</td>[\\\\s]*<td[^>]*>([^<]*)\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    // The link to go to the credit cards overview page\n    private Pattern reCreditCardsLink = Pattern.compile(\"<a href=\\\"([^\\\"#]*)#?\\\">Kort<\");\n\n    // Link to specific credit card\n    private Pattern reCreditCardLink = Pattern.compile(\n            \"href=\\\"\" +\n                    \"(\" + // Start group 1: link url\n                    \"engine\\\\?\" +\n                    \"(?=[^\\\"]*usecase=viewallcards)\" +\n                    \"(?=[^\\\"]*command=gettransactionscredit)\" +\n                    // debit cards have \"debit\" - but we don't need those\n                    \"[^\\\"#]*\" + // Rest of link url\n                    \")\" + // End group 1\n                    \"[^>]*>\" + // Rest of link attributes\n                    \"(.*?)\" + // Group 2: Link contents - Credit card type (Eg. \"Nordea Gold\")\n                    \"</a>\" +\n                    \".*?\" + // Fast forward\n                    \"\\\\*+(\\\\d+)\" + // Group 3: Censured credit card number (account identifier)\n                    \".*?\" + // Fast forward\n                    \"<td.*?>([^<]*)</td>\" + // Group 4: Expire date **/**\n                    \".*?\" + // Fast forward\n                    \"<td.*?>([^<]*)</td>\", // Group 5: Account balance\n            Pattern.DOTALL\n    );\n\n    // Credit card transaction entry\n    private Pattern reCreditCardTransaction = Pattern.compile(\n            \"(\\\\d{4}-\\\\d{2}-\\\\d{2})</a>\" + // Group 1: Transaction date\n                    \"[^<]*</td>\" + // End date col\n                    \"[^<]*<td[^>]*>\" + // Start transaction name col\n                    \"\\\\s*([^<]*)\\\\s*</td>\" + // Group 2: (trimmed) Transaction name\n                    \"[^<]*<td[^>]*>\" + // Start recipient name col (same as transaction name?)\n                    \"[^<]*</td>\" + // Transaction name\n                    \"[^<]*<td[^>]*>\" + // Start transaction native amount/currency col\n                    \"\\\\s*([^<]*)\\\\s*</td>\" +\n                    // Group 3: Transaction native amount/currency (Empty when SEK)\n                    \"[^<]*<td[^>]*>\" + // Start amount col\n                    \"\\\\s*([\\\\d,.-]+)\", // Group 4: Transaction amount\n            Pattern.DOTALL\n    );\n\n    // Credit card currency\n    private Pattern reCreditCardCurrency = Pattern.compile(\n            \"<th[^>]*>Belopp\\\\s([^<]+)</th>\"\n    );\n\n    // The link to go to the loans overview page\n    private Pattern reLoansLink = Pattern.compile(\"<a href=\\\"([^\\\"#]*)#?\\\">Lån<\");\n\n    // Link to specific loan\n    private Pattern reLoanLink = Pattern.compile(\n            \"href=\\\"\" +\n                    \"(\" + // Start group 1: link url\n                    \"engine\\\\?\" +\n                    \"(?=[^\\\"]*usecase=loansoverview)\" +\n                    \"(?=[^\\\"]*command=get_loan_details_command)\" +\n                    \"[^\\\"#]*\" + // Rest of link url\n                    \")\" + // End group 1\n                    \"#?\" + // Trim off a padded #\n                    \"[^>]*>\" + // Rest of link attributes\n                    \"(.*?)\" + // Group 2: Link contents - Loan type (Eg. \"Bolån\")\n                    \"</a>\" +\n                    \".*?\" + // Fast forward\n                    \"\\\\*+(\\\\d+)\" + // Group 3: Censured loan number (account identifier)\n                    \".*?\" + // Fast forward\n                    \"(\\\\d{4}-\\\\d{2}-\\\\d{2})\" +\n                    // Group 4: \"Transaction date\" - Latest interest payment date\n                    \".*?\" + // Fast forward\n                    \"([\\\\d\\\\.,]+)\", // Group 5: Loan amount\n            Pattern.DOTALL\n    );\n\n    private Pattern reAccountSelect = Pattern.compile(\n            \"<select[^>]+name=\\\"transactionaccount\\\"[^>]*>(.*?)</select>\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    private Pattern reAccountOption = Pattern.compile(\n            \"<option[^>]+value=\\\"([\\\\d]+)\\\"[^>]*>.*?(\\\\*{12}\\\\d{4})\",\n            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);\n\n    // Nordea generates unique urls on each page load and serves content from session info,\n    // so we need to find new links in lastResponse after each page load.\n    private String lastResponse;\n\n    private int currentPageType;\n\n    public Nordea(Context context) {\n        super(context, R.drawable.logo_nordea);\n\n        super.url = BASE_URL;\n        super.inputTypeUsername = INPUT_TYPE_USERNAME;\n        super.inputTypePassword = INPUT_TYPE_PASSWORD;\n        super.inputHintUsername = INPUT_HINT_USERNAME;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Nordea(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    protected LoginPackage preLogin() throws BankException, IOException {\n        urlopen = new Urllib(context);\n        Matcher matcher;\n        // Find \"simple login\" link\n        this.lastResponse = urlopen.open(LOGIN_URL);\n        this.currentPageType = PageType.LOGIN;\n        matcher = reSimpleLoginLink.matcher(this.lastResponse);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" login link.\");\n        }\n        // Visit login link\n        String link = BASE_URL + matcher.group(1);\n        this.lastResponse = urlopen.open(link);\n        this.currentPageType = PageType.SIMPLE_LOGIN;\n        matcher = reLoginFormContents.matcher(this.lastResponse);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" login form.\");\n        }\n        // Extract hidden fields\n        String formContents = matcher.group(1);\n        matcher = reNonTelInputField.matcher(formContents);\n        if (!matcher.find()) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" login fields.\");\n        }\n        matcher.reset();\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n        while (matcher.find()) {\n            String name = matcher.group(2);\n            String value = matcher.group(3);\n            // The non-mobile page requires javascript, so we'd best pretend we have it\n            if (\"JAVASCRIPT_DETECTED\".equals(name)) {\n                value = \"true\";\n            }\n            postData.add(new BasicNameValuePair(name, value));\n        }\n        // Login information\n        postData.add(new BasicNameValuePair(\"userid\", getUsername()));\n        postData.add(new BasicNameValuePair(\"pin\", getPassword()));\n        // Submit button is not contained within the form and thus cannot (should not) be found with the InputField matcher\n        postData.add(new BasicNameValuePair(\"commonlogin$loginLight\", \"Logga in\"));\n        return new LoginPackage(urlopen, postData, this.lastResponse, LOGIN_URL);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException, IOException {\n        LoginPackage lp = preLogin();\n        this.lastResponse = urlopen.open(lp.getLoginTarget(), lp.getPostData());\n        this.currentPageType = PageType.ENTRY;\n        if (this.lastResponse.contains(\"fel uppgifter\")) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty() || getPassword().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_username_password).toString());\n        }\n\n        // This puts us at PageType.ENTRY\n        urlopen = login();\n        String loanName;\n\n        // Add regular accounts\n        Matcher matcher = reAccountLink.matcher(this.lastResponse);\n        while (matcher.find()) {\n            accounts.add(new Account(\n                    // Account name\n                    Html.fromHtml(matcher.group(3)).toString().trim(),\n                    // Balance\n                    Helpers.parseBalance(Html.fromHtml(matcher.group(5)).toString()),\n                    // Account identifier - half censured account number: \"************1234\"\n                    Html.fromHtml(matcher.group(4)).toString().trim()\n            ));\n        }\n\n        // TODO: Code for funds\n\n        goToPage(PageType.CREDIT_CARDS);\n        matcher = reCreditCardLink.matcher(this.lastResponse);\n        // Add credit cards\n        while (matcher.find()) {\n            accounts.add(new Account(\n                    // Account/Credit card name\n                    matcher.group(2),\n                    // Balance (not available through simple login)\n                    Helpers.parseBalance(matcher.group(5)),\n                    // Account/Credit card identifier\n                    \"c:\" + matcher.group(3),\n                    -1L,\n                    Account.CCARD\n            ));\n        }\n\n        goToPage(PageType.LOANS);\n        matcher = reLoanLink.matcher(this.lastResponse);\n        // Add loans\n        while (matcher.find()) {\n            loanName = matcher.group(2) + ' ' + matcher.group(3);\n            accounts.add(new Account(\n                    loanName,\n                    Helpers.parseBalance(matcher.group(5)),\n                    \"l:\" + matcher.group(3).trim(),\n                    -1L,\n                    Account.LOANS\n            ));\n        }\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found).toString());\n        }\n        super.updateComplete();\n\n        // Demo account to use with screenshots\n        //accounts.add(new Account(\"Personkonto\", Helpers.parseBalance(\"7953.37\"), \"1\"));\n        //accounts.add(new Account(\"Kapitalkonto\", Helpers.parseBalance(\"28936.08\"), \"0\"));\n\n    }\n\n    @Override\n    public void updateTransactions(Account account, Urllib urlopen) throws LoginException,\n            BankException, IOException {\n        super.updateTransactions(account, urlopen);\n\n        int accType = account.getType();\n        switch (accType) {\n            case Account.REGULAR:\n                updateRegularTransactions(account, urlopen);\n                break;\n            case Account.CCARD:\n                updateCreditTransactions(account, urlopen);\n                break;\n            default:\n                break;\n        }\n    }\n\n    private void goToPage(int pageType) throws IOException {\n        // Convenience method for going to an overview page\n        Matcher matcher;\n        String link;\n        switch (pageType) {\n            case PageType.ENTRY:\n                // Find home link\n                matcher = reHomeLink.matcher(this.lastResponse);\n                break;\n            case PageType.LOANS:\n                // Find loans link\n                matcher = reLoansLink.matcher(this.lastResponse);\n                break;\n            case PageType.CREDIT_CARDS:\n                // Get credit cards link\n                matcher = reCreditCardsLink.matcher(this.lastResponse);\n                break;\n            default:\n                return;\n        }\n        // Find link to page\n        if (matcher.find()) {\n            link = matcher.group(1);\n            // Go to page\n            this.lastResponse = urlopen.open(BASE_URL + link);\n            this.currentPageType = pageType;\n        }\n    }\n\n    public void updateRegularTransactions(Account account, Urllib urlopen)\n            throws LoginException, BankException, IOException {\n        // If we're on the entry page it's easy to just find the link to the account and navigate to it,\n        // If we're already on a transaction page we use the account-switching form instead of going\n        // back to the entry page and starting over. This saves us 1 request.\n\n        Matcher matcher;\n        String link = null;\n        List<NameValuePair> postData = new ArrayList<NameValuePair>();\n\n        if (this.currentPageType != PageType.ENTRY\n                && this.currentPageType != PageType.TRANSACTIONS) {\n            goToPage(PageType.ENTRY);\n        }\n        if (currentPageType == PageType.ENTRY) {\n            // Find the link to the transaction page for this account\n            matcher = reAccountLink.matcher(this.lastResponse);\n            while (matcher.find()) {\n                if (Html.fromHtml(matcher.group(4)).toString().trim().equals(account.getId())) {\n                    link = matcher.group(1);\n                    break;\n                }\n            }\n            if (link == null) {\n                throw new BankException(\n                        res.getText(R.string.unable_to_find).toString() + \" transactions link.\");\n            }\n        } else if (currentPageType == PageType.TRANSACTIONS) {\n            // Find the account dropdown form\n            matcher = reTransactionFormContents.matcher(this.lastResponse);\n            if (!matcher.find()) {\n                throw new BankException(\n                        res.getText(R.string.unable_to_find).toString() + \" account form.\");\n            }\n            link = matcher.group(1);\n            matcher = reNonTextInputField.matcher(matcher.group(2));\n            if (!matcher.find()) {\n                throw new BankException(\n                        res.getText(R.string.unable_to_find).toString() + \" input fields.\");\n            }\n            matcher.reset();\n            // Input fields\n            while (matcher.find()) {\n                // For some odd reason, it does not like us sending the submit button... So don't.\n                if (!matcher.group(1).equals(\"submit\")) {\n                    postData.add(new BasicNameValuePair(matcher.group(2), matcher.group(3)));\n                }\n            }\n            postData.add(new BasicNameValuePair(\"transactionPeriod\", \"0\"));\n            // Account id\n            matcher = reAccountSelect.matcher(this.lastResponse);\n            if (!matcher.find()) {\n                throw new BankException(\n                        res.getText(R.string.unable_to_find).toString() + \" account selection.\");\n            }\n            // Find account to switch to in dropdown\n            matcher = reAccountOption.matcher(matcher.group(1));\n            String id = null;\n            while (matcher.find()) {\n                if (matcher.group(2).equals(account.getId())) {\n                    id = matcher.group(1);\n                    break;\n                }\n            }\n            if (id == null) {\n                throw new BankException(\n                        res.getText(R.string.unable_to_find).toString() + \" account id.\");\n            }\n            postData.add(new BasicNameValuePair(\"transactionaccount\", id));\n        } else {\n            throw new BankException(\"This should never happen. If it does: Grats, you broke it.\");\n        }\n\n        // URL established. Either we have a simple URL parsed from ENTRY-page or a base URL +\n        // a populated postData variable. This works with both.\n        this.lastResponse = urlopen.open(BASE_URL + link, postData);\n        this.currentPageType = PageType.TRANSACTIONS;\n\n        // Match up transactions for this account\n        matcher = reTransaction.matcher(this.lastResponse);\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n        while (matcher.find() && transactions.size() < MAX_TRANSACTIONS) {\n            String date = Html.fromHtml(matcher.group(1)).toString().trim();\n            String text = Html.fromHtml(matcher.group(2)).toString().trim();\n            BigDecimal amount = Helpers.parseBalance(matcher.group(3));\n            Transaction transaction = new Transaction(date, text, amount);\n            transactions.add(transaction);\n        }\n        // Add the transactions to this account\n        account.setTransactions(transactions);\n        // Set currency for this account\n        matcher = reCurrency.matcher(this.lastResponse);\n        if (matcher.find()) {\n            account.setCurrency(Html.fromHtml(matcher.group(1)).toString().trim());\n        }\n    }\n\n    public void updateCreditTransactions(Account account, Urllib urlopen)\n            throws LoginException, BankException, IOException {\n        Matcher matcher;\n        String link = null;\n        ArrayList<Transaction> transactions = new ArrayList<Transaction>();\n\n        if (this.currentPageType != PageType.CREDIT_CARDS) {\n            goToPage(PageType.CREDIT_CARDS);\n        }\n\n        // Find the link to the transaction page for this credit card\n        matcher = reCreditCardLink.matcher(this.lastResponse);\n        while (matcher.find()) {\n            if ((\"c:\" + matcher.group(3)).equals(account.getId())) {\n                link = matcher.group(1);\n                break;\n            }\n        }\n        if (link == null) {\n            throw new BankException(\n                    res.getText(R.string.unable_to_find).toString() + \" transactions link.\");\n        }\n\n        this.lastResponse = urlopen.open(BASE_URL + link);\n        this.currentPageType = PageType.CREDIT_CARD_TRANSACTIONS;\n\n        matcher = reCreditCardTransaction.matcher(this.lastResponse);\n        while (matcher.find() && transactions.size() < MAX_TRANSACTIONS) {\n            String date = matcher.group(1);\n            String text = matcher.group(2);\n            BigDecimal amount = Helpers.parseBalance(matcher.group(4));\n            Transaction transaction = new Transaction(date, text, amount);\n            transactions.add(transaction);\n        }\n        // Add the transactions to this account\n        account.setTransactions(transactions);\n        // Set currency for this account\n        matcher = reCreditCardCurrency.matcher(this.lastResponse);\n        if (matcher.find()) {\n            account.setCurrency(Html.fromHtml(matcher.group(1)).toString().trim());\n        }\n    }\n\n    private static class PageType {\n\n        public static final int LOGIN = 0;\n\n        public static final int SIMPLE_LOGIN = 1;\n\n        public static final int ENTRY = 2;\n\n        public static final int TRANSACTIONS = 3;\n\n        public static final int LOANS = 4;\n\n        public static final int CREDIT_CARDS = 5;\n\n        public static final int CREDIT_CARD_TRANSACTIONS = 6;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/rikslunchen/Rikslunchen.java",
    "content": "/*\n * Copyright (C) 2014 Nullbyte <http://nullbyte.eu>\n * Contributors: PMC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.banking.banks.rikslunchen;\n\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.ObjectReader;\nimport com.liato.bankdroid.banking.Account;\nimport com.liato.bankdroid.banking.Bank;\nimport com.liato.bankdroid.banking.exceptions.BankChoiceException;\nimport com.liato.bankdroid.banking.exceptions.BankException;\nimport com.liato.bankdroid.banking.exceptions.LoginException;\nimport com.liato.bankdroid.legacy.R;\n\nimport org.apache.http.HttpResponse;\nimport android.content.Context;\nimport android.text.InputType;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\n\nimport eu.nullbyte.android.urllib.CertificateReader;\nimport eu.nullbyte.android.urllib.Urllib;\n\npublic class Rikslunchen extends Bank {\n\n    private static final String NAME = \"Rikslunchen\";\n\n    private static final String URL = \"http://www.rikslunchen.se/index.html\";\n\n    private static final int BANKTYPE_ID = Bank.RIKSLUNCHEN;\n\n    private static final String BASE_URL = \"http://www.rikslunchen.se/isr/isr/services/bankdroid/getbalance\";\n\n    private static final ObjectReader READER = new ObjectMapper().reader();\n\n    public Rikslunchen(Context context) {\n        super(context, R.drawable.logo_rikslunchen);\n\n        super.url = URL;\n        super.inputTypeUsername = InputType.TYPE_CLASS_PHONE;\n        super.inputTitletextUsername = R.string.card_id;\n        super.inputHiddenPassword = true;\n    }\n\n    @Override\n    public int getBanktypeId() {\n        return BANKTYPE_ID;\n    }\n\n    @Override\n    public String getName() {\n        return NAME;\n    }\n\n    public Rikslunchen(String username, String password, Context context) throws BankException,\n            LoginException, BankChoiceException, IOException {\n        this(context);\n        this.update(username, password);\n    }\n\n    @Override\n    public Urllib login() throws LoginException, BankException {\n        return urlopen;\n    }\n\n    @Override\n    public void update() throws BankException, LoginException, BankChoiceException, IOException {\n        super.update();\n        if (getUsername().isEmpty()) {\n            throw new LoginException(res.getText(R.string.invalid_card_number).toString());\n        }\n\n        urlopen = new Urllib(context,\n                CertificateReader.getCertificates(context, R.raw.cert_rikslunchen));\n\n        HttpResponse response = urlopen.openAsHttpResponse(\n                BASE_URL + \"?cardid=\" + getUsername(),\n                false);\n        if (response.getStatusLine().getStatusCode() != 200) {\n            response.getEntity().consumeContent();\n            throw new LoginException(context.getString(R.string.invalid_card_number));\n        }\n\n        JsonNode node = READER.readTree(response.getEntity().getContent());\n\n        BigDecimal balance = new BigDecimal(node.get(\"balance\").asDouble());\n            accounts.add(new Account(\"Rikslunchen\", balance, \"1\"));\n\n        if (accounts.isEmpty()) {\n            throw new BankException(res.getText(R.string.no_accounts_found)\n                    .toString());\n        }\n        super.updateComplete();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/banks/rikslunchen/model/Envelope.java",
    "content": "package com.liato.bankdroid.banking.banks.rikslunchen.model;\n\nimport org.simpleframework.xml.Element;\nimport org.simpleframework.xml.Root;\n\n/*\n<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n    <soap:Body>\n        <ns2:getBalanceResponse xmlns:ns2=\"urn:PhoneService\">\n            <return>\n                <amount>1101.14</amount>\n                <lastTopUpDate>2014-01-01</lastTopUpDate>\n            </return>\n        </ns2:getBalanceResponse>\n        <soap:Fault>\n            <faultcode>soap:Server</faultcode>\n            <faultstring>card for 48565643 cannot be found!</faultstring>\n        </soap:Fault>\n    </soap:Body>\n</soap:Envelope>\n */\n\n@Root\npublic class Envelope {\n\n    @Element(name = \"Body\")\n    public Body body;\n\n    public static class Body {\n\n        @Element(required = false)\n        public GetBalanceResponse getBalanceResponse;\n\n        @Element(name = \"Fault\", required = false)\n        public Fault fault;\n\n        public static class GetBalanceResponse {\n\n            @Element(name = \"return\")\n            public Return responseReturn;\n\n            public static class Return {\n\n                @Element\n                public String amount;\n\n                @Element\n                public String lastTopUpDate;\n            }\n        }\n\n        public static class Fault {\n\n            @Element\n            public String faultcode;\n\n            @Element\n            public String faultstring;\n        }\n    }\n}"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/exceptions/BankChoiceException.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.exceptions;\n\nimport com.liato.bankdroid.banking.BankChoice;\n\nimport java.util.ArrayList;\n\npublic class BankChoiceException extends Exception {\n\n    private static final long serialVersionUID = 1L;\n\n    private ArrayList<BankChoice> banks;\n\n    public BankChoiceException(String message) {\n        super(message);\n    }\n\n    public BankChoiceException(String message, ArrayList<BankChoice> banks) {\n        super(message);\n        this.banks = banks;\n    }\n\n    /**\n     * @return the banks\n     */\n    public ArrayList<BankChoice> getBanks() {\n        return banks;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/exceptions/BankException.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.exceptions;\n\npublic class BankException extends Exception {\n\n    private static final long serialVersionUID = 1L;\n\n    public BankException(String message) {\n        super(message);\n    }\n\n    public BankException(String message, Throwable throwable) {\n        super(message, throwable);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/banking/exceptions/LoginException.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.liato.bankdroid.banking.exceptions;\n\npublic class LoginException extends Exception {\n\n    private static final long serialVersionUID = 1L;\n\n    public LoginException(String message) {\n        super(message);\n    }\n\n    public LoginException(String message, Exception cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/provider/IAccountTypes.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.provider;\n\n/**\n * Defines what types of accounts are supported.\n *\n * @since 8 jan 2011\n */\npublic interface IAccountTypes {\n\n    int REGULAR = 1;\n    int FUNDS = 2;\n    int LOANS = 3;\n    int CCARD = 4;\n    int OTHER = 5;\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/provider/IBankTransactionsProvider.java",
    "content": "/*\n * Copyright (C) 2010 Magnusart <http://www.magnusart.com>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.provider;\n\n/**\n * <p>\n * This interface provides constants that can conveniently be used with the\n * BankTransactionProvider. Copy this file and use it in your\n * ContentProviderClient code.\n * </p>\n * <p>\n * Uri format for querying for all transaction of a given bank/account\n * combination:<br/>\n * <code><b>content://{{@link #AUTHORITY}}/{{@link #TRANSACTIONS_CAT}}/{{@link\n * #API_KEY}}={yourkey}</code>\n * <br>\n * <code><b>Would result in: content://com.liato.bankdroid.provider.BankTransactionsProvider/transactions/API_KEY=AAABBBCCC111222</code>\n * </b>\n * </p>\n *\n * <p>\n * <b>Example of reading transactions from a View that implements this\n * interface:</b>\n *\n * <pre>\n * final Uri uri = Uri.parse(&quot;content://&quot; + AUTHORITY + &quot;/&quot; + TRANSACTIONS_CAT\n *         + &quot;/&quot; + API_KEY + apiKey);\n * final Cursor cur = managedQuery(uri, TRANSACTIONS_PROJECTION, ACCOUNT_SELECTION_FILTER, new\n * String[] { currentAccountId }, null);\n * startManagingCursor(cur);\n * </pre>\n *\n * Where <code>currentAccountId</code> is the account ID you wish to filter on.\n * </p>\n *\n * @author Magnus Andersson\n * @version 1.0-RC2\n * @see BankTransactionsProvider\n * @since 8 jan 2011\n */\npublic interface IBankTransactionsProvider {\n\n    /**\n     * <p>\n     * The authority part of the URI.\n     * </p>\n     */\n    String AUTHORITY = \"com.liato.bankdroid.provider.BankTransactionsProvider\";\n\n    /**\n     * <p>\n     * The API Key part of the URI.\n     * </p>\n     */\n    String API_KEY = \"API_KEY=\";\n\n    // ====================================MIME-TYPES======================================\n    /**\n     * <p>\n     * MIME-type for Transactions. Not use today (no inserts) added for clarity.\n     * </p>\n     */\n    String TRANSACTIONS_MIME = \"vnd.android.cursor.dir/vnd.bankdroid.transactions\";\n\n    /**\n     * <p>\n     * MIME-type for Bank/Account. Not use today (no inserts) added for clarity.\n     * </p>\n     */\n    String BANK_ACCOUNTS_MIME = \"vnd.android.cursor.dir/vnd.bankdroid.bankaccounts\";\n\n    // ===================================CATEGORIES=======================================\n    /**\n     * <p>\n     * A category part of the URI.\n     * </p>\n     */\n    String BANK_ACCOUNTS_CAT = \"bankaccounts\";\n\n    /**\n     * <p>\n     * A category part of the URI.\n     * </p>\n     */\n    String TRANSACTIONS_CAT = \"transactions\";\n\n    // ===================================BANK/ACCOUNT_FIELDS==============================\n    /**\n     * <p>\n     * ID for Bank.\n     * </p>\n     * <b>PLEASE NOTE</b><br>\n     * This is an BankDroid internal id, do not depend on this id for keeping\n     * track between sessions.</p>\n     */\n    String BANK_ID = \"_id\";\n    /**\n     * <p>\n     * Use this order by to make sure that all account belonging to one Bank\n     * comes clustered.\n     * </p>\n     */\n    String ORDER_BY_BANK_ACCOUNT = BANK_ID + \" DESC\";\n    /**\n     * <p>\n     * User defined custom name for the Bank\n     * </p>\n     */\n    String BANK_NAME = \"custname\";\n    /**\n     * <p>\n     * Type of Bank.\n     * </p>\n     *\n     * @see IBankTypes\n     */\n    String BANK_TYPE = \"banktype\";\n    /**\n     * <p>\n     * Last time the bank and the bank accounts were synchronized.\n     * </p>\n     */\n    String BANK_LAST_UPDATED = \"updated\";\n    /**\n     * <p>\n     * Account id, this is a composite key that\n     * </p>\n     * <b>PLEASE NOTE</b><br>\n     * This is an BankDroid internal id, do not depend on this id for keeping\n     * track between sessions.</p>\n     *\n     * @See {@link #TRANS_ACCNT}, {@link #ACCOUNT_SELECTION_FILTER}\n     */\n    String ACC_ID = \"id\";\n    /**\n     * <p>\n     * Name of the account.\n     * </p>\n     */\n    String ACC_NAME = \"name\";\n    /**\n     * <p>\n     * The account Type.\n     * </p>\n     *\n     * @See {@link IAccountTypes}\n     */\n    String ACC_TYPE = \"acctype\";\n    /**\n     * <p>\n     * The account balance.\n     * </p>\n     * <p>\n     * <i>Note! This will most likely differ from the total amount that can be\n     * calculated from transactions.</i>\n     * </p>\n     */\n    String ACC_BALANCE = \"balance\";\n    /**\n     * <p>\n     * The projection (ie. db view) that works with the\n     * {@link #BANK_ACCOUNTS_CAT} category.\n     * </p>\n     */\n    String[] BANK_ACCOUNT_PROJECTION = {BANK_ID, BANK_NAME, BANK_TYPE,\n            BANK_LAST_UPDATED, ACC_ID, ACC_BALANCE, ACC_NAME, ACC_TYPE};\n    /**\n     * Defines if an account is hidden.\n     */\n    String ACC_HIDDEN = \"hidden\";\n    /**\n     * <p>\n     * Use this filter to ignore hidden accounts (Hidden accounts only used for\n     * debug purposes). Always use this filter or incorporate it into your own\n     * filters.\n     * </p>\n     */\n    String NO_HIDDEN_ACCOUNTS_FILTER = ACC_HIDDEN + \" = 0\";\n\n    // ===================================TRANSACTION_FIELDS===============================\n    /**\n     * <p>\n     * Transaction ID.\n     * </p>\n     * <p>\n     * <b>PLEASE NOTE</b><br>\n     * This is an BankDroid internal id, not the actual bank transaction id.\n     * </p>\n     */\n    String TRANS_ID = \"_id\";\n\n    /**\n     * <p>\n     * Date of Transaction.\n     * </p>\n     */\n    String TRANS_DATE = \"transdate\";\n\n    /**\n     * <p>\n     * Description text of Transaction.\n     * </p>\n     */\n    String TRANS_DESC = \"btransaction\";\n\n    /**\n     * <p>\n     * Amount of Transaction.\n     * </p>\n     * <p>\n     * String representation of a {@link BigDecimal}. Positive for <i>Income</i>\n     * and negative for <i>Expenses</i>.\n     * </p>\n     */\n    String TRANS_AMT = \"amount\";\n\n    /**\n     * <p>\n     * Currency of the Transaction. (Currently Only SEK)\n     * </p>\n     */\n    String TRANS_CUR = \"currency\";\n\n    /**\n     * <p>\n     * The account a transaction belongs to.\n     * </p>\n     */\n    String TRANS_ACCNT = \"account\";\n\n    /**\n     * <p>\n     * The projection (ie. db view) that works with the\n     * {@link #TRANSACTIONS_CAT} category.\n     * </p>\n     */\n    String[] TRANSACTIONS_PROJECTION = {TRANS_ID, TRANS_DATE, TRANS_DESC,\n            TRANS_AMT, TRANS_CUR, TRANS_ACCNT};\n\n    /**\n     * <p>\n     * Use this filter to only return transactions belonging to a certain\n     * account.\n     * </p>\n     *\n     * <p>\n     * The format for the composite bank/account ID is {BANK_ID}_{ACCOUNT_ID}.<br>\n     * <b>Example IDs:</b> 1_1 or 1_0\n     * </p>\n     *\n     * @See {@link #ACC_ID}\n     */\n    String ACCOUNT_SELECTION_FILTER = TRANS_ACCNT + \" = ?\";\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/provider/IBankTypes.java",
    "content": "/*\n * Copyright (C) 2013 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.liato.bankdroid.provider;\n\n/**\n * Defines what types banks are supported.\n *\n * @since 8 jan 2011\n */\npublic interface IBankTypes {\n\n    int TESTBANK = 0;\n    int NORDEA = 2;\n    int LANSFORSAKRINGAR = 4;\n    int COOP = 6;\n    int ICA = 7;\n    int OKQ8 = 12;\n    int FIRSTCARD = 14;\n    int PAYSON = 16;\n    int JOJO = 17;\n    int IKANOBANK = 18;\n    int RIKSLUNCHEN = 22;\n    int HEMKOP = 23;\n    int NORDNET = 25;\n    int SEVENDAY = 26;\n    int OSUUSPANKKI = 27;\n    int CSN = 29;\n    int AMERICANEXPRESS = 31;\n    int MCDONALDS = 32;\n    int PLUSGIROT = 40;\n    int IKEA = 47;\n    int DANSKEBANK = 52;\n    int VASTTRAFIK = 54;\n    int EVERYDAYCARD = 55;\n    int AKELIUSINVEST = 56;\n    int MENIGA = 57;\n    int RIKSKORTET = 58;\n    int BIOKLUBBEN = 59;\n    int CHALMREST = 60;\n    int AKELIUSSPAR = 62;\n    int SVENSKASPEL = 63;\n    int APPEAKPOKER = 65;\n    int BRUMMER_KF = 67;\n    int ZIDISHA = 68;\n    int BETTERGLOBE = 69;\n    int BITCOIN = 72;\n    int SVEADIREKT = 74;\n    int BLEKINGETRAFIKEN = 77;\n    int OSTGOTATRAFIKEN = 78;\n    int BREDBAND2VOIP = 79;\n    int MINPENSION = 81;\n    int HORS = 86;\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/utils/ExceptionUtils.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.annotation.VisibleForTesting;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Arrays;\n\nimport timber.log.Timber;\n\npublic class ExceptionUtils {\n    private static final String PREFIX = \"com.liato.bankdroid.\";\n\n    /**\n     * Modify an Exception to make it look like it was ultimately caused by Bankdroid.\n     * <p/>\n     * The purpose is to make Crashlytics report Urllib exceptions as coming from whatever\n     * bank Urllib is trying to access.\n     * <p/>\n     * For example, this exception:\n     * <pre>\n     * java.lang.Exception: This is a test Exception\n     *     at not.bankdroid.at.all.ExceptionFactory.getException(ExceptionFactory.java:20)\n     *     at com.liato.bankdroid.utils.ExceptionUtilsTest.testBlameBankdroid(ExceptionUtilsTest.java:16)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n     *     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n     *     at java.lang.reflect.Method.invoke(Method.java:497)\n     *     at ...\n     * </pre>\n     *\n     * Would be turned into this exception:\n     * <pre>\n     * java.lang.Exception: This is a test Exception\n     *     at not.bankdroid.at.all.ExceptionFactory.getException(ExceptionFactory.java:20)\n     *     at com.liato.bankdroid.utils.ExceptionUtilsTest.testBlameBankdroid(ExceptionUtilsTest.java:16)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n     *     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n     *     at java.lang.reflect.Method.invoke(Method.java:497)\n     *     at ...\n     * Caused by: java.lang.Exception: This is a test Exception\n     *     at com.liato.bankdroid.utils.ExceptionUtilsTest.testBlameBankdroid(ExceptionUtilsTest.java:16)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n     *     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n     *     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n     *     at java.lang.reflect.Method.invoke(Method.java:497)\n     *     at ...\n     *     ... 37 more\n     * </pre>\n     */\n    public static void blameBankdroid(Throwable exception) {\n        Throwable ultimateCause = getUltimateCause(exception);\n        if (ultimateCause == null) {\n            // Unable to find ultimate cause, never mind\n            return;\n        }\n\n        StackTraceElement[] bankdroidifiedStacktrace =\n                bankdroidifyStacktrace(ultimateCause.getStackTrace());\n        if (bankdroidifiedStacktrace.length == 0) {\n            // No Bankdroid stack frames found, never mind\n            return;\n        }\n        if (bankdroidifiedStacktrace.length == ultimateCause.getStackTrace().length) {\n            // Bankdroid already to blame, never mind\n            return;\n        }\n\n        Throwable fakeCause = cloneException(ultimateCause);\n        if (fakeCause == null) {\n            Timber.w(new RuntimeException(\n                    \"Unable to bankdroidify exception of class: \" + ultimateCause.getClass()));\n            return;\n        }\n\n        // Put the bankdroidified stack trace before the fakeCause's actual stack trace\n        fakeCause.setStackTrace(concatArrays(bankdroidifiedStacktrace, fakeCause.getStackTrace()));\n\n        ultimateCause.initCause(fakeCause);\n    }\n\n    @VisibleForTesting\n    static StackTraceElement[] concatArrays(StackTraceElement[] a, StackTraceElement[] b) {\n        StackTraceElement[] returnMe = new StackTraceElement[a.length + b.length];\n        System.arraycopy(a, 0, returnMe, 0, a.length);\n        System.arraycopy(b, 0, returnMe, a.length, b.length);\n        return returnMe;\n    }\n\n    @VisibleForTesting\n    @Nullable\n    static Throwable getUltimateCause(Throwable t) {\n        int laps = 0;\n        Throwable ultimateCause = t;\n        while (ultimateCause.getCause() != null) {\n            ultimateCause = ultimateCause.getCause();\n            if (laps++ > 10) {\n                return null;\n            }\n        }\n        return ultimateCause;\n    }\n\n    /**\n     * Clone message and stacktrace but not the cause.\n     */\n    @Nullable\n    @VisibleForTesting\n    static <T extends Throwable> T cloneException(T wrapMe) {\n        Class<?> newClass = wrapMe.getClass();\n        while (newClass != null) {\n            try {\n                T returnMe =\n                        (T) newClass.getConstructor(String.class).newInstance(wrapMe.getMessage());\n                returnMe.setStackTrace(wrapMe.getStackTrace());\n                return returnMe;\n            } catch (InvocationTargetException e) {\n                newClass = newClass.getSuperclass();\n            } catch (NoSuchMethodException e) {\n                newClass = newClass.getSuperclass();\n            } catch (InstantiationException e) {\n                newClass = newClass.getSuperclass();\n            } catch (IllegalAccessException e) {\n                newClass = newClass.getSuperclass();\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Remove all initial non-Bankdroid frames from a stack.\n     *\n     * @return A copy of rawStack but with the initial non-Bankdroid frames removed, or null\n     * if no sensible answer can be given.\n     */\n    @VisibleForTesting\n    @NonNull\n    static StackTraceElement[] bankdroidifyStacktrace(final StackTraceElement[] rawStack) {\n        for (int i = 0; i < rawStack.length; i++) {\n            StackTraceElement stackTraceElement = rawStack[i];\n            if (stackTraceElement.getClassName().startsWith(PREFIX)) {\n                return Arrays.copyOfRange(rawStack, i, rawStack.length);\n            }\n        }\n\n        // No Bankdroid stack frames found, never mind\n        return new StackTraceElement[0];\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/utils/FieldTypeMapper.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport com.liato.bankdroid.api.configuration.FieldType;\n\nimport android.text.InputType;\n\n// TODO Move to app module when all legacy banks have been converted.\npublic class FieldTypeMapper {\n\n    public static FieldType toFieldType(int androidFieldType) {\n        switch (androidFieldType) {\n            case InputType.TYPE_CLASS_NUMBER:\n                return FieldType.NUMBER;\n            case InputType.TYPE_CLASS_PHONE:\n                return FieldType.PHONE;\n            case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:\n                return FieldType.EMAIL;\n            default:\n                return FieldType.TEXT;\n        }\n    }\n    public static int fromFieldType(FieldType fieldType) {\n        switch (fieldType) {\n            case NUMBER:\n                return InputType.TYPE_CLASS_NUMBER;\n            case PHONE:\n                return InputType.TYPE_CLASS_PHONE;\n            case EMAIL:\n                return InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;\n            default:\n                return InputType.TYPE_CLASS_TEXT;\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/utils/Installation.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport android.content.Context;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.util.UUID;\n\n/**\n * Provides a unique identification for the installation.\n *\n * The id is generated the first time the {@link #id(android.content.Context)} is called\n * and are then persisted until the application is uninstalled.\n *\n * @see <a href=\"http://android-developers.blogspot.se/2011/03/identifying-app-installations.html\">Identifying\n * App Installations</a>.\n */\npublic class Installation {\n\n    private static final String INSTALLATION = \"INSTALLATION\";\n\n    private static String sID = null;\n\n    /**\n     * Get the unique identification for the installation.\n     * A new id will be generated the first time the method is called and are then\n     * persisted until the application is uninstalled.\n     *\n     * @return The unique identification for the installed application.\n     */\n    public synchronized static String id(Context context) {\n        if (sID == null) {\n            File installation = new File(context.getFilesDir(), INSTALLATION);\n            try {\n                if (!installation.exists()) {\n                    writeInstallationFile(installation);\n                }\n                sID = readInstallationFile(installation);\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return sID;\n    }\n\n    private static String readInstallationFile(File installation) throws IOException {\n        RandomAccessFile f = new RandomAccessFile(installation, \"r\");\n        byte[] bytes = new byte[(int) f.length()];\n        f.readFully(bytes);\n        f.close();\n        return StringUtils.toString(bytes);\n    }\n\n    private static void writeInstallationFile(File installation) throws IOException {\n        FileOutputStream out = new FileOutputStream(installation);\n        String id = UUID.randomUUID().toString();\n        out.write(StringUtils.getBytes(id));\n        out.close();\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/com/liato/bankdroid/utils/StringUtils.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport java.io.UnsupportedEncodingException;\n\npublic class StringUtils {\n    private static final String CHARSET = \"UTF-8\";\n\n    private StringUtils() {\n        // This constructor is here to prevent people from instantiating this utility class\n    }\n\n    public static byte[] getBytes(String string) {\n        try {\n            return string.getBytes(CHARSET);\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(\"Internal error\", e);\n        }\n    }\n\n    public static String toString(byte[] bytes) {\n        try {\n            return new String(bytes, CHARSET);\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(\"Internal error\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/CertPinningSSLSocketFactory.java",
    "content": "package eu.nullbyte.android.urllib;\n\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nimport org.apache.http.conn.ConnectTimeoutException;\nimport org.apache.http.conn.ssl.SSLSocketFactory;\nimport org.apache.http.params.HttpConnectionParams;\nimport org.apache.http.params.HttpParams;\n\nimport android.os.Build;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.UnknownHostException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.TrustManager;\n\nimport timber.log.Timber;\n\npublic class CertPinningSSLSocketFactory extends SSLSocketFactory {\n\n    private SSLContext sslcontext = null;\n\n    private Certificate[] certificates;\n\n    private String lastHost;\n\n    private CertPinningTrustManager mTrustManager;\n\n    private ClientCertificate mClientCertificate;\n\n    public CertPinningSSLSocketFactory(ClientCertificate clientCertificate,\n            Certificate[] certificates)\n            throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException,\n            KeyManagementException {\n        super(null);\n        this.certificates = certificates;\n        this.mClientCertificate = clientCertificate;\n        setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);\n    }\n\n    private SSLContext createSSLContext() throws IOException {\n        //Log.v(TAG, \"createSSLContext()\");\n        try {\n            SSLContext context = SSLContext.getInstance(\"TLS\");\n            mTrustManager = new CertPinningTrustManager(certificates, lastHost);\n            KeyManager[] keyManagers = null;\n            if (mClientCertificate != null) {\n                KeyManagerFactory kmf = KeyManagerFactory.getInstance(\n                        KeyManagerFactory.getDefaultAlgorithm());\n                kmf.init(mClientCertificate.getKeyStore(),\n                        mClientCertificate.getPassword().toCharArray());\n                keyManagers = kmf.getKeyManagers();\n            }\n            context.init(keyManagers, new TrustManager[]{mTrustManager}, null);\n            return context;\n        } catch (Exception e) {\n            throw new IOException(e.getMessage(), e);\n        }\n    }\n\n//    private static KeyManager2 extends KeyManager\n\n    private SSLContext getSSLContext() throws IOException {\n        //Log.v(TAG, \"getSSLContext()\");\n        if (this.sslcontext == null) {\n            this.sslcontext = createSSLContext();\n        }\n        return this.sslcontext;\n    }\n\n    /**\n     * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket,\n     * String, int, java.net.InetAddress, int,\n     * org.apache.http.params.HttpParams)\n     */\n    @Override\n    public Socket connectSocket(Socket sock, String host, int port,\n            InetAddress localAddress, int localPort, HttpParams params)\n            throws IOException, UnknownHostException, ConnectTimeoutException {\n        //Log.v(TAG, \"connectSocket(socket: \" + sock + \", host: \" + host + \", port: \" + port + \", localAddress: \" + localAddress + \", localPort: \" + localPort + \", params: \" + params);\n        int connTimeout = HttpConnectionParams.getConnectionTimeout(params);\n        int soTimeout = HttpConnectionParams.getSoTimeout(params);\n\n        InetSocketAddress remoteAddress = new InetSocketAddress(host, port);\n        SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());\n\n        if ((localAddress != null) || (localPort > 0)) {\n            // we need to bind explicitly\n            if (localPort < 0) {\n                localPort = 0; // indicates \"any\"\n            }\n            InetSocketAddress isa = new InetSocketAddress(localAddress,\n                    localPort);\n            sslsock.bind(isa);\n        }\n\n        sslsock.connect(remoteAddress, connTimeout);\n        sslsock.setSoTimeout(soTimeout);\n        try {\n            getHostnameVerifier().verify(host, sslsock);\n            // verifyHostName() didn't blowup - good!\n        } catch (IOException iox) {\n            // close the socket before re-throwing the exception\n            try {\n                sslsock.close();\n            } catch (Exception e) {\n                Timber.w(e, \"Error closing SSL socket (ignored)\");\n            }\n            throw iox;\n        }\n        return sslsock;\n    }\n\n    /**\n     * @see org.apache.http.conn.scheme.SocketFactory#createSocket()\n     */\n    @Override\n    public Socket createSocket() throws IOException {\n        //Log.v(TAG, \"createSocket()\");\n        return secureSocket(getSSLContext().getSocketFactory().createSocket());\n    }\n\n\n    /**\n     * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,\n     * String, int, boolean)\n     */\n    @Override\n    public Socket createSocket(Socket socket, String host, int port, boolean autoClose)\n            throws IOException, UnknownHostException {\n        //Log.v(TAG, \"createSocket(socket: \" + socket + \", host: \" + host + \", port: \" + port + \", autoClose: \" + autoClose);\n        lastHost = host;\n        return secureSocket(\n                getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose));\n    }\n\n    public void setHost(String host) {\n        lastHost = host;\n        if (mTrustManager != null) {\n            mTrustManager.setHost(host);\n        }\n    }\n\n    private Socket secureSocket(Socket socket) {\n        if (!(socket instanceof SSLSocket)) {\n            return socket;\n        }\n\n        SSLSocket vSocket = (SSLSocket) socket;\n\n        // Remove SSLv3 support.\n        // See https://code.google.com/p/android/issues/detail?id=78187\n        List<String> supportedProtocols = new ArrayList<String>(\n                Arrays.asList(vSocket.getSupportedProtocols()));\n        supportedProtocols.remove(\"SSLv3\");\n        vSocket.setEnabledProtocols(\n                supportedProtocols.toArray(new String[supportedProtocols.size()]));\n\n        // Fix for supporting old servers.\n        // See https://code.google.com/p/android-developer-preview/issues/detail?id=1200#c23\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {\n            List<String> ciphers = new ArrayList<String>(\n                    Arrays.asList(vSocket.getEnabledCipherSuites()));\n            ciphers.remove(\"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\");\n            ciphers.remove(\"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\");\n            vSocket.setEnabledCipherSuites(ciphers.toArray(new String[ciphers.size()]));\n        }\n        return vSocket;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/CertPinningTrustManager.java",
    "content": "package eu.nullbyte.android.urllib;\n\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.Arrays;\n\nimport javax.net.ssl.X509TrustManager;\n\npublic class CertPinningTrustManager implements X509TrustManager {\n\n    private Certificate[] certificates;\n\n    private String host;\n\n    public CertPinningTrustManager(Certificate[] certificates, String host) {\n        this.certificates = certificates;\n        this.host = host;\n    }\n\n    public X509Certificate[] getAcceptedIssuers() {\n        return new X509Certificate[0];\n    }\n\n    @Override\n    public void checkClientTrusted(X509Certificate[] chain, String authType)\n            throws CertificateException {\n        throw new CertificateException(\"Client authentication not implemented.\");\n    }\n\n    @Override\n    public void checkServerTrusted(X509Certificate[] chain, String authType)\n            throws java.security.cert.CertificateException {\n        for (X509Certificate certificate : chain) {\n            byte[] publicKey = certificate.getPublicKey().getEncoded();\n            for (Certificate pinnedCert : certificates) {\n                if (Arrays.equals(publicKey, pinnedCert.getPublicKey().getEncoded())) {\n                    return;\n                }\n            }\n        }\n        throw new CertificateException(host == null ? \"Server certificate not trusted.\"\n                : String.format(\"Server certificate not trusted for host: %s.\", host));\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/CertificateReader.java",
    "content": "package eu.nullbyte.android.urllib;\n\nimport android.content.Context;\n\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport timber.log.Timber;\n\npublic class CertificateReader {\n\n    public static Certificate[] getCertificates(Context context,\n            int... rawResCerts) {\n        List<Certificate> certificates = new ArrayList<>();\n        try {\n            CertificateFactory cf = CertificateFactory.getInstance(\"X.509\");\n            for (int resId : rawResCerts) {\n                InputStream is = new BufferedInputStream(context.getResources()\n                        .openRawResource(resId));\n                try {\n                    X509Certificate cert = (X509Certificate) cf.generateCertificate(is);\n                    certificates.add(cert);\n                } finally {\n                    try {\n                        is.close();\n                    } catch (IOException e) {\n                        Timber.w(e, \"Failed to close input stream\");\n                    }\n                }\n            }\n        } catch (CertificateException e) {\n            Timber.w(e, \"Generating certificate failed\");\n        }\n        return certificates.toArray(new Certificate[certificates.size()]);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/ClientCertificate.java",
    "content": "package eu.nullbyte.android.urllib;\n\nimport java.security.KeyStore;\n\npublic class ClientCertificate {\n\n    private String mPassword;\n\n    private KeyStore mKeyStore;\n\n    public ClientCertificate(KeyStore keyStore, String password) {\n        mKeyStore = keyStore;\n        mPassword = password;\n    }\n\n    public String getPassword() {\n        return mPassword;\n    }\n\n    public KeyStore getKeyStore() {\n        return mKeyStore;\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/HttpMethod.java",
    "content": "package eu.nullbyte.android.urllib;\n\npublic enum HttpMethod {\n    GET,\n    POST,\n    PUT,\n    DELETE\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/java/eu/nullbyte/android/urllib/Urllib.java",
    "content": "/*\n * Copyright (C) 2010 Nullbyte <http://nullbyte.eu>\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage eu.nullbyte.android.urllib;\n\nimport com.liato.bankdroid.legacy.BuildConfig;\nimport com.liato.bankdroid.legacy.R;\nimport com.liato.bankdroid.utils.ExceptionUtils;\n\nimport org.apache.http.ConnectionReuseStrategy;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpException;\nimport org.apache.http.HttpHost;\nimport org.apache.http.HttpRequest;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpVersion;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.NoHttpResponseException;\nimport org.apache.http.ProtocolException;\nimport org.apache.http.client.AuthenticationHandler;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.HttpRequestRetryHandler;\nimport org.apache.http.client.RedirectHandler;\nimport org.apache.http.client.RequestDirector;\nimport org.apache.http.client.ResponseHandler;\nimport org.apache.http.client.UserTokenHandler;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.client.methods.HttpUriRequest;\nimport org.apache.http.conn.ClientConnectionManager;\nimport org.apache.http.conn.ConnectionKeepAliveStrategy;\nimport org.apache.http.conn.routing.HttpRoutePlanner;\nimport org.apache.http.conn.scheme.PlainSocketFactory;\nimport org.apache.http.conn.scheme.Scheme;\nimport org.apache.http.conn.scheme.SchemeRegistry;\nimport org.apache.http.conn.ssl.SSLSocketFactory;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.apache.http.impl.client.DefaultRedirectHandler;\nimport org.apache.http.impl.client.DefaultRequestDirector;\nimport org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;\nimport org.apache.http.params.BasicHttpParams;\nimport org.apache.http.params.HttpParams;\nimport org.apache.http.params.HttpProtocolParams;\nimport org.apache.http.protocol.BasicHttpContext;\nimport org.apache.http.protocol.HTTP;\nimport org.apache.http.protocol.HttpContext;\nimport org.apache.http.protocol.HttpProcessor;\nimport org.apache.http.protocol.HttpRequestExecutor;\nimport org.apache.http.util.EntityUtils;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.Configuration;\nimport android.os.Build;\nimport android.preference.PreferenceManager;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URI;\nimport java.security.KeyManagementException;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport timber.log.Timber;\n\npublic class Urllib {\n\n    private final static int MAX_RETRIES = 5;\n\n    public final static String DEFAULT_USER_AGENT\n            = \"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17\";\n\n    private String userAgent = null;\n\n    private DefaultHttpClient httpclient;\n\n    private HttpContext mHttpContext;\n\n    private String currentURI;\n\n    private String charset = HTTP.UTF_8;\n\n    private HashMap<String, String> headers;\n\n    private Context mContext;\n\n    private CertPinningSSLSocketFactory mSSLSocketFactory;\n\n\n    public Urllib(Context context) {\n        this(context, null);\n    }\n\n    public Urllib(Context context, Certificate[] pins) {\n        this(context, null, pins);\n    }\n\n    public Urllib(Context context, ClientCertificate clientCert, Certificate[] pins) {\n        mContext = context;\n        this.headers = new HashMap<String, String>();\n        userAgent = createUserAgentString();\n        HttpParams params = new BasicHttpParams();\n        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);\n        HttpProtocolParams.setContentCharset(params, this.charset);\n        params.setBooleanParameter(\"http.protocol.expect-continue\", false);\n        SchemeRegistry registry = new SchemeRegistry();\n        registry.register(new Scheme(\"http\", PlainSocketFactory.getSocketFactory(), 80));\n        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);\n        boolean trustSystemKeystore = prefs.getBoolean(\"debug_mode\", false) && prefs\n                .getBoolean(\"no_cert_pinning\", false);\n        try {\n            mSSLSocketFactory = new CertPinningSSLSocketFactory(clientCert, pins);\n            registry.register(new Scheme(\"https\",\n                    pins != null && !trustSystemKeystore ? mSSLSocketFactory\n                            : SSLSocketFactory.getSocketFactory(), 443));\n        } catch (UnrecoverableKeyException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {\n            Timber.w(e, \"Urllib: SSLSocketFactory error\");\n        }\n        ClientConnectionManager manager = new ThreadSafeClientConnManager(params, registry);\n        httpclient = new BankdroidHttpClient(manager, params);\n        mHttpContext = new BasicHttpContext();\n\n    }\n\n    public String open(String url) throws ClientProtocolException, IOException {\n        try {\n            return this.open(url, new ArrayList<NameValuePair>());\n        } catch (IOException e) {\n            ExceptionUtils.blameBankdroid(e);\n            throw e;\n        }\n    }\n\n    public String post(String url) throws ClientProtocolException, IOException {\n        return this.open(url, new ArrayList<NameValuePair>(), true);\n    }\n\n    public String open(String url, List<NameValuePair> postData)\n            throws ClientProtocolException, IOException {\n        try {\n            return open(url, postData, false);\n        } catch (IOException e) {\n            ExceptionUtils.blameBankdroid(e);\n            throw e;\n        }\n    }\n\n    public String open(String url, List<NameValuePair> postData, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        HttpEntity entity = openAsHttpResponse(url, postData, forcePost).getEntity();\n        if (entity == null) {\n            return \"\";\n        }\n        return EntityUtils.toString(entity);\n    }\n\n    public HttpResponse openAsHttpResponse(String url, List<NameValuePair> postData,\n            boolean forcePost) throws ClientProtocolException, IOException {\n        HttpEntity entity = (postData == null || postData.isEmpty()) && !forcePost ? null\n                : new UrlEncodedFormEntity(postData, this.charset);\n        try {\n            return openAsHttpResponse(url, entity, forcePost);\n        } catch (IOException e) {\n            ExceptionUtils.blameBankdroid(e);\n            throw e;\n        }\n    }\n\n    public HttpResponse openAsHttpResponse(String url, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        return openAsHttpResponse(url, Collections.<NameValuePair>emptyList(), forcePost);\n    }\n\n    public HttpResponse openAsHttpResponse(String url, HttpEntity entity, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        try {\n            if ((entity == null) && !forcePost) {\n                return openAsHttpResponse(url, entity, HttpMethod.GET);\n            } else {\n                return openAsHttpResponse(url, entity, HttpMethod.POST);\n            }\n        } catch (IOException e) {\n            ExceptionUtils.blameBankdroid(e);\n            throw e;\n        }\n    }\n\n    public HttpResponse openAsHttpResponse(String url, HttpMethod method)\n            throws ClientProtocolException, IOException {\n        return openAsHttpResponse(url, null, method);\n    }\n\n    public HttpResponse openAsHttpResponse(String url, HttpEntity entity, HttpMethod method)\n            throws ClientProtocolException, IOException {\n        this.currentURI = url;\n        HttpResponse response;\n        String[] headerKeys = (String[]) this.headers.keySet().toArray(new String[headers.size()]);\n        String[] headerVals = (String[]) this.headers.values().toArray(new String[headers.size()]);\n        HttpUriRequest request;\n        switch (method) {\n            case GET:\n                request = new HttpGet(url);\n                break;\n            case POST:\n                request = new HttpPost(url);\n                ((HttpPost) request).setEntity(entity);\n                break;\n            case PUT:\n                request = new HttpPut(url);\n                ((HttpPut) request).setEntity(entity);\n                break;\n            default:\n                request = new HttpGet(url);\n        }\n        if (userAgent != null) {\n            request.addHeader(\"User-Agent\", userAgent);\n        }\n\n        for (int i = 0; i < headerKeys.length; i++) {\n            request.addHeader(headerKeys[i], headerVals[i]);\n        }\n\n        HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {\n\n            public boolean retryRequest(IOException exception, int executionCount,\n                                        HttpContext context) {\n                // retry a max of 5 times\n                if (executionCount >= MAX_RETRIES) {\n                    return false;\n                }\n                if (exception instanceof NoHttpResponseException) {\n                    return true;\n                } else if (exception instanceof ClientProtocolException) {\n                    return true;\n                }\n                return false;\n            }\n        };\n        httpclient.setHttpRequestRetryHandler(retryHandler);\n\n        response = httpclient.execute(request, mHttpContext);\n\n        //HttpUriRequest currentReq = (HttpUriRequest)mHttpContext.getAttribute(ExecutionContext.HTTP_REQUEST);\n        //HttpHost currentHost = (HttpHost)mHttpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);\n        //this.currentURI = currentHost.toURI() + currentReq.getURI();\n        this.currentURI = request.getURI().toString();\n\n        return response;\n    }\n\n    public InputStream openStream(String url) throws ClientProtocolException, IOException {\n        return openStream(url, (HttpEntity) null, false);\n    }\n\n    public HttpEntity toEntity(List<NameValuePair> postData) {\n        if (postData != null && !postData.isEmpty()) {\n            try {\n                return new UrlEncodedFormEntity(postData, this.charset);\n            } catch (UnsupportedEncodingException e) {\n                Timber.w(e, \"Error converting NameValuePair list to HttpEntity\");\n            }\n        }\n        return null;\n    }\n\n    public InputStream openStream(String url, List<NameValuePair> postData, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        return openStream(url, toEntity(postData), forcePost);\n    }\n\n    public InputStream openStream(String url, String postData, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        try {\n            return openStream(url, postData != null ? new StringEntity(postData, this.charset) : null,\n                    forcePost);\n        } catch (IOException e) {\n            ExceptionUtils.blameBankdroid(e);\n            throw e;\n        }\n    }\n\n    public InputStream openStream(String url, HttpEntity postData, boolean forcePost)\n            throws ClientProtocolException, IOException {\n        this.currentURI = url;\n        String[] headerKeys = (String[]) this.headers.keySet().toArray(new String[headers.size()]);\n        String[] headerVals = (String[]) this.headers.values().toArray(new String[headers.size()]);\n        HttpUriRequest request;\n        if (!forcePost && postData == null) {\n            request = new HttpGet(url);\n        } else {\n            request = new HttpPost(url);\n            ((HttpPost) request).setEntity(postData);\n        }\n        if (userAgent != null) {\n            request.addHeader(\"User-Agent\", userAgent);\n        }\n\n        for (int i = 0; i < headerKeys.length; i++) {\n            request.addHeader(headerKeys[i], headerVals[i]);\n        }\n        this.currentURI = request.getURI().toString();\n        HttpResponse response = httpclient.execute(request);\n        HttpEntity entity = response.getEntity();\n        return entity.getContent();\n    }\n\n    public void close() {\n        httpclient.getConnectionManager().shutdown();\n    }\n\n    public HttpContext getHttpContext() {\n        return mHttpContext;\n    }\n\n    public String getCurrentURI() {\n        return currentURI;\n    }\n\n    public DefaultHttpClient getHttpclient() {\n        return httpclient;\n    }\n\n    public void setContentCharset(String charset) {\n        this.charset = charset;\n        HttpProtocolParams.setContentCharset(httpclient.getParams(), this.charset);\n    }\n\n\n    public void setAllowCircularRedirects(boolean allow) {\n        httpclient.getParams().setBooleanParameter(\"http.protocol.allow-circular-redirects\", allow);\n    }\n\n    public void addHeader(String key, String value) {\n        this.headers.put(key, value);\n    }\n\n    public void setKeepAliveTimeout(final int seconds) {\n        httpclient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {\n            @Override\n            public long getKeepAliveDuration(HttpResponse response, HttpContext arg1) {\n                return seconds;\n            }\n        });\n    }\n\n    public String removeHeader(String key) {\n        return this.headers.remove(key);\n    }\n\n    public void clearHeaders() {\n        this.headers.clear();\n    }\n\n    public HashMap<String, String> getHeaders() {\n        return this.headers;\n    }\n\n    public void setFollowRedirects(boolean follow) {\n        httpclient\n                .setRedirectHandler(follow ? new DefaultRedirectHandler() : new RedirectHandler() {\n                    public URI getLocationURI(HttpResponse response,\n                            HttpContext context) throws ProtocolException {\n                        return null;\n                    }\n\n                    public boolean isRedirectRequested(HttpResponse response,\n                            HttpContext context) {\n                        return false;\n                    }\n                });\n    }\n\n\n    public void setUserAgent(String userAgent) {\n        this.userAgent = userAgent;\n    }\n\n    private String createUserAgentString() {\n        String appName = mContext.getString(R.string.app_name);\n\n        Configuration config = mContext.getResources().getConfiguration();\n        return String\n                .format(\"%1$s/%2$s (%3$s; U; Android %4$s; %5$s-%6$s; %10$s Build/%7$s; %8$s) %9$s %10$s\"\n                        , appName\n                        , BuildConfig.VERSION_NAME\n                        , System.getProperty(\"os.name\", \"Linux\")\n                        , Build.VERSION.RELEASE\n                        , config.locale.getLanguage().toLowerCase()\n                        , config.locale.getCountry().toLowerCase()\n                        , Build.ID\n                        , Build.BRAND\n                        , Build.MANUFACTURER\n                        , Build.MODEL);\n    }\n\n    private void updateSocketFactoryHost(HttpHost host) {\n        if (mSSLSocketFactory != null && host != null) {\n            mSSLSocketFactory.setHost(host.getHostName());\n        }\n    }\n\n    class BankdroidHttpClient extends DefaultHttpClient {\n\n        BankdroidHttpClient(ClientConnectionManager conman, HttpParams params) {\n            super(conman, params);\n        }\n\n        @Override\n        public <T> T execute(HttpHost target, HttpRequest request,\n                ResponseHandler<? extends T> responseHandler)\n                throws IOException, ClientProtocolException {\n            updateSocketFactoryHost(target);\n            return super.execute(target, request, responseHandler);\n        }\n\n        @Override\n        public <T> T execute(HttpHost target, HttpRequest request,\n                ResponseHandler<? extends T> responseHandler, HttpContext context)\n                throws IOException, ClientProtocolException {\n            updateSocketFactoryHost(target);\n            return super.execute(target, request, responseHandler, context);\n        }\n\n        @Override\n        protected RequestDirector createClientRequestDirector(HttpRequestExecutor requestExec,\n                ClientConnectionManager conman, ConnectionReuseStrategy reustrat,\n                ConnectionKeepAliveStrategy kastrat, HttpRoutePlanner rouplan,\n                HttpProcessor httpProcessor, HttpRequestRetryHandler retryHandler,\n                RedirectHandler redirectHandler, AuthenticationHandler targetAuthHandler,\n                AuthenticationHandler proxyAuthHandler, UserTokenHandler stateHandler,\n                HttpParams params) {\n            return new DefaultishRequestDirector(requestExec, conman, reustrat, kastrat, rouplan,\n                    httpProcessor, retryHandler, redirectHandler, targetAuthHandler,\n                    proxyAuthHandler, stateHandler, params);\n        }\n    }\n\n    class DefaultishRequestDirector extends DefaultRequestDirector {\n\n        public DefaultishRequestDirector(HttpRequestExecutor requestExec,\n                ClientConnectionManager conman, ConnectionReuseStrategy reustrat,\n                ConnectionKeepAliveStrategy kastrat, HttpRoutePlanner rouplan,\n                HttpProcessor httpProcessor, HttpRequestRetryHandler retryHandler,\n                RedirectHandler redirectHandler, AuthenticationHandler targetAuthHandler,\n                AuthenticationHandler proxyAuthHandler, UserTokenHandler userTokenHandler,\n                HttpParams params) {\n            super(requestExec, conman, reustrat, kastrat, rouplan, httpProcessor, retryHandler,\n                    redirectHandler, targetAuthHandler, proxyAuthHandler, userTokenHandler, params);\n        }\n\n        @Override\n        public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)\n                throws HttpException, IOException {\n            updateSocketFactoryHost(target);\n            return super.execute(target, request, context);\n        }\n    }\n\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_akeliusinvest.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFxzCCBK+gAwIBAgIRAMu1SQqeSHedwuADp9z64mswDQYJKoZIhvcNAQELBQAw\ngZYxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTwwOgYD\nVQQDEzNDT01PRE8gUlNBIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIFNlY3VyZSBT\nZXJ2ZXIgQ0EwHhcNMTUwNzEzMDAwMDAwWhcNMTgxMDEyMjM1OTU5WjCBojELMAkG\nA1UEBhMCQlMxDjAMBgNVBBETBTAwMDAwMQ8wDQYDVQQHEwZOYXNzYXUxHTAbBgNV\nBAkTFDI4IFBhcmxpYW1lbnQgU3RyZWV0MRswGQYDVQQKExJBa2VsaXVzIEludmVz\ndCBMdGQxEzARBgNVBAsTClByZW1pdW1TU0wxITAfBgNVBAMTGG9ubGluZS5ha2Vs\naXVzaW52ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuN\nB9V2rjv74z59m5QcTfn0x1TCJV67IkBng3UqcCfAEPgJMNo664dQwynQUSXB804B\nHHzuYQ3+qH5Fro6Y6hGMG1CDZLVVa2ORLSNObFSYnjkY+ViZ0X+6c3X0KXRywAB0\nm89FDRuxsFrwlBHkF5HsStil5lHf/HyuO1YSlvdiGE5+yk3qWFVSfL6dpo7rx1IM\npIsnxroUaCwXIpU7i2lbo3hNlUVvWZSf3zl7ZCFdf51HWL4D5JCEioSv+pL+SxbU\nP7xEOI5xBmVMYnUXvTF+uFrXgBToDb62CkEDHWdzr+22C6S4S3jni0E3ccKwkkC5\nbJcA++j7SltQGMQ3OJ0CAwEAAaOCAgAwggH8MB8GA1UdIwQYMBaAFJrzK9rPrU+2\nL7sqSEgqErcbQsEkMB0GA1UdDgQWBBQ/Uk9uaclUgvKAWwF5Tu9XueGBKDAOBgNV\nHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI\nKwYBBQUHAwIwUAYDVR0gBEkwRzA7BgwrBgEEAbIxAQIBAwQwKzApBggrBgEFBQcC\nARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMwCAYGZ4EMAQICMFoGA1Ud\nHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQU9y\nZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcmwwgYsGCCsGAQUF\nBwEBBH8wfTBVBggrBgEFBQcwAoZJaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09N\nT0RPUlNBT3JnYW5pemF0aW9uVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAk\nBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMEEGA1UdEQQ6MDiC\nGG9ubGluZS5ha2VsaXVzaW52ZXN0LmNvbYIcd3d3Lm9ubGluZS5ha2VsaXVzaW52\nZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAa5GjqAFzZizUktjUtEYEHKgtd3p0\n4NPqQzAjzxbQFyyEeNtMkK6pSde3WZ+6Lc6s3fI/GX5C32oMFDZMeAHbX7b2j98s\nqtqFKQNPD7EFWPtgWhWQq5HFt0Wp2xYmnkKqJqeemXNproulljGqPHH2NUlrF2pa\nd3gORGSsZe2ANRB3VFkhj0EAXd+C/LKcwC7GrjMMTxRRATrfKWk+SjIZBpWYa1vm\nb7M4cqBvYNrZNP2ccbUGfX7hsKYiFT/A1hBoZvzgKHxAB3Uur/HxUaoF15cTMhzh\n4Y5/2kjHQzzi+MMr88cwTvB5XoRu21SkQ8R72/eyrfzmplu7S0abQ84jXA==\n-----END CERTIFICATE-----\nonline.akeliusinvest.com:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_akeliusspar.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGwTCCBamgAwIBAgIQFYFYbpcrrScodCOX6GpT3zANBgkqhkiG9w0BAQsFADBH\nMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMX\nR2VvVHJ1c3QgRVYgU1NMIENBIC0gRzQwHhcNMTUwNzAyMDAwMDAwWhcNMTcwNzAx\nMjM1OTU5WjCBvDETMBEGCysGAQQBgjc8AgEDEwJTRTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xFDASBgNVBAUTCzU1NjYxOC04MTIzMQswCQYDVQQGEwJT\nRTESMBAGA1UECAwJU1RPQ0tIT0xNMREwDwYDVQQHDAhEYW5kZXJ5ZDEYMBYGA1UE\nCgwPQWtlbGl1cyBTcGFyIEFCMSIwIAYDVQQDDBl3d3cub25saW5lLmFrZWxpdXNz\ncGFyLnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxW/tv4Z1nFRI\n1474XUCB5Y9xLqP8QfpEAxIV8MLXudy7oHDZ+rlsodFqERmQHecELyG6VdkAaexr\nowgTL/kySzTzL6twAzBzFqzMnMWFv6u+qXzyqpBdZwSYeSWqtOrStgp4h5y3FIYd\ntuLPYpOxsSxEGlARRkP3YzuEvCIQTDJ/IqPUFyEDTNS5zUN50TGBrUVaKHXgkdCJ\nmAjq7CQqtZcMXfT9j91JX413bXmH0rHeHZQ4O75tW6anSea7yG/qmMzMJR+CNQ4s\nApDrdd0zcDCdb480j6rPfe4UQ8C8b0zvbqNkp7zYqnBmTGSy1/XysbpthztgO5UU\nH3o3jXUGgwIDAQABo4IDMTCCAy0wJAYDVR0RBB0wG4IZd3d3Lm9ubGluZS5ha2Vs\naXVzc3Bhci5zZTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDArBgNVHR8EJDAi\nMCCgHqAchhpodHRwOi8vZ20uc3ltY2IuY29tL2dtLmNybDCBoAYDVR0gBIGYMIGV\nMIGSBgkrBgEEAfAiAQYwgYQwPwYIKwYBBQUHAgEWM2h0dHBzOi8vd3d3Lmdlb3Ry\ndXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeS9sZWdhbDBBBggrBgEFBQcCAjA1\nDDNodHRwczovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL3JlcG9zaXRvcnkv\nbGVnYWwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaA\nFN7PXFC3rgIfFReqFugNtSidalrzMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcw\nAYYTaHR0cDovL2dtLnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2dtLnN5\nbWNiLmNvbS9nbS5jcnQwggF/BgorBgEEAdZ5AgQCBIIBbwSCAWsBaQB2AKS5CZC0\nGFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABTk3jEB8AAAQDAEcwRQIhALZJ\nMjvHqBi49EzI1sXL1rhCHuwCAzQ1uUDAPvpv0SZZAiAfmFyVdhXXDCymEpUGcUE8\n5zYoGulnfVT6Y5oXbeoZ1AB3AFYUBpov18Ls0/XhvUSyPsdGdrm8mRFcwO+UmFXW\nidDdAAABTk3jEPwAAAQDAEgwRgIhAMn4c16wx6WkFtYfdgKZRCVILnCTHyvnGKpO\n5p0nDfT5AiEAkxDSZpKahkAg5HduKASiXpACYiUMzVWPmvzyDWixVRcAdgBo9pj4\nH2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAU5N4xAcAAAEAwBHMEUCIEjf\nwRZ8kNALOouUbCzUbrURsWPu5t8ikmrDqXr3lLiUAiEA2OxasnxTpRudVLeirVd4\n7COaBSXod1fObkLO7/GMPtMwDQYJKoZIhvcNAQELBQADggEBADBl4dvF7pT+O7E8\nWgnjmX1kP4wzW4PZPmYoq6sKf5dA5kMwOXajwCh/jx5Z6gzaFZhclFZofqmtVYuE\nAIumm97GMF5+S8daynPGDcUabCyBP73zC8GXPWHT3alBCUxxt/Mw9aBNbyhkDSGy\nBH5/YCsJm7G2BQ9HiCLNhB8exUKCSyL9K9efDMt/fqC9qb8mJK7vUUa75cqZLNs6\nqO/trJm0DOG2ApaCtJoB10M4c9fQz2feedbIWfZrav3wBvakWEcnXug21lnXN0kg\nYs6QSd8lmmrvTyMx2PdzpozSJs1HKw4SUc1egm4Eccg7o/xTkc4PxNNcHvvTJDV6\nyXPFP60=\n-----END CERTIFICATE-----\nwww.online.akeliusspar.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_americanexpress_global.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIIYDCCB0igAwIBAgIQAaqnbsay6zOICUMaChU+CDANBgkqhkiG9w0BAQsFADB1\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk\nIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE3MDEyNDAwMDAwMFoXDTE5MDEyOTEy\nMDAwMFowggEcMR0wGwYDVQQPDBRQcml2YXRlIE9yZ2FuaXphdGlvbjETMBEGCysG\nAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgECEwhOZXcgWW9yazEPMA0GA1UE\nBRMGMTg4MDU1MR4wHAYDVQQJExUzMTUxIFcuIEJlaHJlbmQgRHJpdmUxDjAMBgNV\nBBETBTg1MDI3MQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTEQMA4GA1UE\nBxMHUGhvZW5peDEhMB8GA1UEChMYQW1lcmljYW4gRXhwcmVzcyBDb21wYW55MREw\nDwYDVQQLEwhDb25zdW1lcjEjMCEGA1UEAxMab25saW5lLmFtZXJpY2FuZXhwcmVz\ncy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOe2+mom21AxhL\nBDJNgENfGvhF8z4mcTP5EnpvJno/7+46dPcy6otIEAx9mMbBM7eiYITO6ybPMldV\nepcg0WMoNrJ0xJlp+KwKIOxP+Vg16Rz7c07fDbTaCZfzR1qfdODD8hdGKDLuaT0D\nf142jNmYG0WibBaykN3E5kvmZ6EvnwwGvfEIfVD/4TOB0fFqexWWVDJRKNQH0wKc\nVCY9UIk3BoagWKzLxV5aU5lqCHf8PAJOZ6WEnomHuXYv7Pvg3XNaxxNYfesYms09\nlEaxnLhqZIhhItfilllTX13n+vPFYTUsAJ6qnzAemJqzLsC4LAXQyz7D+TQ0nXAJ\nKJnoBYVRAgMBAAGjggRBMIIEPTAfBgNVHSMEGDAWgBQ901Cl1qCt7vNKYApl0yHU\n+PjWDzAdBgNVHQ4EFgQUo25mMJ/p72Dun3+lrHE+72I9vSIwdwYDVR0RBHAwboIa\nb25saW5lLmFtZXJpY2FuZXhwcmVzcy5jb22CG3Jld2FyZHMuYW1lcmljYW5leHBy\nZXNzLmNvbYIXcmV3YXJkcy5hZXhwLXN0YXRpYy5jb22CGmdsb2JhbC5hbWVyaWNh\nbmV4cHJlc3MuY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD\nAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNl\ncnQuY29tL3NoYTItZXYtc2VydmVyLWcxLmNybDA0oDKgMIYuaHR0cDovL2NybDQu\nZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcxLmNybDBLBgNVHSAERDBCMDcG\nCWCGSAGG/WwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j\nb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0\ndHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2Vy\ndHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNl\ncnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIB9AYKKwYBBAHWeQIEAgSCAeQEggHg\nAd4AdQCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAVnR4Z7LAAAE\nAwBGMEQCIGyUTKolX7fCjfAx0evgDlGtLmRqF/LFp3MCWl8BNY3PAiAlMUhh0X6F\nDedm4odESahntfy8d/3WV02oBfcyPJypEwB2AFYUBpov18Ls0/XhvUSyPsdGdrm8\nmRFcwO+UmFXWidDdAAABWdHhoB4AAAQDAEcwRQIgS1sYO973uUF1ck53HVNr0kIA\nkuYjUOau3K1tFllKz24CIQDYs45QOuiF91Cyr25jycnX8ppdfFjAOFmFZtC3pMkf\nOwB1AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABWdHhodwAAAQD\nAEYwRAIgCCu2KCYMQez7uGnoa3zMcg03Lj7+ubTmMe7WBBldQi4CIHg3clmsny5h\nerX47gKuoEbixn0vlUa2v3MyfIVgL0n1AHYAu9nfvB+KcbWTlCOXqpJ7RzhXlQqr\nUugakJZkNo4e0YUAAAFZ0eGf8QAABAMARzBFAiAi7IWcvkTTbpPkxqFPDffBGMH0\nNuwWoRQHO5ljt0dlfgIhANFuzMU7pPpcvoKdnHNgfsbUp47XNlsJ92RQNyH/j3fQ\nMA0GCSqGSIb3DQEBCwUAA4IBAQBN1H5e5Mzl5+R7ed8LuQgPyNBMx853wCI+lKuy\nxUwGn/DJfNo+fvcywY12wFfsQAxxOTt8ecCs68JFYJlDgnzMumHBOVQf8Psb8OEN\nW3emi7z8lnbQusItvSzZiArbrGLbPICumVrJn+eodzenWn6DAJEQAl3LbXOn4FGP\nKpijmf8hfb2I/UAwMISh4OiMcMHusoBHpekKxOTrCemLIbCKbV2sUV1o6PSN6SDq\nu7fX158B+qQxcEgn0fjAs8CVqs31lJjo/h1kb/53u2iqZFH3P2sbr0jQkVNiL2LW\nbdXhSyChR5z4w4lvj8HthWCs6kU+uzBHdtamdVkFU4d0dzi/\n-----END CERTIFICATE-----\nglobal.americanexpress.com:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_bioklubben.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGVjCCBT6gAwIBAgIQJ7c0DjE2rrf90ZxGr+exPTANBgkqhkiG9w0BAQsFADBE\nMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU\nR2VvVHJ1c3QgU1NMIENBIC0gRzMwHhcNMTYxMjE1MDAwMDAwWhcNMTgwMzE2MjM1\nOTU5WjBkMQswCQYDVQQGEwJTRTESMBAGA1UECAwJU1RPQ0tIT0xNMQ4wDAYDVQQH\nDAVTb2xuYTESMBAGA1UECgwJU0YgQmlvIEFCMQswCQYDVQQLDAJJVDEQMA4GA1UE\nAwwHKi5zZi5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKLUmrPm\n9g2Z12yVD9jnGgk3C2xrdOYqjfjFGOrU2SfTaI1L8POt2s9YspYcKkFG5EB7Iv3a\nIwL0TccsbWT1PaiVvT7hgU94n5fYjjHlMiVMdPpHunGj9KqO12/zz++eQa8xITx5\nAW3S7CYHIBqxPIU43/6ukXcmsGe4ngbHxhl7nfWcgWT/qxUA7guWqxONKNaNOsw4\nKeJizxhURT52nf5+dJIZ9j/3x8vu+WC8kJ9LQzKdFuFOZ05/Ivwj+WcISbOOaisx\naQCdkFMDtTfWPBX9CjEvAEqYsthFj2trvxZYgvnN6zR7eRdAH2chgrh9//ljApp8\n5rzAVClGncBZKq0CAwEAAaOCAyIwggMeMBkGA1UdEQQSMBCCByouc2Yuc2WCBXNm\nLnNlMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMCsGA1UdHwQkMCIwIKAeoByG\nGmh0dHA6Ly9nbi5zeW1jYi5jb20vZ24uY3JsMIGdBgNVHSAEgZUwgZIwgY8GBmeB\nDAECAjCBhDA/BggrBgEFBQcCARYzaHR0cHM6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl\nc291cmNlcy9yZXBvc2l0b3J5L2xlZ2FsMEEGCCsGAQUFBwICMDUMM2h0dHBzOi8v\nd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeS9sZWdhbDAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAU0m/3lvSFP3I8\nMH0j2oV4m6N8WnwwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8v\nZ24uc3ltY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vZ24uc3ltY2IuY29tL2du\nLmNydDCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYA3esdK3oNT6Ygi4GtgWhw\nfi6OnQHVXIiNPRHEzbbsvswAAAFZAd73PAAABAMARzBFAiEA2pXLVLlPgndL3HEz\n0c9DX2L2BJ86iWWr2hJvtMqN31ECIBR3r2mC1fxcm5fn3hdtWNl8GZmCzvRVL156\nqtMwyVgNAHYA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFZAd73\ngwAABAMARzBFAiAtaIC43JHp6fn0NSYUjwh+V+i45Rx4R/An+F+eX46c8AIhAK/x\nW4U0nreGDM7kYLg17Zf/IgdykcEWJUAo9C+pAeHYAHYAvHjh38X2PGhGSTNNoQ+h\nXwl5aSAJwIG08/aRfz7ZuKUAAAFZAd74FQAABAMARzBFAiEApvwu6gDBg3h/04gQ\nXo68xPtQhnhBK6KjDHy9+gRHj4wCIB6JlTJu/PB6mxn4EZJMJkmDjg1zul49LIKN\nlBSp8U0IMA0GCSqGSIb3DQEBCwUAA4IBAQCJuRpRxVPeK4iY19oPDdsXOkewpI1C\nZ/qM9gGyohgHSWpoTgOl3VpRXQxoyOHAjP09y9IfPcXE53tdUqRbXIyr2CLxbaMj\nQ8SkZl5li+XxYmCLSVBBeo9CZoPuztBI5i+KAki5tHtfOjynDyPmGs4UYH62c1A1\nzvPjue4k2aP6Ea7PE5JzfFiWauoc529QNjE4s84YuM0eJBU8Qv2Bz2/YrjuRhkDx\nVyolwHaaiAUpKiQqVE0Dxbpb2SbAUL6gGqeD5XmAmevJdpBcO6C88BSuVEr4SR5a\nvOINhDQg/+E6MHckR2oHKtvIDY9jhp7UsP6idjWDakl4Yc2RGsq+PPIW\n-----END CERTIFICATE-----\nbioklubben.sf.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_bredband2.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIErzCCA5egAwIBAgICBCkwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx\nFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1\nNiBDQSAtIEc0MB4XDTE1MDgwOTE1MTkzMFoXDTE4MTAxMDA2MjgxNlowgZMxEzAR\nBgNVBAsTCkdUMjcyMDEwMDUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t\nL3Jlc291cmNlcy9jcHMgKGMpMTUxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh\nbGlkYXRlZCAtIFJhcGlkU1NMKFIpMRgwFgYDVQQDDA8qLmJyZWRiYW5kMi5jb20w\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRQQ7I0h15SPzlne72jYnz\nPtGlXF/YYKZ+EsOy12AGP/W38uoQo8IHrLOuAMtMAqhA9oUFO/h0OGLNoyGBXl0F\ntJ9T/1WKmJph5LBNAq925JWgdHBokPeOxiOoyJMAYKBvCO7/cyWVADUlKt827uSL\nT85qqk1AinK2HXoE3Wh62A0obpRgqqYCpprsoPz5/NCUnJTBDBWjTuHfg6hL93qJ\nU4w/4phJfEZJmtYRFK1fCck6D1NADu35rMPI6ryvPPjtXKlsqFn29z7sJEHgo0Ay\n+zLfq5GK2ukM/y8p17RQhfesWfEzC1fYAXbTtzd0SnxeGXMa4DfJFNjtKUSdGQpd\nAgMBAAGjggFWMIIBUjAfBgNVHSMEGDAWgBTztVYMxAmwtM8fqvndI1bwd+ih+TBX\nBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly9nei5zeW1jZC5jb20w\nJgYIKwYBBQUHMAKGGmh0dHA6Ly9nei5zeW1jYi5jb20vZ3ouY3J0MA4GA1UdDwEB\n/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwKQYDVR0RBCIw\nIIIPKi5icmVkYmFuZDIuY29tgg1icmVkYmFuZDIuY29tMCsGA1UdHwQkMCIwIKAe\noByGGmh0dHA6Ly9nei5zeW1jYi5jb20vZ3ouY3JsMAwGA1UdEwEB/wQCMAAwQQYD\nVR0gBDowODA2BgZngQwBAgEwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFw\naWRzc2wuY29tL2xlZ2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAuJJabEy83JdfZu+s2\nrOCtALVhYll+g5AqUiEXCtbcckbbVAYOWWVESFuMs/mbiiaAW0qSM+7GwcoV8MFD\nfuo1kDTd7c2KThz6qUjC3u5RCh0jv0MhS0rwZghFsZc0qxMjiQnCRmj03b8KzvDQ\nLGa8CPrgEmAMmSrDnyc9ZKfkRoR9jYE3g91nIjVmmTmzTFQf3ARpZXeSoCKzkYg0\n57edtcYyTKRz2pqu0D6pQJiBYyf5L6klrNT9oC3CUR5Sd2mva7xI33vqxh3LB7LB\nps02VRWTbjDOSxv5cA1nnLx5Za8AreEna+CMcphxzdTEc75QRwm7FfOEWaAWVimh\nYMG1\n-----END CERTIFICATE-----\nportal.bredband2.com:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_brummer.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIH0jCCBrqgAwIBAgIQCRPnldXK9l40D0FXyRHdeDANBgkqhkiG9w0BAQsFADB1\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk\nIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE3MDIwMTAwMDAwMFoXDTE5MDQwNDEy\nMDAwMFowgcsxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB\nBAGCNzwCAQMTAlNFMRMwEQYDVQQFEwo1NTY2MjcyMTgyMRkwFwYDVQQJExBOb3Jy\nbWFsbXN0b3JnIDE0MQ8wDQYDVQQREwYxMTEgNDYxCzAJBgNVBAYTAlNFMRIwEAYD\nVQQHEwlTdG9ja2hvbG0xHjAcBgNVBAoMFUJydW1tZXIgJiBQYXJ0bmVycyBBQjET\nMBEGA1UEAxMKYnJ1bW1lci5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALdYobK2du+PQct99KfEdqZ1LoCjJFs6YP0h91SBXtHZn7K6E3qkNW580DWM\n6R8DSXkcpjnjZygJCtApC3A9q/7ERoGtAAJa1la5jy7RFwg5r/D3cZVur+A7W+DX\nmuegiHWQ8GfTPflGdllm3URfamHvAWgsZf8Se3pfusTY4ASsFrnOY/s+5Ip/lFHT\nWWF9bo3arY7zpK5aWKma5tDfDFHLF7uVp4XcAXNNDWd3pJlwMEOsrXQHG+GDN++D\niJ5z1T6uvdBh7pd8YNGQ7/zbEcFeLYpuMA8KkRPrP+ujF7pjgDgyaoa3Rid8pSug\nxUpeCCjAUissK3iAGzei6jmK0DECAwEAAaOCBAUwggQBMB8GA1UdIwQYMBaAFD3T\nUKXWoK3u80pgCmXTIdT4+NYPMB0GA1UdDgQWBBRgAcs5Wlfij1QTyZJv/ht7klMU\n6jA4BgNVHREEMTAvggpicnVtbWVyLnNlgg53d3cuYnJ1bW1lci5zZYIRb25saW5l\nLmJydW1tZXIuc2UwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB\nBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2Vy\ndC5jb20vc2hhMi1ldi1zZXJ2ZXItZzEuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5k\naWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzEuY3JsMEsGA1UdIAREMEIwNwYJ\nYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv\nbS9DUFMwBwYFZ4EMAQEwgYgGCCsGAQUFBwEBBHwwejAkBggrBgEFBQcwAYYYaHR0\ncDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAChkZodHRwOi8vY2FjZXJ0\ncy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyRXh0ZW5kZWRWYWxpZGF0aW9uU2Vy\ndmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwggH3BgorBgEEAdZ5AgQCBIIB5wSCAeMB\n4QB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABWfq1SfMAAAQD\nAEcwRQIhAO4WwezInv6io+B0UEpi73GMvYHOQM7F0GWZFK3UQCe8AiAslpzMJdcw\nRj0mTM/bL/j/ywOpO6BCFIEW2pYspunW0AB3AFYUBpov18Ls0/XhvUSyPsdGdrm8\nmRFcwO+UmFXWidDdAAABWfq1SGgAAAQDAEgwRgIhAMS0a56iGdE8z/NefoB2jIo4\nZDOyU2/4nG7PQqJGdhHKAiEA+lLD8gBDu/bQwJ1sjOXda58kYnIhdHBc4LsxdT51\nGYYAdwDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAVn6tUfpAAAE\nAwBIMEYCIQCpDHuNS8fHcFuKolxzwYlPAm2bc+03MPdKuomoemb/kQIhAJAeZf1o\nM5PqrSA1OAJHIZXiLc0QNKPzYBG+LkaQIgd/AHUAu9nfvB+KcbWTlCOXqpJ7RzhX\nlQqrUugakJZkNo4e0YUAAAFZ+rVJ3QAABAMARjBEAiAfH0NqXD4oPCsjeHIMtXoE\nP0JtFgT2ttt1CzeAgj79fQIgI4bv4GxKzRcODXk8WX5lccQMk72iOhSns7hVBMqD\ntDswDQYJKoZIhvcNAQELBQADggEBABZOVNT14RPE/1LSPqz3h1WnxSOC3+YjYOle\nKeNeMjBnzSk56OzwMBCFDx+82fUy0Mg5Ocue4uSJsIkeH9+t0g7bLFRo2wO/+MF6\n1VeCsGuB1PWH5aYFnLKOnUZgZh2gOk7Lv3XpmdIoRQx0SqKN29iehkjDxmM7lgKS\nmTkHw3ZOnbo5JKBHurGdmNMKcAgk3/Cg5sjaYGpMNacJBT2Uj4SYF07JScvJOi5U\nJ9nw55LUapUbPLtN8sFnxX4GCKJD0nUiQGSqRpMZlmCIAjCyKNFB1kYkfqwULU8/\nHzn3KhA/seiw6RHEE6KH4ABCGcB+f+/wTWl9EpBBxaFQvsMmDTY=\n-----END CERTIFICATE-----\nwww.brummer.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_coop.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGiDCCBXCgAwIBAgIQXZGLlRfJZXnZe5PsDszKujANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwODA0MDAwMDAwWhcNMTcwODI2\nMjM1OTU5WjCB1zETMBEGCysGAQQBgjc8AgEDEwJTRTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xFDASBgNVBAUTCzU1NjcxMC01NDgwMQswCQYDVQQGEwJT\nRTEPMA0GA1UEEQwGMTcxIDQxMRIwEAYDVQQIDAlTdG9ja2hvbG0xDjAMBgNVBAcM\nBVNvbG5hMRkwFwYDVQQJDBBFTkdMVU5EQVbDhEdFTiA0MRgwFgYDVQQKDA9Db29w\nIFN2ZXJpZ2UgQUIxFDASBgNVBAMMC3d3dy5jb29wLnNlMIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEA24aprt/4q+65dyZAGlgNoTuocOrHZ2rUSs1on6jg\nyvBR0CVgVJHK59k5Cd2+2bEMapy1l9E6inrHlkoiDn/u5tncE5eBsw5z/qzpoEv5\noayHekVoZCNwV0Fil2EGVeCkr3kDe0+ufr45C2+qYGyx2IugnNqrbd0VyrqZ0otS\nbkj55mmeR1fGv7Nb90x+PxhzmwlhDydYX8uB4SbLYlAqsz/MrkpxY2RwYbB2PGiJ\nqKiSUzp9pnR3riXJ1FDN2ytVvjjs/pwAAkFkhE07JNwAVP9LFcR10NBnYZR7dzuq\n72VgEaJvl87q6ydGAeQtWhk9CwC/jQFXLBw1EOxGqb+kswIDAQABo4ICrTCCAqkw\nTAYDVR0RBEUwQ4ILd3d3LmNvb3Auc2WCB2Nvb3Auc2WCEGFwaS5wdXNoLmNvb3Au\nc2WCC2FwaS5jb29wLnNlggxwdXNoLmNvb3Auc2UwCQYDVR0TBAIwADAOBgNVHQ8B\nAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMG8GA1UdIARo\nMGYwBwYFZ4EMAQEwWwYLYIZIAYb4RQEHFwYwTDAjBggrBgEFBQcCARYXaHR0cHM6\nLy9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0cHM6Ly9kLnN5bWNi\nLmNvbS9ycGEwHwYDVR0jBBgwFoAUAVmr5906C1mmZGPWzyAHV9WR52owKwYDVR0f\nBCQwIjAgoB6gHIYaaHR0cDovL3NyLnN5bWNiLmNvbS9zci5jcmwwVwYIKwYBBQUH\nAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Iuc3ltY2QuY29tMCYGCCsGAQUF\nBzAChhpodHRwOi8vc3Iuc3ltY2IuY29tL3NyLmNydDCCAQUGCisGAQQB1nkCBAIE\ngfYEgfMA8QB2AN3rHSt6DU+mIIuBrYFocH4ujp0B1VyIjT0RxM227L7MAAABVlS7\nuoMAAAQDAEcwRQIgVJvm0hA4lP9n+4X34QJJyiAE1y5Qy4mRZrGgQJxF/YUCIQCM\ngtBxmonISmo/FBkJkyjejOuc2jqPnvxWiXOBmUf7cwB3AKS5CZC0GFgUh7sTosxn\ncAo8NZgE+RvfuON3zQ7IDdwQAAABVlS7usAAAAQDAEgwRgIhAM5VmYbSUn8zUSVp\nK4V774j6hdC5XDmzeYM2jqY7o/YOAiEAs7ETJtkadkPdZrJ6U0SLTewPXXuAjXzo\nFNGVNdGFWEgwDQYJKoZIhvcNAQELBQADggEBAAYT0zJG5ZTe8i7GJlkAp/Yth7ex\n8JPVHbWvvZi3Pf1AQ6ZDhMYlu3YLHifplg0awl326V5P6lXHgZ2E8MSTodBemvQd\nKdLpgCrJJL28WGPvcY6kxGMMaI3TJlebyjymzZm6bTEsZ60nNid2LjLdE3ddQBOc\nr2dKeCbASzkbCQHHu49euXtkCeYuN7WBHgWOlafEHuuBYBKWCY97FN4UWu4hxsnl\neTGhSpOsIPZAJ9efbD4eEWqYFK7hI8xOq6Z8pL4VP2ovl3d4EkrlJw6gBMunbVqQ\nu2d5j8OU+0GWyShV3j27Kf0jCxEdRtegCLPLunuEJa8Jaypk9/N5Tv8FIfg=\n-----END CERTIFICATE-----\nwww.coop.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_csn.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIG5zCCBc+gAwIBAgIQTLNgc4bcnhgB4J96YXHi9jANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwNDEyMDAwMDAwWhcNMTgwNDIx\nMjM1OTU5WjCB9DETMBEGCysGAQQBgjc8AgEDEwJTRTEaMBgGA1UEDxMRR292ZXJu\nbWVudCBFbnRpdHkxFDASBgNVBAUTCzIwMjEwMC0xODE5MQswCQYDVQQGEwJTRTEP\nMA0GA1UEEQwGODUyIDM3MRIwEAYDVQQIDAlTdW5kc3ZhbGwxEjAQBgNVBAcMCVN1\nbmRzdmFsbDEcMBoGA1UECQwTTm9ycmEgVGrDpHJuZ2F0YW4gMjEkMCIGA1UECgwb\nQ2VudHJhbGEgc3R1ZGllc3RvZHNuYW1uZGVuMQwwCgYDVQQLDANDU04xEzARBgNV\nBAMMCnd3dy5jc24uc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX\nvKDLeJuS+BlhePspeo+/i1JmWqilBjV5oVX0V9/RYAWVONs4BxdoUslQpydlmWq/\ngzUdJ7nBJQfcOjAKBj20rScCdgh95JtmoNhNMSIyeTZUl+1C8Cbtg5VSjROLxJum\nveJXkTd1GExSxXVX2mj2b5Di9g1iLbB8dN4rWgciigOrnQ0tl0SAC91k4OpqQMDB\nN9Hy2j/E5QiPbQ0tG8cE3/jdvw5xl0pdKttd011mMOQxbU4ISKlQwRt6R1HoPD32\nBHgfrS6q/oN2ey4w7FIBvjwQP/KTy6kIXo6XLzyfsjF7UBXh5aDUqx7o7AMM3tm+\nvYPIrBf8Dzldi136qHIXAgMBAAGjggLvMIIC6zAVBgNVHREEDjAMggp3d3cuY3Nu\nLnNlMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF\nBwMBBggrBgEFBQcDAjBvBgNVHSAEaDBmMAcGBWeBDAEBMFsGC2CGSAGG+EUBBxcG\nMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUF\nBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMB8GA1UdIwQYMBaAFAFZq+fd\nOgtZpmRj1s8gB1fVkedqMCsGA1UdHwQkMCIwIKAeoByGGmh0dHA6Ly9zci5zeW1j\nYi5jb20vc3IuY3JsMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDov\nL3NyLnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL3NyLnN5bWNiLmNvbS9z\nci5jcnQwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AN3rHSt6DU+mIIuBrYFo\ncH4ujp0B1VyIjT0RxM227L7MAAABVAoufNkAAAQDAEcwRQIhAOMzLi9s+OaPP/mX\nSwevafUp3Sz6pdH6ehZziO3Ugzi9AiARkulxM2kdL3BDmOJlk0nbXZndRc/KqEV1\nwYRK4kJ3NgB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABVAou\nfRoAAAQDAEcwRQIhAOXs0RZyQMgU25Acmn3DyXL+zL0UsWWTjE1FdgJ6IU05AiBV\nEKgE49vZqab6htRQLM9OD31xumZ8cTIif15k2vAM5QB2AGj2mPgfZIK+OozuuSgd\nTPxxUV1nk9RE0QpnrLtPT/vEAAABVAoufQMAAAQDAEcwRQIgbX7wD2i05Dqhgf1M\nSlU1xeCELndYXFAgE8Q3+gJvLzcCIQDWh9lLdKTWHwMZiJYI6Z47eWoIqPMyqwjM\nqG97ZlPbHDANBgkqhkiG9w0BAQsFAAOCAQEAwwi6/agTG4HKbKrTDZO40j7hT8PV\ns+t2IhtSuSRK1m0mNAgD6L2elL4zgjZN2Jtks1yHGukAPyvY8HKnZlDShr9PDZ4x\ngWhu0o1/uwYcuZ+nS6VWCCf59maGnoOG9q+aSJBji06puSs9ND0cafSeay97H4bh\nslB5+7Xn/eSs5DDlmdZiCZ4qh6aDvqwsq1edKAstklXzqWZQBwTrlYbW4kAIFXf7\nJGkYmqrgTLOrzpJXcpOMPdkvFaqHAQLk/b4fajMaTgypNwiLFBSoujJn4o3e7nNf\nrCFw6pbiJ5rWkPXpmtsSonWiYB0DAxKgxeVkRIPVoLeBvufL/Gew02rIrw==\n-----END CERTIFICATE-----\nwww.csn.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_danskebank.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFSjCCBDKgAwIBAgIMI2d4vBm6pr6l/ezfMA0GCSqGSIb3DQEBCwUAMGYxCzAJ\nBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTwwOgYDVQQDEzNH\nbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0g\nRzIwHhcNMTYwOTEzMTEzNjAxWhcNMTgwOTE0MTEzNjAxWjBtMQswCQYDVQQGEwJE\nSzETMBEGA1UECBMKQ29wZW5oYWdlbjEVMBMGA1UEBxMMQ29wZW5oYWdlbiBLMRgw\nFgYDVQQKEw9EYW5za2UgQmFuayBBL1MxGDAWBgNVBAMMDyouZGFuc2tlYmFuay5z\nZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANpBHTaIScLocNcQoOuj\nPSX3xwlbomedbXDaeM1LBRLWIiGNibC/XUYGNjn+4tvYyU+B9GDYXLL1C6m3YHsu\nFts0CamxLYS2VSLCjc/v9sFbDZcodj+6sE9/AXhwmjYj8YC6p7FHcK7LGYYOoBAd\nYCuQl7Xd+yaCbajOwyyoItiEe6qf0/hmV2SH6rJsQtPSCbUqMX3kAgAlQOhCqMdD\nke6w4TiQAHv+An4ceF7KuMIPOzHB2/PO1Z/YQLG1vLZMA892fuJeFH5KuvtN6d9a\nh1z21vyu7eHsAg/Ua1HvEGYaA4xjQM5czoP4yQSJaR0kbpp1hrCv0q3K9R6NIUhF\nlC0CAwEAAaOCAe8wggHrMA4GA1UdDwEB/wQEAwIFoDCBoAYIKwYBBQUHAQEEgZMw\ngZAwTQYIKwYBBQUHMAKGQWh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2Fj\nZXJ0L2dzb3JnYW5pemF0aW9udmFsc2hhMmcycjEuY3J0MD8GCCsGAQUFBzABhjNo\ndHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vZ3Nvcmdhbml6YXRpb252YWxzaGEy\nZzIwVgYDVR0gBE8wTTBBBgkrBgEEAaAyARQwNDAyBggrBgEFBQcCARYmaHR0cHM6\nLy93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wCAYGZ4EMAQICMAkGA1Ud\nEwQCMAAwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2NybC5nbG9iYWxzaWduLmNv\nbS9ncy9nc29yZ2FuaXphdGlvbnZhbHNoYTJnMi5jcmwwKQYDVR0RBCIwIIIPKi5k\nYW5za2ViYW5rLnNlgg1kYW5za2ViYW5rLnNlMB0GA1UdJQQWMBQGCCsGAQUFBwMB\nBggrBgEFBQcDAjAdBgNVHQ4EFgQU5QZdNIS6nLfk6lV4vHVRHg6DTlMwHwYDVR0j\nBBgwFoAUlt5h8b0cFilTHMDMfTuDAEDmGnwwDQYJKoZIhvcNAQELBQADggEBAB5P\nl1RAQdS2tXyefgJaymhVpcJds63grMyUztkU6lzYbTbdZsMa5x96WLjfvdDDTVmI\npP5OMlv1q7Gh/4uhkIPOE9VH2thTyHsg9jUetBPSOAJqEi5DLGtlpYqlDRPqDrZp\nbSP5PpKWOC5AXy4cho/Ix4dkRamB9zT7lbYtusCP3Cgnbfm00b2gmOe9ax8jOpXb\n/1zLd7YTjmrGrElIuA0I1FmsEsVzPp0BONaSUVjWtJP4LJ+rQqp/0+iCKdBVLLbA\nsE/FCXopdjvWaQgHoUDKes6FJmY4h0rDpViU3ClTEvfN+DdRlxlODRw0STh+CFtl\nSnEPwHpG0wzZnwfPFvU=\n-----END CERTIFICATE-----\nmobil.danskebank.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_firstcard.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGdzCCBV+gAwIBAgIQFoz2cyoH3choP3fYGiPTlTANBgkqhkiG9w0BAQsFADB+\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj\nIENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE2MTAxNDAwMDAwMFoX\nDTE4MDEwMTIzNTk1OVowgYUxCzAJBgNVBAYTAlNFMRIwEAYDVQQIDAlTdG9ja2hv\nbG0xEjAQBgNVBAcMCVN0b2NraG9sbTEXMBUGA1UECgwOTm9yZGVhIEJhbmsgQUIx\nGjAYBgNVBAsMEUlUIFJldGFpbCBCYW5raW5nMRkwFwYDVQQDDBB3d3cuZmlyc3Rj\nYXJkLnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dG7pvu0mER1\nFxOpvOQPoCjHi6N8N9nfPzUGlBPjWnji7u/Lnlqva8J9NncmXltkSlalMmYQu5+R\nfGHY/PWIfVTl0ixk3pbriKlay9paA/dTdFVKNOZzihPmjeh29bjoYkIRUPfpSfF3\nCDcKlWVyxH9/pR9RmcNtkm5NWDBZT26wGtyqzuwmyPunxQd6PyI9X2SUMZBMsZbd\n/rE/1UEdRsgH1L0OmCe35OFIxoYVpNx7BbgVUSAJZc24Oi2AHrzKt5i7Wg2z2qqp\n6OPkZkJaH2y+lpztdSQAyFiyj1ai/V9CyW267uprA0vON/8zecFFvToIutFLZW9Z\nm0MOJzQUzwIDAQABo4IC5zCCAuMwGwYDVR0RBBQwEoIQd3d3LmZpcnN0Y2FyZC5z\nZTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD\nAQYIKwYBBQUHAwIwYQYDVR0gBFowWDBWBgZngQwBAgIwTDAjBggrBgEFBQcCARYX\naHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0cHM6Ly9k\nLnN5bWNiLmNvbS9ycGEwHwYDVR0jBBgwFoAUX2DPYZBV34RDFIpgKrL1evRDGO8w\nKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3NzLnN5bWNiLmNvbS9zcy5jcmwwVwYI\nKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Muc3ltY2QuY29tMCYG\nCCsGAQUFBzAChhpodHRwOi8vc3Muc3ltY2IuY29tL3NzLmNydDCCAX4GCisGAQQB\n1nkCBAIEggFuBIIBagFoAHYA3esdK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbs\nvswAAAFXws6hjAAABAMARzBFAiBK8CEHPs9cixQPUkaXXB9K3Ud74tf1wmBaFPri\nUOEULQIhALTQaP9lQdrsAi4DKhs60g4yJNcIx3QjmJJh6a0b03W8AHYAaPaY+B9k\ngr46jO65KB1M/HFRXWeT1ETRCmesu09P+8QAAAFXws6hpwAABAMARzBFAiEAnkz+\nOc4HRUxm8RsDhGZ5b+PccYehX1BX3ur6v1g9DNUCID2eL8uVXm80F7FCchu+DG8b\n/URTy0sP6YuTjbC6yZZDAHYA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo\n/csAAAFXws6jggAABAMARzBFAiB2vLVVIqH7/J3SVY4T+ilynHdApDe9qsL3wU6U\n371GzwIhALmmDN5Y0d4WchYXECaRS3E5j/1qWCLffMm4w5eYVXB6MA0GCSqGSIb3\nDQEBCwUAA4IBAQAXFhS0c69Z86ZfY1CAI+byoEmFvj41A1bb4GIyw2c7qyMISRu6\nM6oYLGMBpj2OWZdCov+EfilRVtj/ThcuKuh9+VfZr2bloIsrymkXhmgE4orgfuVj\nlkMm+k3jRokTjQryJLAlIQ3UWf9tmn49cSF1culPi8WrYvbSi4DRfo1p3nWY7/RG\nwz0++oHsk5IK7hiGkXmvSWs/p1KJhoU0HViKci4ZcsPn9OEsDqZ9D2bmYLkhpSJG\ncgXx0qd5ledeOq4G9+mRTOudv2u9QJ24VxKycGoXy6ClWbKDt40CPQCBZ515OPRB\n0QnOSxH/5mBWvneOpWytZZ47OWWKPzalXlAK\n-----END CERTIFICATE-----\nwww.firstcard.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_hemkop.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIHdjCCBl6gAwIBAgIQCiO4Bd6bHZbXhyjqyD/evjANBgkqhkiG9w0BAQsFADB1\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk\nIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE1MDYwOTAwMDAwMFoXDTE3MDYxMzEy\nMDAwMFowgeUxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB\nBAGCNzwCAQMTAlNFMRQwEgYDVQQFEws1NTYxMTMtODgyNjEgMB4GA1UECRMXTm9y\ncmEgU3RhdGlvbnNnYXRhbiA4MGMxDzANBgNVBBETBjExMyAzMzELMAkGA1UEBhMC\nU0UxEjAQBgNVBAgTCVN0b2NraG9sbTESMBAGA1UEBxMJU3RvY2tob2xtMRkwFwYD\nVQQKExBIZW1rb3Bza2VkamFuIEFCMRYwFAYDVQQDEw13d3cuaGVta29wLnNlMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsudvo3kPNpl8ntN4cjLz1P2I\nDAdtq+NgutNkMpThei1M78DpBuy6++IkT5eTmxG0hnNN2xSq+sSQsA6nxwURfxPh\n9UqjElKGE8rR0zu8zDB/r43kCCbJUlw+upbwWIbwLfuuf+XL9ZmRlNyo8z1iHsCA\n3Yg0azgs3M1ZEoEL3yoqmDfEdeFWJutC5Ctl+MKvunrfGUF7jC3J0lxWKHNGKjka\nF1SArnigcyAKXCzQqGQtHgPeE+lGOJ5hdEmRaSm/JQsO+WeStOHRZnpkDNoCHi0Y\nn8PNclXuYECoX/+ObQ/AQxx5jYMMTXJ9z7CbZd07eaXt5CZseYE26VAcy2Zc0QID\nAQABo4IDjzCCA4swHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYD\nVR0OBBYEFFQlBoGp01eS9Y0gEi0ukxZNoTyZMEMGA1UdEQQ8MDqCDXd3dy5oZW1r\nb3Auc2WCCWhlbWtvcC5zZYIOdGVzdC5oZW1rb3Auc2WCDnN2Y3MuaGVta29wLnNl\nMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTIt\nZXYtc2VydmVyLWcxLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29t\nL3NoYTItZXYtc2VydmVyLWcxLmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwCATAq\nMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGIBggr\nBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNv\nbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lD\nZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8E\nAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdgCkuQmQtBhYFIe7E6LMZ3AK\nPDWYBPkb37jjd80OyA3cEAAAAU3XFT3sAAAEAwBHMEUCIQDU+FKN0g9TSP0USbVh\nUaHN76EFu3HbGT1i3Jrw0Sh+KAIgEnExuTir7q69iz3zWDiCTQAP+MNVddKIqYSs\nUIQHMiIAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAU3XFT3o\nAAAEAwBHMEUCIQCdwqLSNe0GhxG4bkTNq1BBOH9kNNyb0/f7UM8eDYY2KAIgRW1e\nuan6YRm4HJdzpbBdq2SGi7EaK4V8bnP9BybaXBwAdwBWFAaaL9fC7NP14b1Esj7H\nRna5vJkRXMDvlJhV1onQ3QAAAU3XFT9BAAAEAwBIMEYCIQC3JmrIwhPLzlcjkJKF\nA6vkAzxyW/rPRfiprvhud0+cWQIhAM6g25gg+vkWKmnp/daFNquNgLNDf21+JWXK\nAUaBzJx/MA0GCSqGSIb3DQEBCwUAA4IBAQA1cYigbvLJE4d0VmYE5J99CLPbdjmy\nNq7ed+5b2VjjFc4mxMAKgHINYgtRDEB+vTnVO/UpXSe31HmiSdUwCmF+/SNu1kkZ\nidvK+K7v4b7uCjuVooy4ExtMVqMZGtaA1pkKIOuxHLANrMbaoYw7a+a3a9zOtXnn\n9GOXoz0LRGyjuFytGihbFRYVbugCgTwizwYB1Y6sQRmAfEUN4OWeicrNdAnReBvq\nDSEjuoKLGGbwUE9Fmcu3eLB/0S3XBDcc4/wtXrHjBZ3M0MUg3vlWb3ZaNESC+Emu\n0GTGAuIFeOxSpCD2yC9sG06gHnJJSQv1LzLJCZPg0IRJ59ei91vhLfmr\n-----END CERTIFICATE-----\nwww.hemkop.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ica.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFMjCCBBqgAwIBAgIMYiysILzIsNkk0aiAMA0GCSqGSIb3DQEBCwUAMGYxCzAJ\nBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTwwOgYDVQQDEzNH\nbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0g\nRzIwHhcNMTYxMTE1MDg0MTA2WhcNMTcxMTE2MDg0MTA2WjBpMQswCQYDVQQGEwJT\nRTEXMBUGA1UECBMOU3RvY2tob2xtcyBsYW4xDjAMBgNVBAcTBVNvbG5hMQswCQYD\nVQQLEwJJVDEPMA0GA1UEChMGSUNBIEFCMRMwEQYDVQQDEwphcGkuaWNhLnNlMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyUT84RTCZGqEcEe+8CNDDyve\nayptEmLsnLo7SC0G/LWnvn5XhrOv9TQDhFiD1ayjwXvcbZjDzoLp5dN8M/r0c6NM\n6GSMo1F/mfwDmLJpp1Jx6FCL5CZ7+MYfzP0KaxGTLa9otbWy/Mfcxxx8ifvKI88h\nOjvJC+g3nz0wy1AJKDfYBgEraeFb5FtdhuuhUY78zHeXEXksZpiuh+x9DeEbHpPx\nvmRUDdZLOJVUwhGEa5kJyqMCqDEjwXX+gsfs+zIqIC6XW1kXRL53zF3Oroeat+qy\nvc/JtyI8tEuifrUIhqOipZVmGf2asw6isWpN/G1zoIIKTMRkJRMUssyLPZCqXwID\nAQABo4IB2zCCAdcwDgYDVR0PAQH/BAQDAgWgMIGgBggrBgEFBQcBAQSBkzCBkDBN\nBggrBgEFBQcwAoZBaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQv\nZ3Nvcmdhbml6YXRpb252YWxzaGEyZzJyMS5jcnQwPwYIKwYBBQUHMAGGM2h0dHA6\nLy9vY3NwMi5nbG9iYWxzaWduLmNvbS9nc29yZ2FuaXphdGlvbnZhbHNoYTJnMjBW\nBgNVHSAETzBNMEEGCSsGAQQBoDIBFDA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3\ndy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAIBgZngQwBAgIwCQYDVR0TBAIw\nADBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dz\nL2dzb3JnYW5pemF0aW9udmFsc2hhMmcyLmNybDAVBgNVHREEDjAMggphcGkuaWNh\nLnNlMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU8zEw\n//vJou9pN8JUZ+yxttNcLdIwHwYDVR0jBBgwFoAUlt5h8b0cFilTHMDMfTuDAEDm\nGnwwDQYJKoZIhvcNAQELBQADggEBAAU4C0JNq9AM2mYT3b8VXY6em77Y/AbXAze0\n0TYeZgn2wtp9lSBmVUtyAqWFZIE9aKzDruRCaeRzla4zZPN5TDS8jm2KEuBp7xb3\n4u3Fb7jSmOhyyMuqXzcjFVXp3Gde2GVYAgnDsaXBfJuk63aeUU1mg6kWOh+P7Vez\n84VLXofWNpdhspWXGkBc898GgLK7Ko+lJQ3LS5vn3ITTxlmD2t66jNib8R2aihwa\nXPUdPdTvFuyhT1i8CIuSZAXbZiQRtQh1ooh0lWGxYnL3zGQ29i0O5h44tq+gFOTB\nXP5rIJEjeETnTBZYVLKKjMP5+kUzD2+4o5jMz5ucz7Kzb2LcWYg=\n-----END CERTIFICATE-----\napi.ica.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ikanobank.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIJDTCCB/WgAwIBAgIMLWSUroS/j1oU9O0JMA0GCSqGSIb3DQEBCwUAMGIxCzAJ\nBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTgwNgYDVQQDEy9H\nbG9iYWxTaWduIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EgLSBTSEEyNTYgLSBHMjAe\nFw0xNjA2MjAwODU2MDJaFw0xODA2MjEwODU2MDJaMIHfMR0wGwYDVQQPDBRQcml2\nYXRlIE9yZ2FuaXphdGlvbjEUMBIGA1UEBRMLNTE2NDA2LTA5MjIxEzARBgsrBgEE\nAYI3PAIBAxMCU0UxCzAJBgNVBAYTAlNFMQ4wDAYDVQQIEwVTa2FuZTEOMAwGA1UE\nBxMFTWFsbW8xHDAaBgNVBAkTE0h5bGxpZSBCb3VsZXZhcmQgMjcxCzAJBgNVBAsT\nAklUMR0wGwYDVQQKExRJa2FubyBCYW5rIEFCIChQdWJsKTEcMBoGA1UEAxMTc2Vj\ndXJlLmlrYW5vYmFuay5zZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB\nALnzB13dT1Q8mEYnt6wtKyadOY/bsnRlhutg5yb0dw/KXRf2MKhGZ+74f4Y1wJ2R\n2bSJit3r+tK5dxWAf1vSfe+XDPImu0s3q/8JHSfHzH0MMfJGgz+x7jx78wlp2B+r\nkq6fx71xhHFO+rvvByRyJaj80tam5COcivedBhGlw0dQQPAPhXZ6Ik9M/Fb7Tb+Z\n4MROmD9iaEcWJVRfMWXSqBoOMUqndMgciGpFQBeje7f8rb5Mr8phI0FEaFx8VwEA\nDItvRg736tKbh8O8x0vSe7H2XSTfymkOh1wRufmjEfO5CEgvc7k4jvn2+kE4AvDt\nStSvIw74od/zIOta/x5SioQSDvV4fUEjQmZ+jJnG+26kDz33Y2hY6UnN5kpNm/Mp\n6qGAHYrCGjYoOMW94w7IqYXD/XlsBb6u771wSTLV+8XdCSYQHacK4qNDLVo4icLj\nuyHxib04bRzxp03Uc3qBJJtmJtXJ7O/VLNvEvrHxeNabhWWhFs8n7TmwNUweY++9\nflM9QjFFNG8w7/iub77pZDhJsHwPlyMYbEtr0PEtBASKegNEQ2JGgug4J0Pl8Adf\nXoLd2tS3INtKw5wDrXxBHaw+OeJIfVBp6UWKLx97lO+GYMIpou4462CjMwuuBOIQ\ni57LhAXG3SY/1l9dpOGcE7qMsKAspl2NbCUFy3s8qmO5AgMBAAGjggRDMIIEPzAO\nBgNVHQ8BAf8EBAMCBaAwgZQGCCsGAQUFBwEBBIGHMIGEMEcGCCsGAQUFBzAChjto\ndHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc2V4dGVuZHZhbHNo\nYTJnMnIyLmNydDA5BggrBgEFBQcwAYYtaHR0cDovL29jc3AyLmdsb2JhbHNpZ24u\nY29tL2dzZXh0ZW5kdmFsc2hhMmcyMFUGA1UdIAROMEwwQQYJKwYBBAGgMgEBMDQw\nMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRv\ncnkvMAcGBWeBDAEBMAkGA1UdEwQCMAAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDov\nL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc2V4dGVuZHZhbHNoYTJnMi5jcmwwHgYD\nVR0RBBcwFYITc2VjdXJlLmlrYW5vYmFuay5zZTAdBgNVHSUEFjAUBggrBgEFBQcD\nAQYIKwYBBQUHAwIwHQYDVR0OBBYEFCF8iwzWeCT7zohaesJnFJgXK4KkMB8GA1Ud\nIwQYMBaAFNpAd0NlHPj+p+P0ZII+TUMTIjECMIICbgYKKwYBBAHWeQIEAgSCAl4E\nggJaAlgAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAVVtBhvH\nAAAEAwBHMEUCIQDRbAjcbuUGjUr1dBFMyOGHaqq9XGtqHzrRjpxh4d3XNwIgPg1d\nTgYHO4VZKngy8rdsRErt92H1xWkiABuajQW3IfEAdQCkuQmQtBhYFIe7E6LMZ3AK\nPDWYBPkb37jjd80OyA3cEAAAAVVtBiGiAAAEAwBGMEQCIH9SrLHiP7ucs20y9li2\nLufLrYtOYHARO4pWDAurBVeMAiAUrA/rM28HCgpAjitGVl/YH4a8uhcilAXRGzXa\nzCJkiwB3AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABVW0GKn8A\nAAQDAEgwRgIhAJ6c06tA4pj6QO16IoH5vFYf9UHlYn/kLT1iatCpWtOrAiEA72aN\nuhLfqiOg5Po6DxcMZmzvdj5/CQGxHkcngKmcLhEAdgDd6x0reg1PpiCLga2BaHB+\nLo6dAdVciI09EcTNtuy+zAAAAVVtBi76AAAEAwBHMEUCIQCPhJCOWx7J9UkWz4Kq\nD82EkzpYsGt1OWziM3GFmYObwgIgKO0a3fA4PFQGk1q4/t44skHh32tvrmVl80Nn\nfOkbdwEAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAVVtBjPH\nAAAEAwBHMEUCIFcZsEFLwNJgFlE29yG/Uxzxst8oVmx9EnJQ9mgsKOeOAiEA7jtt\nru57yDCZ/C7dsr2l/pwi8sSPYtHwVuENthAZ6u4wDQYJKoZIhvcNAQELBQADggEB\nAB3xT3CMYQvpJ2xlotAFmiEM5qJkDpGJwnddhL14W4q//VH0yQrL4UwtssnVGMNf\nZX+06JiDUeSEyDq8HRdbbF1Yd9/ssRc0zJqT5eYlDRKm1jYd8/9WR7O0IJKR/MtY\n5ClHPjv7/kmao0oQx41VM28uI/GjYyqRACd7XubVt0YTVha0tRSBHNY/SrVQM7jd\nscEs93mhOe2uOxEnHnzsfH+2hvS+f3+YDu9JEE7O+7ykwuAfdcJ2x8fq0PEZ5b+7\nm2ByuyjFU0ux/p+LuK6ton4Q0OLcXuWHxNrwpZ9Vh6+c4052MYt4935QqwRAZj4w\nON+jB1Oe99EbwuPC1bFJybo=\n-----END CERTIFICATE-----\nsecure.ikanobank.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ikanopartner.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIIrDCCB5SgAwIBAgIMNo0UBiNQ0fznzJHXMA0GCSqGSIb3DQEBCwUAMGIxCzAJ\nBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTgwNgYDVQQDEy9H\nbG9iYWxTaWduIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EgLSBTSEEyNTYgLSBHMjAe\nFw0xNTAzMTgxMDIxMDNaFw0xNzA0MjcxMDQ4MjNaMIIBADEdMBsGA1UEDwwUUHJp\ndmF0ZSBPcmdhbml6YXRpb24xETAPBgNVBAUTCDI4MTQ4MzIxMRMwEQYLKwYBBAGC\nNzwCAQMTAkRLMQswCQYDVQQGEwJESzERMA8GA1UECBMIR2xvc3RydXAxETAPBgNV\nBAcTCEdsb3N0cnVwMRowGAYDVQQJExFTdGF0aW9uc3BhcmtlbiAyNDELMAkGA1UE\nCxMCSVQxPDA6BgNVBAoTM0lrYW5vIEJhbmssIEZpbGlhbCBhZiBJa2FubyBCYW5r\nIEFCIChQdWJsKSwgU3ZlcmlnZTEdMBsGA1UEAxMUcGFydG5lci5pa2Fub2Jhbmsu\nc2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDMXIZyIKSbJUhXe2kT\nvOfF29NbQQpK9xlHIUdhEnqKnDfD+mBCnFwcDZ8iaqDexcwX2zLuC0RpsMu54k8E\nyaHZu1Mwq/0h6bSdkBbmA3L+vX985eOcPU9zrF7W5HUDL2/gkvy7dDr5ZeDXtly6\nvS4W0La0/ugMyTtPH2lKUCy3kS0Ia4/TmvGIitQgTw8aAOUBXL0df+7GtxvPiFsA\nc2qVRab8peCyrFSxSycOO3aIc1zzlhSK1ABb9mwEr+KviJBMdxYPO3I/l+OrRVic\nLvv6Th3Tq0oMYHC1Ilg1uMNENAWAEoToIUiPrRJ9L5pL8uSup2c5blEyNPbPh6AM\nPFJx3c9FCbYWqWzae6esA967wiuASGWItSN890HDHHJ24HBEp+wLvqeuXvR1iN0I\nzGZwlGPxDbTimSLcsQRIVvJtFpS8rvOkoZslnGY0ZueRoLm8nIRlM2UDV+AhB4yn\nHSqPffSLUEHA0VycFB1VHpYvLMrsUYGu0+efdNovy4IQ7PfDTG/5hdbAx2GYazHh\nE7l72EX3j3/SwU3KoWvDnkadI93LZlfLsco1LeDRUv3OEW9Lj1EbspZiz2sAlfIz\nEAMKzlbnWRn2S9lUQpVbL1jsD7JA3KRPe37ejABcFijA6GMq4FoxzghPC4GBZnho\nyOsPhJO0ua9hekVQah+u/PEhOQIDAQABo4IDwDCCA7wwDgYDVR0PAQH/BAQDAgWg\nMEwGA1UdIARFMEMwQQYJKwYBBAGgMgEBMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v\nd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMEMGA1UdHwQ8MDowOKA2oDSG\nMmh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvZ3NleHRlbmR2YWxzaGEyZzIu\nY3JsMIGUBggrBgEFBQcBAQSBhzCBhDBHBggrBgEFBQcwAoY7aHR0cDovL3NlY3Vy\nZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvZ3NleHRlbmR2YWxzaGEyZzJyMi5jcnQw\nOQYIKwYBBQUHMAGGLWh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9nc2V4dGVu\nZHZhbHNoYTJnMjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwCQYDVR0T\nBAIwADAfBgNVHREEGDAWghRwYXJ0bmVyLmlrYW5vYmFuay5zZTAdBgNVHQ4EFgQU\nwja+k4amQyKGu3q0x+TNxR/UF9cwHwYDVR0jBBgwFoAU2kB3Q2Uc+P6n4/Rkgj5N\nQxMiMQIwggHzBgorBgEEAdZ5AgQCBIIB4wSCAd8B3QB0AGj2mPgfZIK+OozuuSgd\nTPxxUV1nk9RE0QpnrLtPT/vEAAABTCxmoGMAAAQDAEUwQwIgXtd5yn/zGuLJszd/\nbSsZriHmejrGkhz0qM4NREFo848CHyB8tN4EqQB9cFA0ILHnNNxHzZRYuiOmdBAU\naAajI0sAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAUwsZqig\nAAAEAwBHMEUCIDYVzVb14/GAe4tXMMMbC1sEXSkY7Sp23Q38M1+dBCjJAiEAwdUd\nUp5/Rl29cqbb4WHbT4jD1DqbHOZNfOjkIqH7BFYAdgDuS723dc5guuFCaR+r4Z5m\now9+X7By2IMAxHuJeqj9ywAAAUwsZrT9AAAEAwBHMEUCIQCsJZM6RlmZPivH84+X\nKobbS9XkOtZue6IsE19+yRflhQIgeB3ARuy8EQOhuA9gJRsIprtboxRoijMcvEo7\nKq6Dd2MAdQBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAUwsZroO\nAAAEAwBGMEQCIE+9kHVQjtaG+nJ8Ap1/n3wNwASb+2g2Tp6nHeqp3ruFAiBTU4sT\n16/4nUGTRBJP4qYQIBKk2wXjnB9r25hdUwUD4jANBgkqhkiG9w0BAQsFAAOCAQEA\nXNxfzv9fzHVgWMXt5TjNFGd9+OkcbpXhd4PSFPeL/sMxeOQcX08bt6GydsmAXIuN\nF8z1B4jIVAYN+bHroi8vkrkmxM+UFLOryZ+hD1fbngX9b8wvi/nqIICOfP8Lz/9K\nOwwXmxGvDx65UgQId1Y/u4ZnKDghPROHKqkQN0w7Yz6mtXj9TyqZhkaXiaqZNxGd\nCFNL8Ka+SVStbGhC6da0Cq9tCMb03lcKR1vlssOBH+ak64ZHPVinOsTx01xzrv/+\nfgIa4VVmjQyZ2j5nfTr81CS1gj3IWqibCGZy5JW88wLbByRP6aB+NFDx0wKC/UMh\nX2rz9QRCM2gbnOM+w8D12w==\n-----END CERTIFICATE-----\npartner.ikanobank.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_jojo.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIE/DCCA+SgAwIBAgIQIpOEjsBXxATU9+f3D5yYMjANBgkqhkiG9w0BAQsFADB+\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj\nIENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE1MDEyMjAwMDAwMFoX\nDTE5MDEyMjIzNTk1OVowgYYxCzAJBgNVBAYTAlNFMQ4wDAYDVQQIDAVTS0FORTET\nMBEGA1UEBwwKSGFzc2xlaG9sbTEdMBsGA1UECgwUU2thbmUgTGFucyBMYW5kc3Rp\nbmcxFjAUBgNVBAsMDVNrYW5ldHJhZmlrZW4xGzAZBgNVBAMMEiouc2thbmV0cmFm\naWtlbi5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMakjVoyclPx\nG7ZzeOXsGrnsYFpw/grxo9ieU0ZFcGhJvrSr9oc8HGvMw7PIkHYfBxG/UlZP+U8O\nZhETkE7dO5LWYAxoWLFrOQZV2a6rxI1e3YxRIKB4XfR7g4HIt9pFpT8zJbj0MsoU\nkuGt3wAyTGScPEgZcHfNvwtoTU3mgY5Qbj18LJwsVWPgrj78igffmqVGs/O7sv61\ntjT2TySVLjc4T4CG8AeGHCdDAeKSUZ1hcgiK2Hvxj0Ox5SMlAJ38T1LxcNuqH0CI\nOoHIl4hHIBe+jqhoB7jHdi2qKhVyAij3SFITfQeVfzadIN433q/Orvh3C5cFXmw9\nykvAuK34SJcCAwEAAaOCAWswggFnMB0GA1UdEQQWMBSCEiouc2thbmV0cmFmaWtl\nbi5zZTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYB\nBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0\ndHBzOi8vZC5zeW1jYi5jb20vcnBhMB8GA1UdIwQYMBaAFF9gz2GQVd+EQxSKYCqy\n9Xr0QxjvMCsGA1UdHwQkMCIwIKAeoByGGmh0dHA6Ly9zcy5zeW1jYi5jb20vc3Mu\nY3JsMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3NzLnN5bWNk\nLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL3NzLnN5bWNiLmNvbS9zcy5jcnQwDQYJ\nKoZIhvcNAQELBQADggEBABOMmY7ZUmJyzjUWbNPF85D3bJc31qK7z7ylBWY7WpoO\n4lZJCW2+mZ0MfIQr7/VHseMuhKuF8IzoRXOediW7BnAF2TsNQePnCAYYiekwnmKl\ndFA4BzqrYrA2P7DFH8SfWhoPjKL1LLC7LlpUmbmPmgiVlOAPkyMuKTHTfsq7xuYL\nbJCguo5gq9LgRUltkXjaZIOAcPm/t8/GvK440+l1WidRejND7xAw2vDBrDoSka5m\n+6QSmBh6iD6NYHjnUDMI3xIYponqt8DV/zoBQYZnJu640OacS5qmpytHaN/KIuno\nY59Yey0ZXaN9jbXw0dj65mEto7jYfWwZkkccqyfO50k=\n-----END CERTIFICATE-----\nwww.shop.skanetrafiken.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_lansforsakringar.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGITCCBQmgAwIBAgIRALVy+JJ/Rmcr6VZoYIqBX+MwDQYJKoZIhvcNAQELBQAw\ngZYxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTwwOgYD\nVQQDEzNDT01PRE8gUlNBIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIFNlY3VyZSBT\nZXJ2ZXIgQ0EwHhcNMTUwNTA1MDAwMDAwWhcNMTcwNTMxMjM1OTU5WjCB+jELMAkG\nA1UEBhMCU0UxDzANBgNVBBETBjExNSA0MTESMBAGA1UECBMJU3RvY2tob2xtMRIw\nEAYDVQQHEwlTdG9ja2hvbG0xGjAYBgNVBAkTEVRlZ2VsdWRkc3YuIDExLTEzMRkw\nFwYDVQQSExAxMDYgNTAgU3RvY2tob2xtMRwwGgYDVQQKExNMYW5zZm9yc2Frcmlu\nZ2FyIEFCMSMwIQYDVQQLExpQcm92aWRlZCBieSBQS0ktUGFydG5lciBBQjEUMBIG\nA1UECxMLU3RhbmRhcmRTU0wxIjAgBgNVBAMTGW1vYmlsLmxhbnNmb3JzYWtyaW5n\nYXIuc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTwqtpTIgrRi4H\nfowbnUgSVurdAXXHdW0WullI6iPKxOFRYCJunIjBXGbj3VHWsUSqYgIqaHnb0fLo\nVhzSWkjchoG7P76Z0NRkegv6tuE+Zcze9CrTZyv03f2KreVynhQam6V6N5XK4SvG\n6HB9H1wZLEb43sDlbmKslm2xB0LE5NV+AQGemtt1qYZTwUQE571jcjIhsQl8Cukj\n5KnuQwpxxhsEVrFqI48EotrFe8+exlXxsepoLPwkpCtFy2jwU9+9A9U9xDC+EDXb\nqu2TPpMLrwA/5EgYrLFXQubbwnAaCGns/03RYM0FCz4S6PyZCK8vP1+mVt9Px2OB\nnoICaYBXAgMBAAGjggICMIIB/jAfBgNVHSMEGDAWgBSa8yvaz61Pti+7KkhIKhK3\nG0LBJDAdBgNVHQ4EFgQUIGoAMY4MQoG2sLw08ChZ6exo3bEwDgYDVR0PAQH/BAQD\nAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMFAGA1UdIARJMEcwOwYMKwYBBAGyMQECAQMEMCswKQYIKwYBBQUHAgEWHWh0dHBz\nOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMAgGBmeBDAECAjBaBgNVHR8EUzBRME+g\nTaBLhklodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FPcmdhbml6YXRp\nb25WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGLBggrBgEFBQcBAQR/MH0w\nVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQU9y\nZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYBBQUH\nMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTBDBgNVHREEPDA6ghltb2JpbC5s\nYW5zZm9yc2FrcmluZ2FyLnNlgh13d3cubW9iaWwubGFuc2ZvcnNha3Jpbmdhci5z\nZTANBgkqhkiG9w0BAQsFAAOCAQEAekxw08Z/AOZdoCIMqs5ZeCSW4nUYp/kqsv7T\ntHSEadEc88n05aibWjX16kqtr07JViLKUyKoq6jfZHgWQpCqMvWhFOog7ZWLLkFB\nrm8iAq4v05CpPrtFdjgAJwEnBX1aJUFREgDiqy6ytlNez2uEi7w/jryybMhB1A5F\nGFnpOjs00XSJ150FzdQ05mPuUU4NNMLPazU6IFeCRhWvlhAZ1SorS2HqjNkQbKU7\nBMTe35Ssb2iWcZePdkrWfB9zeurU90RFgaZ3SeXH+h9qb6c7GJd+7vM65KB+uiXQ\nZgcRC1dwwl2etmdYp6c4sz+6CugCoVCXWZav/wlQKnw7+k/jrA==\n-----END CERTIFICATE-----\nmobil.lansforsakringar.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_meniga.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFQDCCBCigAwIBAgIIHHBEGyxYdQQwDQYJKoZIhvcNAQELBQAwgbQxCzAJBgNV\nBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow\nGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UECxMkaHR0cDovL2NlcnRz\nLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQDEypHbyBEYWRkeSBTZWN1\ncmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwHhcNMTYwODI1MTMzNDM4WhcN\nMTkxMDMwMTUwNDEyWjBVMQswCQYDVQQGEwJJUzETMBEGA1UEBwwKS8OzcGF2b2d1\ncjEbMBkGA1UEChMSTWVuaWdhIEljZWxhbmQgZWhmMRQwEgYDVQQDDAsqLm1lbmln\nYS5pczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEjHxkNQ0TB+jbk\nJugI5aZ7x2TJbIqrZYJ3i99pEXehRzU5Nx6BMubPgJ3yYcdgDuWjbjm/Zobe08DW\nZ33UbCu0VDnDdcPIUAzpR3g+FZT8zZuK65RY3zK7Cxv/CJbyg+yVgodK4qz50mHy\nl404hGwrxylyeJhIcTiq1Q+CLdVIWamd3p1ZDJFIQyWJcltLFtH1kmRmZA6KSulV\n+Tv5kPgEKwX121ISU7mywItC0b0B3sUD07N4SyylqJdBFFaIqjQC09ffstfoMuDo\n4PA9gf0zlT/b6k0JfFl9IFymO7c0Dw8kPSnxS/spbqmochH9T0dkJAC589AVO+g4\nONQBzdsCAwEAAaOCAbIwggGuMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYB\nBQUHAwEGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIFoDA1BgNVHR8ELjAsMCqgKKAm\nhiRodHRwOi8vY3JsLmdvZGFkZHkuY29tL2dkaWcyczItMy5jcmwwXQYDVR0gBFYw\nVDBIBgtghkgBhv1tAQcXAjA5MDcGCCsGAQUFBwIBFitodHRwOi8vY2VydGlmaWNh\ndGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMAgGBmeBDAECAjB2BggrBgEFBQcB\nAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHkuY29tLzBABggr\nBgEFBQcwAoY0aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0\nb3J5L2dkaWcyLmNydDAfBgNVHSMEGDAWgBRAwr0njsw0gzCiM9f7bLPwtCyAzjAh\nBgNVHREEGjAYggsqLm1lbmlnYS5pc4IJbWVuaWdhLmlzMB0GA1UdDgQWBBR2+sl7\nFZYz9XlyJeOApGc+MTxvIDANBgkqhkiG9w0BAQsFAAOCAQEAR+uxgkI6AfSB+Txd\nIYbWQEYYjTXDWCNGoNp5Y+Dl1M8qdBKjYXfyYAKOWCNi4qRwDk1+QOtv6AB3CkOy\nH4O6HmhKcmeGOw2zpKzMLOD4y58VJr0LpIBvE4WNVHssjhKvZizaD5xGLtDbogXn\nO5o1STzUp0FzQKwVtLw4KdE7UEJwfA7Q/MNOjIuzylNmKa2dDjHv+DfcJab4Qhw1\n1qUGdDIZxLOgyMkZiO1UbqBtctOeYgYNphBAoyzWurLmu0n7fzhhdCZTq67XHJAE\nxV/zSLYmh50rSN1GEAg69zo5fAQFn9SKTTGdDo5jqB3hAHBiuf4/F1j0DWQ96kNK\n2F8WeQ==\n-----END CERTIFICATE-----\nwww.meniga.is:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_minpension.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIH3TCCBsWgAwIBAgIQSxRugYizx9lBU/JAeD4aIzANBgkqhkiG9w0BAQsFADBB\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMRswGQYDVQQDExJ0\naGF3dGUgU1NMIENBIC0gRzIwHhcNMTYxMjA4MDAwMDAwWhcNMjAwMTMxMjM1OTU5\nWjCBlTELMAkGA1UEBhMCU0UxEjAQBgNVBAgMCVN0b2NraG9sbTESMBAGA1UEBwwJ\nU3RvY2tob2xtMSEwHwYDVQQKDBhNaW4gUGVuc2lvbiBpIFN2ZXJpZ2UgQUIxITAf\nBgNVBAsMGE1pbiBQZW5zaW9uIGkgU3ZlcmlnZSBBQjEYMBYGA1UEAwwPKi5taW5w\nZW5zaW9uLnNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwpwIicRL\nTffXO9heGZoBxtyoRlq3QPq15RS75zdyr5tUNjyPFwqSny2UxWCSxIjEvYSyI7Iu\nUXzsu4MeePIgIdPHhZG+JaG0w8AS1ZFc1VAq/ULT0naHYVrE8xCQy4MDtFCxlDLN\ncSbsENZglVHIILoWhwh/xba6RrILk+tW5elQYM3TQxf3BT6xLvYYAkHGmWk95JFB\nMrL6uvTufs3bdwffUeYFwy1sXyiizbjr9F9MSx5u0FnelYrF7q39diJZKWTGAvK3\nuEuAgKh4cpC80ixGr/zwGdsyvRBCoQB9w5gUWVEJSinLKoZjYS7zZyzyApzEf7fV\nHHPFXpuSzfL150sNf6ge4E4ZZhBPrRcDg7GU6ZjbonGgi7hARpKyU+fiPKXG908W\nP5cjmFomkz6rCVOeK0JEmVrxAlpAomTuTBMhEmjeqP19j3CGYauGHAAe8C6lERZ1\npvTXUS7+vioy1JYuEJVCWVE5DPp1yA6iBmuPG+DxvlapSJ1uD2cW4XhUflQjOwfA\nxBhhEhdY49XIH0iaa+ygfoKtkbPITxgYlk1EKu1yDgjPJ/DSO+4qQdsxwUL1PvfY\nMZZi7/MRyzQ7gX1MOlW1CG0m+UW6ZRLMdZ8WdNVN+gytVFoHZyWVp8Bt48GI+6DA\nOOvG2ohHVxlVpawlEJ5xd1ys2EwclVH4UM8CAwEAAaOCA3owggN2MCkGA1UdEQQi\nMCCCDyoubWlucGVuc2lvbi5zZYINbWlucGVuc2lvbi5zZTAJBgNVHRMEAjAAMG4G\nA1UdIARnMGUwYwYGZ4EMAQICMFkwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRo\nYXd0ZS5jb20vY3BzMC8GCCsGAQUFBwICMCMMIWh0dHBzOi8vd3d3LnRoYXd0ZS5j\nb20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCBaAwHwYDVR0jBBgwFoAUwk9IV/zR\nT5rAXTh9DgXb2S61UmAwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3RqLnN5bWNi\nLmNvbS90ai5jcmwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFcGCCsG\nAQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3RqLnN5bWNkLmNvbTAmBggr\nBgEFBQcwAoYaaHR0cDovL3RqLnN5bWNiLmNvbS90ai5jcnQwggH2BgorBgEEAdZ5\nAgQCBIIB5gSCAeIB4AB2AN3rHSt6DU+mIIuBrYFocH4ujp0B1VyIjT0RxM227L7M\nAAABWN53LHkAAAQDAEcwRQIhANKbz22YATzbyv2DsuBOONOQlrSyfr7ZwkcrVQVx\nKo/OAiBffkNpsiqNgvw3Mua5giyk7KRIZzmj/RuA6pIPs5d8nAB3AO5Lvbd1zmC6\n4UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABWN53LMQAAAQDAEgwRgIhAKu7WS3z\n4RlEKvfBEEkXaU9ZsWfuWOERiBcgaXuGOI4HAiEAq34zpW7ww+W3Ka1gkn20RhyI\ntB4A8agZoRPO4S5SJx8AdgC8eOHfxfY8aEZJM02hD6FfCXlpIAnAgbTz9pF/Ptm4\npQAAAVjedy1wAAAEAwBHMEUCIH/iku72aTt3OjeL6QZepzX29fwae6AIEuW7Xdvu\nSkfKAiEAyQdE96NxQODnytn2FsMDLFbVHpjR/r9Ux3/eXc/2Q9QAdQCkuQmQtBhY\nFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAVjedyyXAAAEAwBGMEQCIDz9ITBk\n5QE0Cokr1xotGVZbu7tzKmtEZVzEybbgb2KWAiBVgdBjh2mY4bIvjCDn0sOyeYiV\n8tOU0MHtw7IUoRcqjzANBgkqhkiG9w0BAQsFAAOCAQEAo6HA2EVB3j6KI56nKdUY\nsgKquCOylrAjPH3Ov9+E6Z71vCrpVBkB24oy3lhO6F3194HwQR8PsuMSBY35etm5\n3E/Lg9GtvRydyKzO3IE3oP0JTKC2qjBS8GHhTZe+fCOlOUmBvTRV5efv0asSBr3f\neplRu9iuJWXtlH4eTSLtJPI3d7Cy7rSe8pYcFItNAKP3cBt28Od3Q4i+6cFN5YNu\nxGq3V+6RIQLbjYtN8QOkmNZbCEFiLIT0aTKRzRS2Qsji62fQCGVrVTBFzOlenwLx\nBcf6wJ+l96odQxruyF9Lf7FYkysSVsNcygIFglaI5RzcpuGH8k6fzciuN43lEhl+\nzA==\n-----END CERTIFICATE-----\nwww.minpension.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_nordnet.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIG0TCCBbmgAwIBAgIQCTG/PvH6DLLelnjWPIWjUzANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTUwNTA2MDAwMDAwWhcNMTcwNzAx\nMjM1OTU5WjCB4jETMBEGCysGAQQBgjc8AgEDEwJTRTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xEzARBgNVBAUTCjUxNjQwNjAwMjExCzAJBgNVBAYTAlNF\nMRIwEAYDVQQRDAlTRS0xNjcgMTQxEjAQBgNVBAgMCVN0b2NraG9sbTEPMA0GA1UE\nBwwGQnJvbW1hMR4wHAYDVQQJDBVHdXN0YXZzbHVuZHN2YWdlbiAxNDExGDAWBgNV\nBAoMD05vcmRuZXQgQmFuayBBQjEXMBUGA1UEAwwOd3d3Lm5vcmRuZXQuc2UwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD19QZG/9p2hPU9j/r6rN+Yad0g\nyjn0BTes4FjVSU5LEizmnvAkCQAuP1+UtMt7YSWGR0f5YgbB25MYUnZAzjqD66U8\nGQFD2rIH5mIzmnePnyZ5D4L/8eR5DBYNENkxLCcRwVrloYWrHFVU71YvfmThZDD0\nivyHLp3yNvtpH2UhsXFbax58sikj6SrQ6oR4iv91rr+EfIZwxvWaRH9iyMNCidyU\n76Zp4vJjdJLScIJPbse62tHHP5LR4rvxil0WV/WjTjxETBuXXFKWVNp6n3ai5kmn\n/rSv6w0KxKM0En74XQcv3K3V+CjGhI/uUZGr75iv0lveieO/VLz7931dUMm1AgMB\nAAGjggLrMIIC5zAZBgNVHREEEjAQgg53d3cubm9yZG5ldC5zZTAJBgNVHRMEAjAA\nMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\nZgYDVR0gBF8wXTBbBgtghkgBhvhFAQcXBjBMMCMGCCsGAQUFBwIBFhdodHRwczov\nL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZGhdodHRwczovL2Quc3ltY2Iu\nY29tL3JwYTAfBgNVHSMEGDAWgBQBWavn3ToLWaZkY9bPIAdX1ZHnajArBgNVHR8E\nJDAiMCCgHqAchhpodHRwOi8vc3Iuc3ltY2IuY29tL3NyLmNybDBXBggrBgEFBQcB\nAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zci5zeW1jZC5jb20wJgYIKwYBBQUH\nMAKGGmh0dHA6Ly9zci5zeW1jYi5jb20vc3IuY3J0MIIBfwYKKwYBBAHWeQIEAgSC\nAW8EggFrAWkAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAU0p\nm/IhAAAEAwBHMEUCIQDuu9Aee6kHSG9zqkJ82cuo4CXrtoP60MKX+7xsvrQpHQIg\nPxibS/kPGMNUkk2lClE+maBK0Zfykz7t6hvC3iXAfy4AdgBWFAaaL9fC7NP14b1E\nsj7HRna5vJkRXMDvlJhV1onQ3QAAAU0pm/NuAAAEAwBHMEUCIFlgHw4BqVQkGVxY\nEUhHT3jDvTa706kxjKQGjIclw9ETAiEA0pcjcMZFenkYvWtCLSw1dhfXw5aZ0ZUA\nnVf0ES45g/UAdwBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAU0p\nm/I8AAAEAwBIMEYCIQDMCYzT+1JboVJYLdJxfaQnLqc2eBL6sb+nNvKc0DxcNQIh\nALj6CbaMVBFksrqJWhW1i8donesjevi+fl6EOHY+FAtQMA0GCSqGSIb3DQEBCwUA\nA4IBAQBmE3iKXcUKbK+dGlQOf/3tOXWf92fiPzEIVc2FAg+BZKllKpFza7AOMEFK\nPCSF9I6tSbglqYn/xpYFDQMw+XWwcuqoWYe0o2V/y9/hIFxxVEjKJkGLOjp92ShN\n0gIPAgWtMGEdAFJQs0qk5k8MxaE+2jy7XJrkc0pWTVvRh5qDol+uPS0BsX/RJdgm\n0vZ/fN0B02l3N4CIO8xzr0LqQZqIhVBxiyF10iI+wYV6a0waaQuYDvIyl8+6aPuN\nEwlNPYwqys021AJq6dhmNgEIrGIJRRLleOQQnIYBYX2uBPnpEZoN/pITGA/wzwCc\nrmjH7XVO3UTpgBRIpl/8UpVNm5cV\n-----END CERTIFICATE-----\nwww.nordnet.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_okq8.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGpjCCBY6gAwIBAgIQLfVa7JpgOJYVyDHLos+aYTANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwNTE4MDAwMDAwWhcNMTcwODE3\nMjM1OTU5WjCBrjETMBEGCysGAQQBgjc8AgEDEwJOTzEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xFDASBgNVBAUTCzkzMyAwMTIgODY3MQswCQYDVQQGEwJO\nTzEQMA4GA1UECAwHRm9ybmVidTEQMA4GA1UEBwwHRm9ybmVidTEWMBQGA1UECgwN\nRVZSWSBOT1JHRSBBUzEZMBcGA1UEAwwQbmV0dGJhbmsuZWRiLmNvbTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBANavewIOCNulmbOCw9k7uf0tSe4DVcXD\nGhbDm5C+u/XsGEgi8/jm/WA5H1wOd1ejp/IuFOttvv5E53Qqlt3kMrOv2sW4etw8\nDia2I5fUtDvZxCqBk1hXFrt9o1845ThpPQDsGhLkYLIbPP8cjFKhDs51Y7pwh1mV\nCD01X+b3aPVIlkyde0d80EdgTUenD7Wf14y7XPaeYq9pRWGbBXpaohjVZu2Twqd3\n/R+OLgpDVSWY4A8xgQPGPtr/1xheCUJNY5q5BBZaxO339cQxefxGCG+Qj7SQD0yw\nvPo7J19ETdpfa5RGvg+801E61MlS4dkz9lk6rpLV4oofd1H0vJhwWhcCAwEAAaOC\nAvQwggLwMBsGA1UdEQQUMBKCEG5ldHRiYW5rLmVkYi5jb20wCQYDVR0TBAIwADAO\nBgNVHQ8BAf8EBAMCBaAwbwYDVR0gBGgwZjBbBgtghkgBhvhFAQcXBjBMMCMGCCsG\nAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdo\ndHRwczovL2Quc3ltY2IuY29tL3JwYTAHBgVngQwBATArBgNVHR8EJDAiMCCgHqAc\nhhpodHRwOi8vc3Iuc3ltY2IuY29tL3NyLmNybDAdBgNVHSUEFjAUBggrBgEFBQcD\nAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUAVmr5906C1mmZGPWzyAHV9WR52owVwYI\nKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Iuc3ltY2QuY29tMCYG\nCCsGAQUFBzAChhpodHRwOi8vc3Iuc3ltY2IuY29tL3NyLmNydDCCAX0GCisGAQQB\n1nkCBAIEggFtBIIBaQFnAHcA3esdK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbs\nvswAAAFUxYZvBgAABAMASDBGAiEAo3DacSbjLPzS94+PUg87ICK6IYfPwVD9AJSQ\nMKt08EgCIQCbJDle9ao/8lOQq7/dEux8D217ya0cklg7K9/HkwNR9gB1AKS5CZC0\nGFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABVMWGb1AAAAQDAEYwRAIgFdU/\n8x3SuhbHab6LeuP9pfRCJS9M4kE5Ks4aV7yu4boCIHV6MXwxlHn8NEQQdOtia1P4\nb96USsTGKkQv1XpmE95oAHUAaPaY+B9kgr46jO65KB1M/HFRXWeT1ETRCmesu09P\n+8QAAAFUxYZvMAAABAMARjBEAiA5DZx7L5hPDTRpk3yqUZuL4tM1dWxjHWFgcn7J\nDm/C4wIgNWKbrt5YmaQ1qJAlWzw3X5a1IX9z7+iWwtmbHXr0E+UwDQYJKoZIhvcN\nAQELBQADggEBABkhWVVGEjDT/2Y4dxMJjfIYoA84gZJFJcNpqgV9ZgrfnPdmiJCP\nSmOhplBoFS2tpLukv9m566HmlZXYgX1pQQfXoNeFvcLtIUtGibIkKygeQT2emdnL\nuJBHpNYthNUSFAi5KVQqRUzZ5PsoVsyr5RSeJOXoaIPJofJpG7qDfzZEWRndrTQV\nqZdkaXlNs4Om0xkgj+qCnaToHR5Mh/hlpxuPnGB/c69Jz6eDRg3dW7KJVnYGCJfS\nwJysxy9DHacJojLMdBl8E3xPkn1SVNv1C24cGishLcfSWKvinm4z/brSWd7HvIUp\nhldUTZe6PNFogJtLQ49aehfHDSOCNLM4xrE=\n-----END CERTIFICATE-----\nnettbank.edb.com:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ostgotatrafiken_login.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFfjCCBGagAwIBAgIRAKOKgCqyMq9biovKz3eHTo8wDQYJKoZIhvcNAQEFBQAw\ngY4xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTQwMgYD\nVQQDEytDT01PRE8gRG9tYWluIFZhbGlkYXRpb24gTGVnYWN5IFNlcnZlciBDQSAy\nMB4XDTE2MTIxOTAwMDAwMFoXDTE3MTIxNzIzNTk1OVowazEhMB8GA1UECxMYRG9t\nYWluIENvbnRyb2wgVmFsaWRhdGVkMSAwHgYDVQQLExdMZWdhY3kgTXVsdGktRG9t\nYWluIFNTTDEkMCIGA1UEAxMbc3NsNTEzMjMxLmNsb3VkZmxhcmVzc2wuY29tMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoo5oiTWjySYRFPue9v7OFv27\n95/KJcUZ50tTZx+Mu0XsM/vIeEifp2+/EMq13kr26xlY4mytJ8amhZlIC1gwh3/7\n29RngE9u88UGJzhWKFmNu4yCtVZCoMkALaN4xIbVmlJVm6MWXFPDDYD2NVOA85TM\nH28ACxkU5uch9a02LktuV0Evq8Uqb+ldSqDKNz9mp1whTb8WOwqDFDxlRXu6U1pR\ng8YK1Wlc58hY8wgLnm5JwHnxYbHfAE5yiJMJ/d9HMxsKcooSMtP8WY42XJmcJ94B\n15WJgLtZq/J7s+nvaRJ+roncNhx9kpHvUAO1E3aSrI4rT6iz6H4Iep/3b51THwID\nAQABo4IB9zCCAfMwHwYDVR0jBBgwFoAUmY4ClcUeVSJ7h3CLXhwBwnbErugwHQYD\nVR0OBBYEFFd9xsH12GaSTSgdudw1HKZ905dqMA4GA1UdDwEB/wQEAwIFoDAMBgNV\nHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBFBgNVHSAE\nPjA8MDoGCysGAQQBsjEBAgIHMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJl\nLmNvbW9kby5jb20vQ1BTMFMGA1UdHwRMMEowSKBGoESGQmh0dHA6Ly9jcmwuY29t\nb2RvY2E0LmNvbS9DT01PRE9Eb21haW5WYWxpZGF0aW9uTGVnYWN5U2VydmVyQ0Ey\nLmNybDCBhQYIKwYBBQUHAQEEeTB3ME4GCCsGAQUFBzAChkJodHRwOi8vY3J0LmNv\nbW9kb2NhNC5jb20vQ09NT0RPRG9tYWluVmFsaWRhdGlvbkxlZ2FjeVNlcnZlckNB\nMi5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLmNvbW9kb2NhNC5jb20wUAYD\nVR0RBEkwR4Ibc3NsNTEzMjMxLmNsb3VkZmxhcmVzc2wuY29tghQqLm9zdGdvdGF0\ncmFmaWtlbi5zZYISb3N0Z290YXRyYWZpa2VuLnNlMA0GCSqGSIb3DQEBBQUAA4IB\nAQBCyqq8Cl2smTKklqTNvjmJVz/HOOuHi/YplukWPv5Ztc6KrQ3m279ipdyQR4IK\nQ42iYhp7Z1/iw0WqCaDWHiibdJYKMaEWB6nr7BV2qvDnDdAgyTNcW4ZOLakfmy4y\nkGygPzt0cjlZMmSI8iTBPCD4cTkMtQ7EKn3kcRlZ5azBFqT5VXH9N3P183qz1sv6\niSg/pLR46dLy061+egeRoElS4Glggg0pAl1fv3duIGmYd3oREK3HRGHlCZ3dA0Hv\ncmJp6Qs2K1phPW3DC6EAVkDKyRUN3BiglOz3xu0eCdAVvnlUFveYcNnH8P2047x1\nS8rFrPmWlg/+TVPw8kuNxYxG\n-----END CERTIFICATE-----\nwww.ostgotatrafiken.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ostgotatrafiken_overview.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIF+zCCBOOgAwIBAgIQLkbSyzUCuYcvo3NrRnVRFDANBgkqhkiG9w0BAQsFADBC\nMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMS\nUmFwaWRTU0wgU0hBMjU2IENBMB4XDTE2MDUxMzAwMDAwMFoXDTE4MDcxMjIzNTk1\nOVowHzEdMBsGA1UEAwwUKi5vc3Rnb3RhdHJhZmlrZW4uc2UwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQCqlByXmkGHtN2T7Sn2fmH/M7nYiqbWkUrYuwss\nJuO8E38+sd4zhOzdPFoMS3r32iZ3szL0b79TaWs4/IyZo5ocsujWlZNMD8v5dWyI\n19HwL3hSs15VVFm5zaKO3YJIs+jd3GGQG75IS7iiFbDtduXo05LaRIF7gYSBreVu\noRNi5zO8owzBpoiSrOxO8fEoPxIEMYZhTQpdEpEhQywsb4xFGesjcGjcXdqENu89\ndxao6/BV1Nh3jBVXnTHGUbkj29CYkDrfjxJGHyhjUD57eiSnDgKXZl6wO0sfyg6h\nHpkDr9Lt0r+WygNfJwGvsjHl6bWR5G9J1OruaaLs8AqJg4ffAgMBAAGjggMOMIID\nCjAzBgNVHREELDAqghQqLm9zdGdvdGF0cmFmaWtlbi5zZYISb3N0Z290YXRyYWZp\na2VuLnNlMAkGA1UdEwQCMAAwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2dwLnN5\nbWNiLmNvbS9ncC5jcmwwbwYDVR0gBGgwZjBkBgZngQwBAgEwWjAqBggrBgEFBQcC\nARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMCwGCCsGAQUFBwICMCAM\nHmh0dHBzOi8vd3d3LnJhcGlkc3NsLmNvbS9sZWdhbDAfBgNVHSMEGDAWgBSXwidQ\nnsLJ7AyIMsh8reKmAU/abzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB\nBQUHAwEGCCsGAQUFBwMCMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0\ncDovL2dwLnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2dwLnN5bWNiLmNv\nbS9ncC5jcnQwggF/BgorBgEEAdZ5AgQCBIIBbwSCAWsBaQB2AN3rHSt6DU+mIIuB\nrYFocH4ujp0B1VyIjT0RxM227L7MAAABVKowxvMAAAQDAEcwRQIhAICW+ZzuMcXK\nK24R7FTtzPZ/+izSVZA8rFfv5M6xxLqXAiBu9+zAI87hcweWxYrSiNxXOZJFXX6d\ndHY37JPhhGwz+gB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAAB\nVKowxw8AAAQDAEcwRQIgRv9VjemfxOtAPm5X2tFRD+Wk4ihKyMqANPXUlcM3LaAC\nIQD42/kjfz5bMHR3ikoIZAD++fqdAPMlSPTfPW4+ssO4YQB3AGj2mPgfZIK+Oozu\nuSgdTPxxUV1nk9RE0QpnrLtPT/vEAAABVKowxwYAAAQDAEgwRgIhAMd0CW+Lxk6/\nkidq6fWMypRFJn2UyUuD2sBhJizO2jiQAiEAjxNZH4HbvYemK0CzB3uxe2fTA6mR\nhdOoWv3fmyVPUgAwDQYJKoZIhvcNAQELBQADggEBAJO3D9KV/Rjy0eeIvMWfDz+p\n5pwGecBImxLEKkdcv3DxhB6EVR18Yejs9p96MSxlvbWFr/sISL9VS6Yr85J1wADn\n+P3UkGq7B3JcZdKOY6aKfZvJYwDMXU+SvoFQZsE3B/OnVnb/GbwKemnpiCHFnkYQ\ncUxe8//x41e/H+6Aafs16vz7RVhDSnQaVTft5Ju6bdfurb9H9NXZ6oSTXFg3WBGx\nutdnWO5BiY1sil965JFiTCkaDXMPSHzq4uAge6JiU7BppAhsqd5CWQNKzgPL/B3F\n0hOvrUy14IrxKaQt/6JUlLgB7r+RdbbwPaAZoXLZmC9M02gsgwoTdp8XSzvx4x0=\n-----END CERTIFICATE-----\nwebtick.ostgotatrafiken.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_osuuspankki.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGSzCCBTOgAwIBAgIQQq4J10cEVtza7iMNxJPZGjANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYxMTI4MDAwMDAwWhcNMTcxMjEx\nMjM1OTU5WjCB0jETMBEGCysGAQQBgjc8AgEDEwJGSTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xEjAQBgNVBAUTCTAyNDI1MjItMTELMAkGA1UEBhMCRkkx\nDjAMBgNVBBEMBTAwNTEwMRAwDgYDVQQIDAdVdXNpbWFhMREwDwYDVQQHDAhIZWxz\naW5raTEaMBgGA1UECQwRVGVvbGxpc3V1c2thdHUgMUIxFjAUBgNVBAoMDU9QIE9z\ndXVza3VudGExEjAQBgNVBAMMCXd3dy5vcC5maTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAOtUH95ashzyEZYAvTzQ9EEijM7+styfIK/KZBJWUKM0+mod\nhaod+cGvMT27IDm/EZt013X4RG8RbW74K54bdHdBkwFDOpVTRLL6ZGiGkz+C/Dd4\n+iPXJwKek0Bw+BicTwIayyvOIa3NlAGaJWUVG/R9MLZGu+Tx9/LtYStXQHOmBdsy\njocNN+62OjFW/J11KW2jQTPeg/gZ7iE4S92U1jythHZp0/pSNYW2jCh8HAHj5F2d\nSe8VAkW5M7X7I30RVcb2tN4c2vdjSXsedwxlvPrZ+9SNpA+vHiTcH+PhVCeRfWnD\nvw96bSeS3XWSai+5dRxTiBHjkMT6VdA8HJLc2lkCAwEAAaOCAnUwggJxMBQGA1Ud\nEQQNMAuCCXd3dy5vcC5maTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAdBgNV\nHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwbwYDVR0gBGgwZjAHBgVngQwBATBb\nBgtghkgBhvhFAQcXBjBMMCMGCCsGAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29t\nL2NwczAlBggrBgEFBQcCAjAZDBdodHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNV\nHSMEGDAWgBQBWavn3ToLWaZkY9bPIAdX1ZHnajArBgNVHR8EJDAiMCCgHqAchhpo\ndHRwOi8vc3Iuc3ltY2IuY29tL3NyLmNybDBXBggrBgEFBQcBAQRLMEkwHwYIKwYB\nBQUHMAGGE2h0dHA6Ly9zci5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly9z\nci5zeW1jYi5jb20vc3IuY3J0MIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHcA3esd\nK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbsvswAAAFYquWeNQAABAMASDBGAiEA\nm/vqbAbbDWYSuyDaeX/tL0Tgu6Yd9fTYsNS4sAPR3V8CIQDHEuKjK6b26BaEX3NM\n06N2iRP/Fc6jAG902C+DGoKf1AB2AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDE\ne4l6qP3LAAABWKrlnoQAAAQDAEcwRQIhAPfcqyFXMb4jVRim8DIE/ahDR2T6KaZ5\n/Pk4oQIf0RkvAiBjbtXK8OxVk20vce9jgblMdYaANEuX1uZ/m91qCG0i3TANBgkq\nhkiG9w0BAQsFAAOCAQEASAe4g82eWmOp9ALiojwejKwQVV4LbT7vQ8smZGhptu1p\nr4zUppGqXRLpaJjudgLIgZsrHygbGTPJaqw8HR7PYjMt3fOozwH/W2dVHNhjPp09\nIiBtERECYB9LXkbIC/Iqgn60OWgnaoh7mPjH6jgVGsG/KpDRyLQUx64nLIMFXqdV\n06xu/JcmEoe/5Tf30kcvVAB0I5T17FvzXoAQXUn2IgjYbPomC+Gg3YB80cz6/+NR\nGTBonUx/4aK3XhC5NyFYoR+U+rzEZOPwwLb8kdfg7ykSqz9OngKQl/lgpHsSmIqM\ncB1X7Qc6VtmqOTNuKPcPRlA7OV4N3DYNzhC2ePxoIw==\n-----END CERTIFICATE-----\nwww.op.fi:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_osuuspankki_mobile.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFyzCCBLOgAwIBAgIQNuC1ww5v/flYBsp+YToqozANBgkqhkiG9w0BAQsFADB+\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj\nIENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE2MDkxMzAwMDAwMFoX\nDTE3MDkxNDIzNTk1OVowXDELMAkGA1UEBhMCRkkxEDAOBgNVBAgMB1V1c2ltYWEx\nETAPBgNVBAcMCEhlbHNpbmtpMRYwFAYDVQQKDA1PUCBPc3V1c2t1bnRhMRAwDgYD\nVQQDDAdtLm9wLmZpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlU2n\ntR+HsJxXUG19V0nLXNGzDlO6JV/nZfYtebWDSTXIbbU+7+Nkp7sKXZ0Q7h5HgWQC\nwRsy1BQpILs8aJW4cS8k8P8D4sinT7hkB7RknJlLGlYP6ET9ueypeCejQf3/FZAC\nLW75G3/KgMEYp6oYHB0rkqiYdDF7x0xwzYLXpzqrYcK4LEYer6vQ1TKDzbcl0z4W\nhfvd1yTvj2jhh2XBcqYGkq1tkESBMDRY/BGHWtmv9lA19pDl8bPtguwzVlRHyG2Y\nHSsGL5xeYEkKMxZU9hVeapjYyrIn1aQkL5MBWZWs/GFyL4muNQL3r0/VGaDS8EJh\nuzl+W+RJZq2D59/fcQIDAQABo4ICZTCCAmEwEgYDVR0RBAswCYIHbS5vcC5maTAJ\nBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI\nKwYBBQUHAwIwYQYDVR0gBFowWDBWBgZngQwBAgIwTDAjBggrBgEFBQcCARYXaHR0\ncHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0cHM6Ly9kLnN5\nbWNiLmNvbS9ycGEwHwYDVR0jBBgwFoAUX2DPYZBV34RDFIpgKrL1evRDGO8wKwYD\nVR0fBCQwIjAgoB6gHIYaaHR0cDovL3NzLnN5bWNiLmNvbS9zcy5jcmwwVwYIKwYB\nBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Muc3ltY2QuY29tMCYGCCsG\nAQUFBzAChhpodHRwOi8vc3Muc3ltY2IuY29tL3NzLmNydDCCAQUGCisGAQQB1nkC\nBAIEgfYEgfMA8QB3AN3rHSt6DU+mIIuBrYFocH4ujp0B1VyIjT0RxM227L7MAAAB\nVyPAKi0AAAQDAEgwRgIhAJl/ol6fKdRuV/RNGGWSO3SiRCDUjlgP1eB6GrvxuraH\nAiEA+1NQCkPhG9TQmc8E7iM2ECvYuYQjk3FAaDTsDFG+/DYAdgCkuQmQtBhYFIe7\nE6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAVcjwCtYAAAEAwBHMEUCIFuYPIUIO0vi\nP0dmlyrsm2qTrGDswbNrJa2jGkcl91zpAiEA4zEXEONS0gKLdU3U3JmwRC0InJkv\nee/vcfZGozcdNF4wDQYJKoZIhvcNAQELBQADggEBABQzNG2VogCzgpvHbxshzFUy\nMzUsEUSWyKySnD5AdD+29Vm8e3Fd7wjh8JwDuKFQzAkyMwpYXzwKrvd8ujjAg9SS\nRYspgJXSdwA3qNA71jcWtISQo0F9GwH0swH1Wfy0skQEQTeUvZz4HPiAZl2gxls6\nyaEqVdNNK8Qe7XhSxj+kGslhrRPg3T4KCmtMDmBwG1aWoT5NHHTG9OzDOTlmqG8K\nZfe2c5iJtw+Kh4cZAXykTPaieqWzqfVGtkjZGJDXLkca+c/ZT8V4GY0KGN6wSIQX\n8CsOC5k125QAF6q2Gq3Yk9kPsNXdoMyOGEwnzVlAezCAn1duXAVWLtXYyVjyf3Q=\n-----END CERTIFICATE-----\nm.op.fi:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_payson.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGsTCCBZmgAwIBAgIQGQ6DXwcjHWGwsEDhbB8dKjANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwNjA4MDAwMDAwWhcNMTgwOTA3\nMjM1OTU5WjCBsDETMBEGCysGAQQBgjc8AgEDEwJTRTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xFDASBgNVBAUTCzU1NjY0Ni0yODU4MQswCQYDVQQGEwJT\nRTEOMAwGA1UECAwFU29sbmExDjAMBgNVBAcMBVNvbG5hMRIwEAYDVQQKDAlQYXlz\nb24gQUIxCzAJBgNVBAsMAklUMRYwFAYDVQQDDA13d3cucGF5c29uLnNlMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArbrVPccCNT56QqBCcFhJxhNmsck2\ntwf5bUQLquYqfrJq7rl9aS9yVTlleK4nUYabmR04GZB0QUy+8SS18kUoYo8jgdnq\nwjak7zndsWoC60KK0fWgUXbqtv6NU4nmGrXoqOwCVH7RnAxyPHk8z2MXjKzRvHsS\nVVZ623jet5c/h9dPHHxw21L1KQI0Nw1XYYBoNanrcnCtoEGjvqai9DJiSmBFpNps\nXU3tmc5WK/CH6dNFUu6QAbB0eaaZfSjG0iQVipgN+cTHXpEhmt++bRhjmTgz9DAF\n42GZAg58d+6SGFAURd0uYU6d7a2xxO6LwsmRkWt7uO22JUVqZBPdZN4FNQIDAQAB\no4IC/TCCAvkwIwYDVR0RBBwwGoINd3d3LnBheXNvbi5zZYIJcGF5c29uLnNlMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMG8GA1UdIARoMGYwWwYLYIZIAYb4RQEH\nFwYwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYB\nBQUHAgIwGQwXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwBwYFZ4EMAQEwKwYDVR0f\nBCQwIjAgoB6gHIYaaHR0cDovL3NyLnN5bWNiLmNvbS9zci5jcmwwHQYDVR0lBBYw\nFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFAFZq+fdOgtZpmRj1s8g\nB1fVkedqMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3NyLnN5\nbWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL3NyLnN5bWNiLmNvbS9zci5jcnQw\nggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AN3rHSt6DU+mIIuBrYFocH4ujp0B\n1VyIjT0RxM227L7MAAABVS/P6xoAAAQDAEcwRQIhAIuPX9LzUGr9t/Fsljm4NRdi\nzxZFNXLJmFq6LmtBCKPgAiBZhjduuTl24u+lMWy70rMntd6dahUkJ2u5OtkRnKB0\n5wB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABVS/P6zAAAAQD\nAEcwRQIhAKws/fUHqQtTl+h8jLgeuYKXkCWf6wyw4xpG+JlqrGskAiAzJFmCi1bK\n8DkYgyZaAqln8scODHJsOXSlgY6OUAaFdQB2AGj2mPgfZIK+OozuuSgdTPxxUV1n\nk9RE0QpnrLtPT/vEAAABVS/P6zQAAAQDAEcwRQIhAKgq+kEfgeDqwD+wyX8/ond6\n8YpasnlfsVafA0rpN+GpAiBAXvio/Cu0sxMcmxQbkYXiumWMoTIAU6q9AHRWt77T\nPTANBgkqhkiG9w0BAQsFAAOCAQEAbopbxypaStbeVTFqQQljtczJQUMeyejUJfZv\nL7OO5hv+uLnvTW+dG4tocB1Vy0mY+gd8d/MjOyR42QY25ppzcbpCox1LnTFYEC+n\nLObE5wLq2VFxyR5/9P/tOBehCZEdxbDGS6cxVo4cPjKsTBKnJAzYYw0dyVSAaLJA\nllYYeF2ihJVdqfxMZymrOFaSdg8z/7/msE9Czp/UO8wCMCVnjaqxOKnf7NEI56yR\n0wjzV58FbpBdKvVLC1PfF0XR8pTQVubNnoYeiZeAHL59Yd8hK+slVTtu5qfUvkPx\njYpLhiApQY5dOsFYOIP9pWFdV9azfAvqe1NSFQ1OSdPZoVelKA==\n-----END CERTIFICATE-----\nwww.payson.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_plusgirot.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGfjCCBWagAwIBAgIQbo/Txp+O1DUri0MJuySE2TANBgkqhkiG9w0BAQsFADB+\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj\nIENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE2MTAxNzAwMDAwMFoX\nDTE4MDEwMTIzNTk1OVowgYUxCzAJBgNVBAYTAlNFMRIwEAYDVQQIDAlTdG9ja2hv\nbG0xEjAQBgNVBAcMCVN0b2NraG9sbTEXMBUGA1UECgwOTm9yZGVhIEJhbmsgQUIx\nEjAQBgNVBAsMCVBsdXNnaXJvdDEhMB8GA1UEAwwYa29udG91dGRyYWcucGx1c2dp\ncm90LnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt4V4w7RVKJ8Z\nNTZzhpe04u5MuknawqYN2q8OA2d23kvKor2YVIuTGvNzJo098s+gqlqINUwAU7At\n4nn9z4+4JSJ4+tqK/xZVjLvzC9Y0enVXfvsmaOy9jp+oA5riJf5378ta+QHjLwU2\nm9kglEE7FiXJ7gNV8TaTpVTmKDvDCIrtG1pQPMNE4zAsEWtDSAjwe68Mkl2ZKbcq\na+k+LfIy/Yyhi65RJVtRN9o99bq+ZrBoLZ6eFX4Tu9TkzlMj5YN370Hz0tT7Vuez\nEXLn70rJMPzxEfgwox/PYMccStviIc0++3tkgP3rAgjrtyCPL4lknsx+Ki8hgvIq\nz6T+jWB2HQIDAQABo4IC7jCCAuowIwYDVR0RBBwwGoIYa29udG91dGRyYWcucGx1\nc2dpcm90LnNlMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG\nCCsGAQUFBwMBBggrBgEFBQcDAjBhBgNVHSAEWjBYMFYGBmeBDAECAjBMMCMGCCsG\nAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdo\ndHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNVHSMEGDAWgBRfYM9hkFXfhEMUimAq\nsvV69EMY7zArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vc3Muc3ltY2IuY29tL3Nz\nLmNybDBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zcy5zeW1j\nZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly9zcy5zeW1jYi5jb20vc3MuY3J0MIIB\nfQYKKwYBBAHWeQIEAgSCAW0EggFpAWcAdgDd6x0reg1PpiCLga2BaHB+Lo6dAdVc\niI09EcTNtuy+zAAAAVfSdPmrAAAEAwBHMEUCIQDSRYkISpRrL2N/NzY1ngBn6KRP\n4sx65PoH0HSMPqlk5wIgIedk8JhBZweilNtXUjPNlaiu4NuDqBnJho3s+8f88IUA\ndgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAVfSdPnPAAAEAwBH\nMEUCIQCUTIT2u3vxVEPTD3Gpp1WD8qhnvTlbxojEI1dkOyZcggIgP7N2EnIFgD0n\nK2XhfHUyShXUbwjjhVz5+mlQxRTI58AAdQDuS723dc5guuFCaR+r4Z5mow9+X7By\n2IMAxHuJeqj9ywAAAVfSdPoNAAAEAwBGMEQCIBm+P4i7KuRUws/IppdxW0gAyzTj\ncCN3pyEYnu5A8Zm9AiAmJAwRz9Yd69pps3ulXTfLp4YZUHg63yv7lvJPwuqrczAN\nBgkqhkiG9w0BAQsFAAOCAQEABJ6GLvONcxtkEazxo4EBKDagkHkri5dmP9m6LSgD\nOljqxfuYyXX6d2I6ZkA9TdtFwdInPuCI9L5clHKE7i38SMSfTiLgiz6978jeYZso\n9PyHvs2rx6W8hn6wvCchIHt189ddBXF4BXAsL/KmaMjfDzm8ANNvVXqrUZ4ZKuvj\nUvFerDUmeJEPN88pIHmCLf0xCj2A1OSskFYLiPRuSPBycUU6m5eC7Blt2d9M6u1f\nBAi8cOyC6jv224QZl4QuuoxHzncJwP+DbbRkXovIzn4iFkY8SjbJLMGeM+hf/46X\nb7/H85qGm2J9Bge974C59pUB+NiDLZIhEK9SazvkSsDEiw==\n-----END CERTIFICATE-----\nkontoutdrag.plusgirot.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_rikslunchen.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEOTCCAyGgAwIBAgIDCkK4MA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNVBAYTAlVT\nMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdSYXBpZFNTTCBTSEEy\nNTYgQ0EgLSBHMzAeFw0xNjAyMTQxNDI0NTBaFw0xOTA1MTMxNjU4MjRaMBsxGTAX\nBgNVBAMMECoucmlrc2x1bmNoZW4uc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQCyH+246rIeQoBTKdOScIcHiE9i48fSAqDDO40v289T/aLsFnQMFRhp\nLTSD6RMCJuKkpGopU+AzS9L6R8O1yWTwHGMSU+Jv0O8Rb/OCwsIVz88CblK99WUg\nVpJkTt7pPQHylvanZVRe5gl8WsGAzt5UIBb2SOUJNX+xhKyT3Y7xN5YYCIJE5JYY\nrLv8W+kiWrINOZquEn5JEaNVcu2Qza9vgOJKhXpvxSEzJigEpVK+WOrRWCHw8Jld\ni8dJ4CtHnyHSTEx2X5O6zcQOgd8wtvdp5cYtB0lk6tPGChh1KziFxx6lVIdNI3U5\nFg38Vzb2kMOTSlWUiVX3CMLMFdxAIKpjAgMBAAGjggFYMIIBVDAfBgNVHSMEGDAW\ngBTDnPP800YINLvORn+gfFvz4gjLWTBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUH\nMAGGE2h0dHA6Ly9ndi5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly9ndi5z\neW1jYi5jb20vZ3YuY3J0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwKwYDVR0RBCQwIoIQKi5yaWtzbHVuY2hlbi5zZYIOcmlr\nc2x1bmNoZW4uc2UwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv\nbS9ndi5jcmwwDAYDVR0TAQH/BAIwADBBBgNVHSAEOjA4MDYGBmeBDAECATAsMCoG\nCCsGAQUFBwIBFh5odHRwczovL3d3dy5yYXBpZHNzbC5jb20vbGVnYWwwDQYJKoZI\nhvcNAQELBQADggEBACbLp2QSWaCPsS0Hx6VjN/UFkQdLu1V3pt7nvx8QM/V9mw40\nMwCnt8j3jVP2AucifWrCDNZnS+2hC4nC8sTVtrAO6TbM2vEbeYYWKZuLAhbmo35C\nhZqdMvDReJosiV47B7WKAUVsuatpfei8owegMss7QKZTcQ7BY+4IHc9qX7v7c4Wd\n0foDeA3Qx/9/gkZkELRaNzL+3aOoYAtDzSH7wAgVcl4QVbYflTji6I+yWG6X0Vot\ngX00C4zMb+bDWd4Bcv9kXmLvwVNI5QVH5l/1O/qghtIdD55jvbzd73/JEEF4JaM5\nrObGzID7GRO2w+H/KWkfkGe1hf1PiEZ0DGKHU3g=\n-----END CERTIFICATE-----\nwww.rikslunchen.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_sevenday.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIErzCCA5egAwIBAgIQEnMLH/kKPg6noEtYTbkbsTANBgkqhkiG9w0BAQsFADBB\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMRswGQYDVQQDExJ0\naGF3dGUgU1NMIENBIC0gRzIwHhcNMTUwOTE2MDAwMDAwWhcNMTgxMjE1MjM1OTU5\nWjBmMQswCQYDVQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMQ4wDAYDVQQHFAVL\naXN0YTEbMBkGA1UEChQSU2V2ZW5EYXkgRmluYW5zIEFCMRYwFAYDVQQDFA0qLnNl\ndmVuZGF5LnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvr2Of0jn\napOhMEVOS4LDOqXgvtrJMnyO67WHU58EoFfIPS2gas5uvcZOfmmw977+ZcwsoMZ9\nKkI7/M2wRDht0zKGmY1qsOXKQ81iPfh86SahPW2UFw6/Xy3Eo86IdNL5+tvdYyuw\nrpEvLN3Vzc3Wk4PJFkQ2gAXQ9IqQg5xNC0A5sFu2o09nSM7L8E2gJBuynY6uckLJ\nnyGjnDDDKP8L+9BWZhmx49BDblMlcGlQZp2OgSFwMyPTjxT1TA9M3vokS6kVTMIR\nNC6YdGY4K720eVQ7DGMfaN4fdaiFVSKWq0gA3WRINLylj25NcNX5BqRkHYSkKCEb\nO5i14MhuYhkcJwIDAQABo4IBfDCCAXgwJQYDVR0RBB4wHIINKi5zZXZlbmRheS5z\nZYILc2V2ZW5kYXkuc2UwCQYDVR0TBAIwADBuBgNVHSAEZzBlMGMGBmeBDAECAjBZ\nMCYGCCsGAQUFBwIBFhpodHRwczovL3d3dy50aGF3dGUuY29tL2NwczAvBggrBgEF\nBQcCAjAjDCFodHRwczovL3d3dy50aGF3dGUuY29tL3JlcG9zaXRvcnkwDgYDVR0P\nAQH/BAQDAgWgMB8GA1UdIwQYMBaAFMJPSFf80U+awF04fQ4F29kutVJgMCsGA1Ud\nHwQkMCIwIKAeoByGGmh0dHA6Ly90ai5zeW1jYi5jb20vdGouY3JsMB0GA1UdJQQW\nMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUH\nMAGGE2h0dHA6Ly90ai5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly90ai5z\neW1jYi5jb20vdGouY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQCxlYGend2ODu6asV7a\n5AC+nAyqEbrfti590lDGl6gV34XtQqZs6DnW4ajrU8LxAAOYt9wA9/ByiHs+1lmd\nsN1CTdSx1w8W54X19Suj4ZxqaWdASZ+0S7bQzWDY9odQ6onkz/e3curwEGEUYqVg\nmUTzdXTrhEIDjn1N0FNAaAgFwIN7mA2Lqb0KaOS4rb08VDxpVCR5y+CgmZdPIJ4t\nUfuc8ZEwqnnG+llsqCtxUjqHSwpXnXuGrIK0Ce3je/h52jv9M9KDqfPyWC43WVr6\nv1XIL6LhBXAuJsNUg1oI2OObLiySpqVqIkopoDoXEsBqL9zgV9msx76Q4HGSE5Ch\nbxGM\n-----END CERTIFICATE-----\nwww.sevenday.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_sveadirekt.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIGFjCCBP6gAwIBAgIQZQtOWNvqlxeWRXvCoRU4iDANBgkqhkiG9w0BAQsFADB+\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj\nIENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE2MDMyOTAwMDAwMFoX\nDTE3MDMzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlNFMRgwFgYDVQQIDA9TdG9ja2hv\nbG1zIEzDpG4xDjAMBgNVBAcMBVNvbG5hMRgwFgYDVQQKDA9TdmVhIEVrb25vbWkg\nQUIxFDASBgNVBAsMC1N2ZWEgRGlyZWt0MR8wHQYDVQQDDBZzZXJ2aWNlcy5zdmVh\nZGlyZWt0LnNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuHvXAKj5\nfX619BB7e2CcCcdlA42Z9Rg/z3eREi3Tbtz4dUdFYkuVilw9CK1zNjzRvYl6H3V0\nk5aGpc/WyXakfDVw60+9UQwiit2bctXtI1trd9U5oRTmV9JZbSNXmDWMxpRNsFZp\nOZQlBi49DufCuDmjTmpwtV6ozcJ8rd6HdhxyHyOfvFF3Vavgsx2rvbKroBEgV8qj\n7YR3zMjWgyEelWgr4sTxr6uYWDObXiWlzKwAO0d7C5M0LtmlMjeRaBfkKvPnMWtz\n+Bi1A0P80t1jQrIfMhGNMcaSxQbCk4qpsqgzXW2831Zd8bO4yPL0OghRWOnk0ULX\noGDHBA4GN7h7gQIDAQABo4ICgzCCAn8wMwYDVR0RBCwwKoIWc2VydmljZXMuc3Zl\nYWRpcmVrdC5zZYIQd3Muc3ZlYWRpcmVrdC5zZTAJBgNVHRMEAjAAMA4GA1UdDwEB\n/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwYQYDVR0gBFow\nWDBWBgZngQwBAgIwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9j\ncHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwHwYDVR0j\nBBgwFoAUX2DPYZBV34RDFIpgKrL1evRDGO8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0\ncDovL3NzLnN5bWNiLmNvbS9zcy5jcmwwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUF\nBzABhhNodHRwOi8vc3Muc3ltY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vc3Mu\nc3ltY2IuY29tL3NzLmNydDCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AN3rHSt6\nDU+mIIuBrYFocH4ujp0B1VyIjT0RxM227L7MAAABU8FTg70AAAQDAEYwRAIgZMbg\n7avyLJpvSS8qn7LkBW3C1lu6N7P+V6DNNMddmKICIApm3Z8HYw1UupSOSrE7jDdm\n/9yLrC0LhXA04kr+zgUNAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN\n3BAAAAFTwVOD7gAABAMARjBEAiBuwgAVcDfrGxq54UsEe7gXP7Fxrr8T8qbCpKS4\neb3K/wIgMBDBukKQ/xVkk+pf8Si9EK10LQ4Aty+Z+bLLcYIr7I4wDQYJKoZIhvcN\nAQELBQADggEBAIGYKrWzy+jGQAcI2dbRRYdhgXajeXE9nLCVRdI3R5H8Snp6EOSp\nn2BsqOZejER+L2Dig4nSuNuYbzq/iePQbFy4lsYUSRty8A7+VZ2H8YUdO0MOolS0\nF1xdGG2KLoBdNimoY5sSKB6+mD7C9FRhE3DdycFpCpu9lDWGXyA9OrBdgzdaWTEi\n4dNX2OmLhYF5o6QULPjpNzcFg7Mq86dl4EcBY5RUleCCyVjb2mn3n0iy6e87hawT\nLpNKhoxFeruBtPeWir4Nk/h0/5H6e2MJ+zkr4fGBMSuqQXLcXF5fz1qL6lbb1H6g\nP2Q+Ku4TW1U8XTyODlsk3DUhaMIuI8clg2s=\n-----END CERTIFICATE-----\nservices.sveadirekt.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_svenskaspel.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIHJDCCBgygAwIBAgIQR26lBh+7DwXPQtJSfT8vwjANBgkqhkiG9w0BAQsFADB3\nMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd\nBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj\nIENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwNDIyMDAwMDAwWhcNMTgwNTAz\nMjM1OTU5WjCB9zETMBEGCysGAQQBgjc8AgEDEwJTRTEdMBsGA1UEDxMUUHJpdmF0\nZSBPcmdhbml6YXRpb24xEzARBgNVBAUTCjU1NjQ2MDE4MTIxCzAJBgNVBAYTAlNF\nMQ8wDQYDVQQRDAY2MjEgMzkxEDAOBgNVBAgMB0dvdGxhbmQxDjAMBgNVBAcMBVZp\nc2J5MRwwGgYDVQQJDBNOb3JyYSBIYW5zZWdhdGFuIDE3MRgwFgYDVQQKDA9BQiBT\ndmVuc2thIFNwZWwxFzAVBgNVBAsMDklULUF2ZGVsbmluZ2VuMRswGQYDVQQDDBJ3\nd3cuc3ZlbnNrYXNwZWwuc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQC6Ns14X85QKNKh4VFKcWcww0nPMiDVV693hTeDq1g4nlWMxVkQlTVzyUSFQHr5\ndya1x2GujbZyyidPt3CbTtro5LbldCrdD06lVH8W5Lfl58CaI+CjuOfNvHveFDYf\nBWkBvVme0YFsnsBLaS+OI1tcLos/ZIWk5a7jFAJzdsQOlX+wZ39hmXzl+j6kDLny\nZDpJ2ik2XRxPEvhNCMPxvtd3EMb1XBpEbnEC6KJKMAfKHdgNiwebQSVJDmtOC5Ib\ndrePnnFqiDY7y9LonkmNYyME4UyPCsy9On+z+hNu51jdDBBvCsx44hhttFXv4R5q\nIj025IKu+oy7Vs+80vG0vlKFAgMBAAGjggMpMIIDJTBOBgNVHREERzBFghZhcGku\nd3d3LnN2ZW5za2FzcGVsLnNlghdsdW5hLnd3dy5zdmVuc2thc3BlbC5zZYISd3d3\nLnN2ZW5za2FzcGVsLnNlMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBvBgNVHSAEaDBmMAcGBWeBDAEBMFsG\nC2CGSAGG+EUBBxcGMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20v\nY3BzMCUGCCsGAQUFBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMB8GA1Ud\nIwQYMBaAFAFZq+fdOgtZpmRj1s8gB1fVkedqMCsGA1UdHwQkMCIwIKAeoByGGmh0\ndHA6Ly9zci5zeW1jYi5jb20vc3IuY3JsMFcGCCsGAQUFBwEBBEswSTAfBggrBgEF\nBQcwAYYTaHR0cDovL3NyLnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL3Ny\nLnN5bWNiLmNvbS9zci5jcnQwggF/BgorBgEEAdZ5AgQCBIIBbwSCAWsBaQB2AN3r\nHSt6DU+mIIuBrYFocH4ujp0B1VyIjT0RxM227L7MAAABVD0+IlQAAAQDAEcwRQIg\nDm7FNeveY4f2+vL3K2/5YTns/EoFjoqzbdNx3ZVeMZQCIQC7Wh/fcmoavBl7srtN\nYrR7mF1mnUgJcbU0H0D5NILlWQB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3\nzQ7IDdwQAAABVD0+IpcAAAQDAEcwRQIgI+w7bGB6Yaoe+ObRTde8yGIldncJ+eu/\n5xDrIz0InbICIQCkxFSS2+8ZFmu+/OLMVA72ErP8Gia0KbfkvYqBYmcryQB3AGj2\nmPgfZIK+OozuuSgdTPxxUV1nk9RE0QpnrLtPT/vEAAABVD0+IpMAAAQDAEgwRgIh\nALElfBtz9v6YddQJXPaEi+Kw+KNLrmz6WsAGmfAmVfPmAiEAsttSP6oCwEhVx8x9\nmc42aejfmt9WvLufnCG0kV2wdXEwDQYJKoZIhvcNAQELBQADggEBADD1iEG8euUw\nr+D104kPasFlicSF6Xbqb7KOVf2Whu/7EMqNci1uSCvUfJwfekzkYR9kJ+SGozd7\nzyatCdx2O+ER5PVaRQO5TWM5nrL9YUum6shEw/qKlfqh6QvIANgG7r9XVNVK/TW7\nWPcX0KeEOV6pyNJFV7BDtSdDC9rbDdmRLeCUyTbJACBVdIJGE0YqJQwpTHB0EbBU\naKtc+f/CdRVvct3Cf4SDqWaQEbroNpdQ7T0OAMRvLLzt71wys8SHw8Ffa/7pApmm\nwthZ1kPsQsRMHdhsTzvaMaEsC9ZNUbcsLAnTDC7aECpAUquOqO4RsgCqXzmSYS7a\nW/iRil53ZpA=\n-----END CERTIFICATE-----\napi.www.svenskaspel.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_ticketrikskortet.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFOTCCBCGgAwIBAgISESFqmv9qazcTAAxXLzgtX5bJMA0GCSqGSIb3DQEBCwUA\nMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTwwOgYD\nVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gU0hB\nMjU2IC0gRzIwHhcNMTYwMjE1MTAzNjA0WhcNMTcwNDI4MTMwMDAwWjBnMQswCQYD\nVQQGEwJGUjEXMBUGA1UECBMOSGF1dHMtZGUtU2VpbmUxETAPBgNVBAcTCE1hbGFr\nb2ZmMRMwEQYDVQQKEwpFREVOUkVEIFNBMRcwFQYDVQQDEw53d3cuZWRlbnJlZC5z\nZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJk64k7izHX/3tT/OgyT\nDsUx3Q59kgyTmCf+LxhFLPXGon8XpSHZKr9YlB1V5cQWOGavm7yd8oD3gLpP7Kc7\ndUdNi6HVvCInIbz5wkC9KHrHddAfJN+ge4H7kZVG3iB7mVEAXn4mTZhZ6Ryrk5E1\nEttNccCH5vbwGWqqlhAtSj667V1YV9PNbIU19LdGiyXrqSYxkU5eFtz1H9amCc2+\nZi7zBoHpGJd//ZZqtJ7M9BO3/eFypi4efy70q9uK+Rz/auKLsSpOsE+bRdhO+2Dq\nEZpXNL8WPJ8VcjapRDwA8zRZWyXfywB9cMSZi/zYjBCaWR2Yg+YiWfcxBIvX0nQC\nIOcCAwEAAaOCAd4wggHaMA4GA1UdDwEB/wQEAwIFoDBJBgNVHSAEQjBAMD4GBmeB\nDAECAjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9y\nZXBvc2l0b3J5LzAlBgNVHREEHjAcgg53d3cuZWRlbnJlZC5zZYIKZWRlbnJlZC5z\nZTAJBgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNV\nHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dzL2dzb3Jn\nYW5pemF0aW9udmFsc2hhMmcyLmNybDCBoAYIKwYBBQUHAQEEgZMwgZAwTQYIKwYB\nBQUHMAKGQWh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzb3Jn\nYW5pemF0aW9udmFsc2hhMmcycjEuY3J0MD8GCCsGAQUFBzABhjNodHRwOi8vb2Nz\ncDIuZ2xvYmFsc2lnbi5jb20vZ3Nvcmdhbml6YXRpb252YWxzaGEyZzIwHQYDVR0O\nBBYEFINVyXBBD8j8ezpKRW/LqDa8LD/0MB8GA1UdIwQYMBaAFJbeYfG9HBYpUxzA\nzH07gwBA5hp8MA0GCSqGSIb3DQEBCwUAA4IBAQBEjKFbo9oIPBe8sRzDORmY82hR\naQjI7xsk/F82R+UvkKMoE45VyLR4wAQSJ+dMtE7QdkuN43SXqySaj3UG1ohh2E9o\n0NKMVkY1F4tlbG5ngaqjudM9lF23yTCISfQa3a+Idl4LhwiwgtZqdqfM3iR8TYe7\nnkrJY4KYXURWGvdoMCnSWbgS2I77+gk3idoah+3JVpBPpX4FgMABi/UgZfHGz9hZ\nAfbhJgY8t3edeFBug0VlUEvhckMtLwOppKmi45Yp+Dttygz4MnX0fCDYiUpVopYe\nnMXmXWIyW5C065HQf6IlcV35vg0q7C+aztvCFGL/s6BPNY3F2vIJ0I9mGjna\n-----END CERTIFICATE-----\nwww.edenred.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_vasttrafik.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIG8TCCBdmgAwIBAgIQLw3oiO5pfyS//nmbxVLjUDANBgkqhkiG9w0BAQsFADBE\nMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU\nR2VvVHJ1c3QgU1NMIENBIC0gRzMwHhcNMTYxMTI0MDAwMDAwWhcNMjAwMTE2MjM1\nOTU5WjB4MQswCQYDVQQGEwJTRTEYMBYGA1UECAwPVmFzdHJhIEdvdGFsYW5kMRAw\nDgYDVQQHDAdTS8OWVkRFMRYwFAYDVQQKDA1WYXN0dHJhZmlrIEFCMQswCQYDVQQL\nDAJJVDEYMBYGA1UEAwwPKi52YXN0dHJhZmlrLnNlMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEApcU6TNs1zd1p0Y8ZwRagpav7ir4erVZwdjdocHXS5cTr\nTzgiwOeXlJRmd/708OFRfN6bQq+s1hnULqdwB9eWXUdOd3jZwJPuSupBnChJHrCQ\nd9X81/hmvqUKnqvy9YBB2KZPSip4vj5C0r6gyL7FzqywHWmZ0KCyD+a0y3rj6jZH\nreMq2v6FpjLA8F55pegEI21PVVQ0HEWJV2K6ATnbEVw3/u1CqA5DuRj0zWJjYU+j\nQfTYsXVq/mA1CntuNsAXVosrrolgbr+T4KqTmsDhXLAGeS/CGjQBgCNhHI9ljU8G\nkDH9k7N4mQDyJ23Stxpsr9G2GmcZ3HEpApgpFz9EcwIDAQABo4IDqTCCA6UwKQYD\nVR0RBCIwIIIPKi52YXN0dHJhZmlrLnNlgg12YXN0dHJhZmlrLnNlMAkGA1UdEwQC\nMAAwDgYDVR0PAQH/BAQDAgWgMCsGA1UdHwQkMCIwIKAeoByGGmh0dHA6Ly9nbi5z\neW1jYi5jb20vZ24uY3JsMIGdBgNVHSAEgZUwgZIwgY8GBmeBDAECAjCBhDA/Bggr\nBgEFBQcCARYzaHR0cHM6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9yZXBv\nc2l0b3J5L2xlZ2FsMEEGCCsGAQUFBwICMDUMM2h0dHBzOi8vd3d3Lmdlb3RydXN0\nLmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeS9sZWdhbDAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAU0m/3lvSFP3I8MH0j2oV4m6N8Wnww\nVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vZ24uc3ltY2QuY29t\nMCYGCCsGAQUFBzAChhpodHRwOi8vZ24uc3ltY2IuY29tL2duLmNydDCCAfUGCisG\nAQQB1nkCBAIEggHlBIIB4QHfAHcA3esdK3oNT6Ygi4GtgWhwfi6OnQHVXIiNPRHE\nzbbsvswAAAFYljT1wAAABAMASDBGAiEAzUGB2nVUZmC/eiEOWFYaeOm61lHVgSzB\nYMfQ2chLCOsCIQC5yme+mKFeYJlsOcZGXviu4trgbFTwQ5/+dsGwX7cVAQB1AO5L\nvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABWJY09gAAAAQDAEYwRAIg\nVPvLVocxnFGLTT1lhPN3Qgbr7ps5R48r6lYeaUWChMICIAcQD2cHWNx8RKHFPGE0\n/moYHbD8rQTDDUBrMRLdGhcxAHUAvHjh38X2PGhGSTNNoQ+hXwl5aSAJwIG08/aR\nfz7ZuKUAAAFYljT2tgAABAMARjBEAiAgz+64cfRsaYoEKblmyo1rG+7g5fIvODu1\n9klLI0EO+AIgDNce5RMtVyDiaMUKTvWqKh7Rn9F2/kdjyk8PPTNQCsUAdgCkuQmQ\ntBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAViWNPXfAAAEAwBHMEUCICHG\n6qRiiiTNKbZPNU55DKOpLn7mLsoD4MCxtyzuYz6TAiEA1kguSD4gB1Ov/zMdTytm\nyXZvRAo5PTmulMZX/v1XnDowDQYJKoZIhvcNAQELBQADggEBAFIyiOvLKy/sPqOp\nwYFyb/U6coPLGoCaqZG5XP5GC5wl1i2+y2U0GJ6270LHRQHtHxIkggYGiZUF2FE2\nFjFwcSDvE1jiQF6Oub/VapNdRoBDG0OtBILF5rgS0k2lpMpk6Q7yKUJbARaUTbWX\nrMA/rcWwsOMCoYO3rS+KrefsZsOjt9UKPljbn/BrA+++FyK3TCwpli529+BCIkP8\nfprgHJY/DbIXCU/PSBeIdyIq6YYyg5v1ZB0/uv5pFgQ6tpXhR1Fj8+ICuctmQ/8Y\n94rgEraoBiKpVL8EK8T5t7cHJLq53jT76eWHolLzQNr96NCrU9rGQaTKKF/SZ78M\n3WKfVac=\n-----END CERTIFICATE-----\nwww.vasttrafik.se:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/cert_zidisha.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFRTCCBC2gAwIBAgIRALL16i1zNSkcJwJ6D+N7mXAwDQYJKoZIhvcNAQELBQAw\ngZAxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTYwNAYD\nVQQDEy1DT01PRE8gUlNBIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIg\nQ0EwHhcNMTYwMTExMDAwMDAwWhcNMTkwMjE1MjM1OTU5WjBOMSEwHwYDVQQLExhE\nb21haW4gQ29udHJvbCBWYWxpZGF0ZWQxEzARBgNVBAsTCkNPTU9ETyBTU0wxFDAS\nBgNVBAMTC3ppZGlzaGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEAuKE2rxtX5B+MoLM8fq8zEdX1GcnUGgMe5/Gb+f7yytdekWCW+8d+m9XM9Shn\nOBcU57VBHYpgh4agDsKjFEyOHsYRHr/GA0ApMdWAcTukRPuLclLI1A4kuEJoOjpJ\nhMk8oeUGbdUbplNohFLnSiXuB5WlwD/Dmu0yASc8y2XWfF+XUfb6XE508e3m+tEU\nvprKQ6Ed3N1rxqJAeKX1R5D31WGMeVCzBNQyL6wezevyBD99xVq3zTSttWrf/P9f\nD2MXLfZb48eL7qg9VMvt6Q84ncO3Pd532MCP6NKfv2OchuPfj1Sp6vkNsDBBpXeX\nDi72AmENHSZdw2CCAIDDJN7QNwIDAQABo4IB2TCCAdUwHwYDVR0jBBgwFoAUkK9q\nOpRaC9iQ6hJWc99DtDoo2ucwHQYDVR0OBBYEFMMQqjKURbICRechx3ePy6/dxhE6\nMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUF\nBwMBBggrBgEFBQcDAjBPBgNVHSAESDBGMDoGCysGAQQBsjEBAgIHMCswKQYIKwYB\nBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMAgGBmeBDAECATBU\nBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9S\nU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGFBggrBgEFBQcB\nAQR5MHcwTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E\nT1JTQURvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYBBQUH\nMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAnBgNVHREEIDAeggt6aWRpc2hh\nLm9yZ4IPd3d3LnppZGlzaGEub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQAWZteFTH1O\nWuLFvh7zdR/vrAd/LoPQaGpipQ1fl57KDk+V1AHzRjhClZyc8iRG7LckogWveSB9\nIkHh9DsXog6FvL1Uzo2RtoNhiZlGO9FPC09oD0TZSdxPdbT6Vy1X2hdXhQfOZ9qj\nYllovUEiFsviEAqGX8Ghsx9f0sWoCM2ryqHp/9rnjm7ssLKW4PeYF3wXQHHYHv6m\ne8ynJTGy+2AP25NOjP+QOwzv5Z55LbQZ/5kuYiKQgZNP2t385f4920bq5ONrDXty\nI7iX1nuHYRekIh/3RIuOs0gv4mQWuinkX4MkAt8jmDnvK+WvS9SstvlhHidpzApq\nZOxgmUzR3DLJ\n-----END CERTIFICATE-----\nwww.zidisha.org:443\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/raw/loading.html",
    "content": "<html>\n\t<head>\n\t\t<meta name=\"viewport\" content=\"width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;\"/>\n\t\t<style type=\"text/css\">\n\t\t\tbody {\n\t\t\t\t/*background: #1a1a1a url(file:///android_asset/background_repeat.png) no-repeat;*/\n\t\t\t\tbackground: transparent;\n\t\t\t\tbackground-size: 100%%;\n\t\t\t\tmargin: 0;\n\t\t\t\tpadding: 0;\n\t\t\t\theight: 100%%;\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-left: 12%%;\n\t\t\t\twidth: 76%%;\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: 45%%;\n\t\t\t}\n\t\t\t#logo {\n\t\t\t\twidth: 100%%;\n\t\t\t\tdisplay: block;\n\t\t\t}\n\t\t\t#loading {\n\t\t\t        float:right;\n\t\t\t}\n\t\t\t.c {\n\t\t\t    background-color: #59b1f9; /*Preload: #CCC; Presubmit: #59b1f9*/\n\t\t\t    float:left;\n\t\t\t    height:6px;\n\t\t\t    margin-left:5px;\n\t\t\t    width:6px;\n\t\t\t    -webkit-animation-name: bounce_circle;\n\t\t\t    -webkit-border-radius:3px;\n\t\t\t    -webkit-animation-duration: 2.5s;\n\t\t\t    -webkit-animation-iteration-count: infinite;\n\t\t\t    -webkit-animation-direction: linear;\n\t\t\t    opacity:0.3;\n\t\t\t}\n\t\t\t#c1{\n\t\t\t    -webkit-animation-delay: .0s;\n\t\t\t }\n\t\t\t#c2{\n\t\t\t    -webkit-animation-delay: .4s;\n\t\t\t}\n\t\t\t#c3{\n\t\t\t    -webkit-animation-delay: .8s;\n\t\t\t}\n\t\t\t#c4{\n\t\t\t    -webkit-animation-delay: 1.2s;\n\t\t\t}\n\t\t\t@-webkit-keyframes bounce_circle{\n\t\t\t    0%%{opacity:0.3;}\n\t\t\t    50%%{opacity:1;background-color:#111}\n\t\t\t    100%%{opacity:0.3;}\n\t\t\t}\n\t\t</style>\n\t\t<script type=\"text/javascript\">\n\t\t%s\n\t\t</script>\n\t</head>\n\t<body>\n\t\t<div id=\"content\">\n\t\t\t<img id=\"logo\" src=\"file:///android_asset/logo_text_big.png\" alt=\"Bankdroid\" />\n\t\t\t<div id=\"loading\">\n\t\t\t\t<div id=\"c1\" class=\"c\"></div>\n\t\t\t\t<div id=\"c2\" class=\"c\"></div>\n\t\t\t\t<div id=\"c3\" class=\"c\"></div>\n\t\t\t\t<div id=\"c4\" class=\"c\"></div>\n\t\t\t</div>\n\t\t</div>\n\t\t%s\n\t</body>\n</html> "
  },
  {
    "path": "bankdroid-legacy/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">bankdroid</string>\n\n    <string name=\"username\">Username</string>\n    <string name=\"password\">Password</string>\n    <string name=\"extras_field\">Extras</string>\n    <string name=\"card_number\">Card number</string>\n    <string name=\"email\">E-mail</string>\n    <string name=\"points\">points</string>\n    <string name=\"card_id\">Card ID</string>\n    <string name=\"balance\">Balance</string>\n    <string name=\"pno\">YYYYMMDDNNNN</string>\n\n    <string name=\"bitcoin_address\">Bitcoin address</string>\n    <string name=\"invalid_bitcoin_address\">Invalid bitcoin address.</string>\n    <string name=\"public_pension\">Public pension</string>\n    <string name=\"occupational_pension\">Occupational pension</string>\n    <string name=\"private_pension\">Private pension</string>\n\n    <string name=\"unable_to_find\">Unable to find</string>\n    <string name=\"unable_to_login\">Unable to login. Please try again later.</string>\n    <string name=\"invalid_username_password\">Invalid username or password.</string>\n    <string name=\"no_accounts_found\">No accounts found</string>\n    <string name=\"invalid_username\">Invalid username.</string>\n    <string name=\"invalid_card_number\">Invalid card number.</string>\n    <string name=\"server_error_try_again\">Server error. Please try again later.</string>\n    <string name=\"update_transactions_error\">\"There was a problem updating the transaction details. Please try again later.\"</string>\n\n</resources>\n"
  },
  {
    "path": "bankdroid-legacy/src/main/res/values-sv/strings.xml",
    "content": "<resources>\n    <string name=\"username\">Användarnamn</string>\n    <string name=\"password\">Lösenord</string>\n    <string name=\"card_number\">Kortnummer</string>\n    <string name=\"email\">E-post</string>\n    <string name=\"points\">poäng</string>\n    <string name=\"card_id\">Kort ID</string>\n    <string name=\"balance\">Saldo</string>\n    <string name=\"pno\">ÅÅÅÅMMDDNNNN</string>\n\n    <string name=\"bitcoin_address\">Bitcoin-adress</string>\n    <string name=\"invalid_bitcoin_address\">Ogiltig bitcoin-adress.</string>\n    <string name=\"public_pension\">Allmän pension</string>\n    <string name=\"occupational_pension\">Tjänstepension</string>\n    <string name=\"private_pension\">Privat pension</string>\n\n    <string name=\"unable_to_find\">Kunde ej hitta</string>\n    <string name=\"unable_to_login\">Kunde ej logga in. Var vänlig försök igen senare.</string>\n    <string name=\"invalid_username_password\">Användarnamn och lösenord stämmer ej.</string>\n    <string name=\"no_accounts_found\">Inga konton funna</string>\n    <string name=\"invalid_username\">Ogiltigt användarnamn.</string>\n    <string name=\"invalid_card_number\">Ogiltigt kortnummer.</string>\n    <string name=\"server_error_try_again\">Serverfel. Var god försök igen om en stund.</string>\n    <string name=\"update_transactions_error\">Kunde ej uppdatera transaktionsdata. Var vänlig försök igen senare.</string>\n</resources>\n"
  },
  {
    "path": "bankdroid-legacy/src/test/java/com/liato/bankdroid/utils/ExceptionUtilsTest.java",
    "content": "package com.liato.bankdroid.utils;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.ConnectException;\n\nimport eu.nullbyte.android.urllib.Urllib;\nimport not.bankdroid.at.all.ExceptionFactory;\n\npublic class ExceptionUtilsTest {\n    @Test\n    public void testBlameBankdroid() {\n        Exception e = ExceptionFactory.getException();\n        String before = toStringWithStacktrace(e);\n        ExceptionUtils.blameBankdroid(e);\n        String after = toStringWithStacktrace(e);\n        String description =\n                String.format(\"\\n---- Before ----\\n%s---- After ----\\n%s----\", before, after);\n\n        String[] afterLines = after.split(\"\\n\");\n        int lastCausedByIndex = 0;\n        for (int i = 0; i < afterLines.length; i++) {\n            if (afterLines[i].startsWith(\"Caused by: \")) {\n                lastCausedByIndex = i;\n            }\n        }\n\n        Assert.assertNotEquals(description, 0, lastCausedByIndex);\n        Assert.assertTrue(description,\n                afterLines[lastCausedByIndex + 1].startsWith(\"\\tat com.liato.bankdroid.\"));\n    }\n\n    /**\n     * Like {@link #testBlameBankdroid()} but with an Exception with a cause.\n     */\n    @Test\n    public void testBlameBankdroidWithCause() {\n        Exception e = ExceptionFactory.getExceptionWithCause();\n        String before = toStringWithStacktrace(e);\n        ExceptionUtils.blameBankdroid(e);\n        String after = toStringWithStacktrace(e);\n        String description =\n                String.format(\"\\n---- Before ----\\n%s---- After ----\\n%s----\", before, after);\n\n        String[] afterLines = after.split(\"\\n\");\n        int firstCausedByIndex = 0;\n        for (int i = 0; i < afterLines.length; i++) {\n            if (afterLines[i].startsWith(\"Caused by: \")) {\n                firstCausedByIndex = i;\n                break;\n            }\n        }\n        Assert.assertNotEquals(description, 0, firstCausedByIndex);\n        Assert.assertTrue(description,\n                afterLines[firstCausedByIndex + 1].startsWith(\"\\tat not.bankdroid.at.all.\"));\n\n        int lastCausedByIndex = 0;\n        for (int i = 0; i < afterLines.length; i++) {\n            if (afterLines[i].startsWith(\"Caused by: \")) {\n                lastCausedByIndex = i;\n            }\n        }\n        Assert.assertNotEquals(description, 0, lastCausedByIndex);\n        Assert.assertTrue(description,\n                afterLines[lastCausedByIndex + 1].startsWith(\"\\tat com.liato.bankdroid.\"));\n    }\n\n    @Test\n    public void testBlameBankdroidAlreadyToBlame() {\n        // Creating it here we're already inside of Bankdroid code, blaming bankdroid should be a\n        // no-op\n        Exception e = new Exception();\n\n        String before = toStringWithStacktrace(e);\n\n        ExceptionUtils.blameBankdroid(e);\n        String after = toStringWithStacktrace(e);\n\n        Assert.assertEquals(before, after);\n    }\n\n    private String toStringWithStacktrace(Exception e) {\n        StringWriter stringWriter = new StringWriter();\n        PrintWriter printWriter = new PrintWriter(stringWriter);\n        e.printStackTrace(printWriter);\n        printWriter.close();\n        return stringWriter.toString();\n    }\n\n    @Test\n    public void testBankdroidifyStacktrace() {\n        StackTraceElement[] bankdroidified = new StackTraceElement[] {\n                new StackTraceElement(\"not.bankdroid.SomeClass\", \"someMethod\", \"SomeClass.java\", 42),\n                new StackTraceElement(\"com.liato.bankdroid.SomeOtherClass\", \"someOtherMethod\", \"SomeOtherClass.java\", 43),\n        };\n        bankdroidified = ExceptionUtils.bankdroidifyStacktrace(bankdroidified);\n\n        StackTraceElement[] expected = new StackTraceElement[] {\n                new StackTraceElement(\"com.liato.bankdroid.SomeOtherClass\", \"someOtherMethod\", \"SomeOtherClass.java\", 43),\n        };\n\n        Assert.assertArrayEquals(expected, bankdroidified);\n\n        // Test re-bankdroidification\n        Assert.assertArrayEquals(expected, ExceptionUtils.bankdroidifyStacktrace(bankdroidified));\n    }\n\n    @Test\n    public void testCloneExceptionWonky() {\n        ExceptionFactory.WonkyException raw = ExceptionFactory.getWonkyException();\n\n        @SuppressWarnings(\"ThrowableResultOfMethodCallIgnored\")\n        ConnectException cloned = ExceptionUtils.cloneException(raw);\n\n        assert cloned != null;\n        Assert.assertEquals(raw.getMessage(), cloned.getMessage());\n        Assert.assertArrayEquals(raw.getStackTrace(), cloned.getStackTrace());\n        Assert.assertEquals(\n                \"Cloning an uninstantiable Exception should return an instance of its super class\",\n                raw.getClass().getSuperclass(), cloned.getClass());\n    }\n\n    @Test\n    @SuppressWarnings({\"PMD.AvoidCatchingNPE\"})\n    public void testCloneExceptionNPE() {\n        NullPointerException raw = null;\n        try {\n            //noinspection ConstantConditions\n            new Urllib(null);\n            Assert.fail(\"Exception expected\");\n        } catch (NullPointerException e) {\n            raw = e;\n        }\n\n        @SuppressWarnings(\"ThrowableResultOfMethodCallIgnored\")\n        NullPointerException cloned = ExceptionUtils.cloneException(raw);\n\n        assert cloned != null;\n        Assert.assertEquals(raw.getMessage(), cloned.getMessage());\n        Assert.assertArrayEquals(raw.getStackTrace(), cloned.getStackTrace());\n        Assert.assertEquals(raw.getClass(), cloned.getClass());\n    }\n\n    @Test(timeout = 1000)\n    public void testGetUltimateCauseRecursive() {\n        Exception recursive = new Exception();\n        Exception intermediate = new Exception(recursive);\n        recursive.initCause(intermediate);\n        Assert.assertNull(ExceptionUtils.getUltimateCause(recursive));\n    }\n\n    @Test\n    public void testConcatArrays() {\n        StackTraceElement s1 = new StackTraceElement(\"a\", \"b\", \"c\", 123);\n        StackTraceElement s2 = new StackTraceElement(\"d\", \"e\", \"f\", 456);\n        StackTraceElement[] concatenated =\n                ExceptionUtils.concatArrays(\n                        new StackTraceElement[]{s1}, new StackTraceElement[]{s2});\n        Assert.assertArrayEquals(new StackTraceElement[]{ s1, s2 }, concatenated);\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/test/java/not/bankdroid/at/all/ExceptionFactory.java",
    "content": "package not.bankdroid.at.all;\n\nimport java.net.ConnectException;\n\n/**\n * For the test in {@link com.liato.bankdroid.utils.ExceptionUtilsTest}\n */\npublic class ExceptionFactory {\n    public static class WonkyException extends ConnectException {\n        public WonkyException(int wonky) {\n            super(\"Wonky: \" + wonky);\n        }\n    }\n\n    public static WonkyException getWonkyException() {\n        return new WonkyException(5);\n    }\n\n    public static Exception getException() {\n        return new Exception(\"This is a test Exception\");\n    }\n\n    public static Exception getExceptionWithCause() {\n        return new Exception(\"This Exception has a cause\", getException());\n    }\n}\n"
  },
  {
    "path": "bankdroid-legacy/src/test/java/not/bankdroid/at/all/ExceptionThrower.java",
    "content": "package not.bankdroid.at.all;\n\nimport java.net.ConnectException;\n\n/**\n * For the test in {@link com.liato.bankdroid.utils.ExceptionUtilsTest}\n */\npublic class ExceptionThrower {\n    public static class WonkyException extends ConnectException {\n        public WonkyException(int wonky) {\n            super(\"Wonky: \" + wonky);\n        }\n    }\n\n    public static void throwWonkyException() throws WonkyException {\n        throw new WonkyException(5);\n    }\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n\nsubprojects {\n    // Workaround. See https://code.google.com/p/android/issues/detail?id=64887#c54\n    plugins.withType(JavaPlugin).whenPluginAdded {\n        task copyTestResources(type: Copy) {\n            from \"${projectDir}/src/test/resources\"\n            into \"${buildDir}/classes/test\"\n        }\n        processTestResources.dependsOn copyTestResources\n    }\n}\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '3.3'\n}\n"
  },
  {
    "path": "config/ide/androidstudio/AndroidStyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<code_scheme name=\"AndroidStyle\">\n    <option name=\"JAVA_INDENT_OPTIONS\">\n        <value>\n            <option name=\"INDENT_SIZE\" value=\"4\"/>\n            <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n            <option name=\"TAB_SIZE\" value=\"8\"/>\n            <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n            <option name=\"SMART_TABS\" value=\"false\"/>\n            <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n            <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n            <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n        </value>\n    </option>\n    <option name=\"FIELD_NAME_PREFIX\" value=\"m\"/>\n    <option name=\"STATIC_FIELD_NAME_PREFIX\" value=\"m\"/>\n    <option name=\"CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND\" value=\"9999\"/>\n    <option name=\"NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND\" value=\"9999\"/>\n    <option name=\"IMPORT_LAYOUT_TABLE\">\n        <value>\n            <package name=\"com.google\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"com\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"junit\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"net\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"org\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"android\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"java\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"javax\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"\" withSubpackages=\"true\" static=\"true\"/>\n        </value>\n    </option>\n    <option name=\"RIGHT_MARGIN\" value=\"100\"/>\n    <option name=\"JD_P_AT_EMPTY_LINES\" value=\"false\"/>\n    <option name=\"JD_DO_NOT_WRAP_ONE_LINE_COMMENTS\" value=\"true\"/>\n    <option name=\"JD_KEEP_EMPTY_PARAMETER\" value=\"false\"/>\n    <option name=\"JD_KEEP_EMPTY_EXCEPTION\" value=\"false\"/>\n    <option name=\"JD_KEEP_EMPTY_RETURN\" value=\"false\"/>\n    <option name=\"JD_PRESERVE_LINE_FEEDS\" value=\"true\"/>\n    <option name=\"KEEP_CONTROL_STATEMENT_IN_ONE_LINE\" value=\"false\"/>\n    <option name=\"KEEP_BLANK_LINES_IN_CODE\" value=\"1\"/>\n    <option name=\"BLANK_LINES_AROUND_FIELD\" value=\"1\"/>\n    <option name=\"BLANK_LINES_AFTER_CLASS_HEADER\" value=\"1\"/>\n    <option name=\"ALIGN_MULTILINE_PARAMETERS\" value=\"false\"/>\n    <option name=\"ALIGN_MULTILINE_FOR\" value=\"false\"/>\n    <option name=\"CALL_PARAMETERS_WRAP\" value=\"1\"/>\n    <option name=\"METHOD_PARAMETERS_WRAP\" value=\"1\"/>\n    <option name=\"EXTENDS_LIST_WRAP\" value=\"1\"/>\n    <option name=\"THROWS_LIST_WRAP\" value=\"1\"/>\n    <option name=\"EXTENDS_KEYWORD_WRAP\" value=\"1\"/>\n    <option name=\"THROWS_KEYWORD_WRAP\" value=\"1\"/>\n    <option name=\"METHOD_CALL_CHAIN_WRAP\" value=\"1\"/>\n    <option name=\"BINARY_OPERATION_WRAP\" value=\"1\"/>\n    <option name=\"BINARY_OPERATION_SIGN_ON_NEXT_LINE\" value=\"true\"/>\n    <option name=\"TERNARY_OPERATION_WRAP\" value=\"1\"/>\n    <option name=\"TERNARY_OPERATION_SIGNS_ON_NEXT_LINE\" value=\"true\"/>\n    <option name=\"FOR_STATEMENT_WRAP\" value=\"1\"/>\n    <option name=\"ARRAY_INITIALIZER_WRAP\" value=\"1\"/>\n    <option name=\"ASSIGNMENT_WRAP\" value=\"1\"/>\n    <option name=\"PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE\" value=\"true\"/>\n    <option name=\"WRAP_COMMENTS\" value=\"true\"/>\n    <option name=\"IF_BRACE_FORCE\" value=\"3\"/>\n    <option name=\"DOWHILE_BRACE_FORCE\" value=\"3\"/>\n    <option name=\"WHILE_BRACE_FORCE\" value=\"3\"/>\n    <option name=\"FOR_BRACE_FORCE\" value=\"3\"/>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"css\">\n        <option name=\"INDENT_SIZE\" value=\"4\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"java\">\n        <option name=\"INDENT_SIZE\" value=\"4\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"8\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"js\">\n        <option name=\"INDENT_SIZE\" value=\"4\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"4\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"jsp\">\n        <option name=\"INDENT_SIZE\" value=\"4\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"sql\">\n        <option name=\"INDENT_SIZE\" value=\"2\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"xml\">\n        <option name=\"INDENT_SIZE\" value=\"4\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <ADDITIONAL_INDENT_OPTIONS fileType=\"yml\">\n        <option name=\"INDENT_SIZE\" value=\"2\"/>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"8\"/>\n        <option name=\"TAB_SIZE\" value=\"4\"/>\n        <option name=\"USE_TAB_CHARACTER\" value=\"false\"/>\n        <option name=\"SMART_TABS\" value=\"false\"/>\n        <option name=\"LABEL_INDENT_SIZE\" value=\"0\"/>\n        <option name=\"LABEL_INDENT_ABSOLUTE\" value=\"false\"/>\n        <option name=\"USE_RELATIVE_INDENTS\" value=\"false\"/>\n    </ADDITIONAL_INDENT_OPTIONS>\n    <codeStyleSettings language=\"JavaScript\">\n        <option name=\"KEEP_CONTROL_STATEMENT_IN_ONE_LINE\" value=\"false\"/>\n        <option name=\"KEEP_BLANK_LINES_IN_CODE\" value=\"1\"/>\n        <option name=\"BLANK_LINES_AROUND_FIELD\" value=\"1\"/>\n        <option name=\"BLANK_LINES_AFTER_CLASS_HEADER\" value=\"1\"/>\n        <option name=\"ALIGN_MULTILINE_PARAMETERS\" value=\"false\"/>\n        <option name=\"ALIGN_MULTILINE_FOR\" value=\"false\"/>\n        <option name=\"CALL_PARAMETERS_WRAP\" value=\"1\"/>\n        <option name=\"METHOD_PARAMETERS_WRAP\" value=\"1\"/>\n        <option name=\"EXTENDS_LIST_WRAP\" value=\"1\"/>\n        <option name=\"THROWS_LIST_WRAP\" value=\"1\"/>\n        <option name=\"EXTENDS_KEYWORD_WRAP\" value=\"1\"/>\n        <option name=\"THROWS_KEYWORD_WRAP\" value=\"1\"/>\n        <option name=\"METHOD_CALL_CHAIN_WRAP\" value=\"1\"/>\n        <option name=\"BINARY_OPERATION_WRAP\" value=\"1\"/>\n        <option name=\"BINARY_OPERATION_SIGN_ON_NEXT_LINE\" value=\"true\"/>\n        <option name=\"TERNARY_OPERATION_WRAP\" value=\"1\"/>\n        <option name=\"TERNARY_OPERATION_SIGNS_ON_NEXT_LINE\" value=\"true\"/>\n        <option name=\"FOR_STATEMENT_WRAP\" value=\"1\"/>\n        <option name=\"ARRAY_INITIALIZER_WRAP\" value=\"1\"/>\n        <option name=\"ASSIGNMENT_WRAP\" value=\"1\"/>\n        <option name=\"PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE\" value=\"true\"/>\n        <option name=\"WRAP_COMMENTS\" value=\"true\"/>\n        <option name=\"IF_BRACE_FORCE\" value=\"3\"/>\n        <option name=\"DOWHILE_BRACE_FORCE\" value=\"3\"/>\n        <option name=\"WHILE_BRACE_FORCE\" value=\"3\"/>\n        <option name=\"FOR_BRACE_FORCE\" value=\"3\"/>\n        <option name=\"PARENT_SETTINGS_INSTALLED\" value=\"true\"/>\n    </codeStyleSettings>\n</code_scheme>\n"
  },
  {
    "path": "config/quality/checkstyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n   \"http://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n<module name=\"Checker\">\n    <property name=\"charset\" value=\"UTF-8\"/>\n\n    <property name=\"severity\" value=\"error\" />\n\n    <module name=\"SuppressionFilter\">\n      <property name=\"file\" value=\"${checkstyleSuppressionsPath}\"/>\n    </module>\n    <module name=\"FileTabCharacter\">\n        <property name=\"eachLine\" value=\"true\"/>\n    </module>\n    <module name=\"Translation\" />\n\n    <!--\n    <module name=\"RegexpSingleline\">\n        <property name=\"format\" value=\"\\s+$\" />\n        <property name=\"minimum\" value=\"0\" />\n        <property name=\"maximum\" value=\"0\" />\n        <property name=\"message\" value=\"Line has trailing spaces.\" />\n        <property name=\"severity\" value=\"info\" />\n    </module>\n    -->\n\n    <module name=\"TreeWalker\">\n        <property name=\"tabWidth\" value=\"4\" />\n        <module name=\"AvoidStarImport\" />\n        <module name=\"IllegalImport\" />\n        <module name=\"RedundantImport\" />\n        <module name=\"UnusedImports\" />\n        <!-- <module name=\"ParameterNumber\" /> -->\n        <module name=\"EmptyForIteratorPad\" />\n        <module name=\"MethodParamPad\" />\n\n        <module name=\"NoWhitespaceAfter\">\n            <property name=\"tokens\" value=\"BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS\" />\n        </module>\n        <module name=\"NoWhitespaceBefore\" />\n        <module name=\"WhitespaceAfter\">\n            <property name=\"tokens\" value=\"COMMA, SEMI\"/> <!-- Not TYPECAST -->\n        </module>\n        <module name=\"WhitespaceAround\">\n           <property name=\"allowEmptyMethods\" value=\"true\" />\n        </module>\n\n        <module name=\"ParenPad\" />\n        <module name=\"TypecastParenPad\" />\n        <module name=\"RedundantModifier\" />\n        <module name=\"AvoidNestedBlocks\" />\n        <module name=\"LeftCurly\" />\n        <module name=\"NeedBraces\" />\n        <module name=\"RightCurly\" />\n        <module name=\"EmptyStatement\" />\n        <module name=\"EqualsHashCode\" />\n        <module name=\"IllegalInstantiation\" />\n        <module name=\"InnerAssignment\" />\n        <module name=\"SimplifyBooleanExpression\" />\n        <module name=\"SimplifyBooleanReturn\" />\n        <!-- <module name=\"HideUtilityClassConstructor\" /> -->\n        <!-- <module name=\"InterfaceIsType\" /> -->\n        <module name=\"ArrayTypeStyle\" />\n\n        <module name=\"UpperEll\" />\n\n        <!--\n        <module name=\"LineLength\">\n            <property name=\"max\" value=\"100\" />\n            <property name=\"ignorePattern\" value=\"^package.*|^import.*|a href|href|http://|https://|ftp://|content://\"/>\n        </module>\n        -->\n    </module>\n</module>\n"
  },
  {
    "path": "config/quality/checkstyle/suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!DOCTYPE suppressions PUBLIC\n    \"-//Puppy Crawl//DTD Suppressions 1.1//EN\"\n    \"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd\">\n\n<suppressions>\n    <suppress files=\"R.java\" checks=\"[a-zA-Z0-9]*\"/>\n    <suppress files=\"BuildConfig.java\" checks=\"[a-zA-Z0-9]*\"/>\n    <suppress files=\"Test\" checks=\"[a-zA-Z0-9]*\"/>\n    <suppress files=\"generated\" checks=\"[a-zA-Z0-9]*\"/>\n</suppressions>\n"
  },
  {
    "path": "config/quality/findbugs/findbugs-filter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FindBugsFilter>\n    <!-- http://stackoverflow.com/questions/7568579/eclipsefindbugs-exclude-filter-files-doesnt-work -->\n    <Match>\n        <Class name=\"~.*\\.R\\$.*\"/>\n    </Match>\n    <Match>\n        <Class name=\"~.*\\.Manifest\\$.*\"/>\n    </Match>\n    <!-- All bugs in test classes, except for JUnit-specific bugs -->\n    <Match>\n        <Class name=\"~.*\\.*Test\" />\n        <Not>\n            <Bug code=\"IJU\" />\n        </Not>\n    </Match>\n</FindBugsFilter>\n"
  },
  {
    "path": "config/quality/lint/lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n    <!-- Disable since it has external dependencies that we cannot affect. -->\n    <issue id=\"GradleDependency\" severity=\"ignore\" />\n\n    <!-- Disable since it starts failing for non-code-related reasons. -->\n    <issue id=\"OldTargetApi\" severity=\"ignore\" />\n\n    <!-- FIXME: This file should be empty and all violations fixed. Then we will all hug. -->\n\n    <issue id=\"AllowBackup\" severity=\"ignore\" />\n    <issue id=\"AlwaysShowAction\" severity=\"ignore\" />\n    <issue id=\"AppCompatResource\" severity=\"ignore\" />\n    <issue id=\"BatteryLife\" severity=\"ignore\" />\n    <issue id=\"ClickableViewAccessibility\" severity=\"ignore\" />\n    <issue id=\"ContentDescription\" severity=\"ignore\" />\n    <issue id=\"DefaultLocale\" severity=\"ignore\" />\n    <issue id=\"ExportedReceiver\" severity=\"ignore\" />\n    <issue id=\"GetInstance\" severity=\"ignore\" />\n    <issue id=\"GoogleAppIndexingWarning\" severity=\"ignore\" />\n    <issue id=\"IconDensities\" severity=\"ignore\" />\n    <issue id=\"IconDuplicates\" severity=\"ignore\" />\n    <issue id=\"IconLocation\" severity=\"ignore\" />\n    <issue id=\"IconMissingDensityFolder\" severity=\"ignore\" />\n    <issue id=\"InefficientWeight\" severity=\"ignore\" />\n    <issue id=\"InlinedApi\" severity=\"ignore\" />\n    <issue id=\"InvalidPackage\" severity=\"ignore\" />\n    <issue id=\"ManifestOrder\" severity=\"ignore\" />\n    <issue id=\"MergeRootFrame\" severity=\"ignore\" />\n    <issue id=\"MissingTranslation\" severity=\"ignore\" />\n    <issue id=\"NewApi\" severity=\"ignore\" />\n    <issue id=\"NewerVersionAvailable\" severity=\"ignore\" />\n    <issue id=\"NotSibling\" severity=\"ignore\" />\n    <issue id=\"ObsoleteLayoutParam\" severity=\"ignore\" />\n    <issue id=\"Orientation\" severity=\"ignore\" />\n    <issue id=\"Overdraw\" severity=\"ignore\" />\n    <issue id=\"ParcelClassLoader\" severity=\"ignore\" />\n    <issue id=\"PluralsCandidate\" severity=\"ignore\" />\n    <issue id=\"Registered\" severity=\"ignore\" />\n    <issue id=\"RtlHardcoded\" severity=\"ignore\" />\n    <issue id=\"RtlSymmetry\" severity=\"ignore\" />\n    <issue id=\"ScrollViewSize\" severity=\"ignore\" />\n    <issue id=\"SelectableText\" severity=\"ignore\" />\n    <issue id=\"SetJavaScriptEnabled\" severity=\"ignore\" />\n    <issue id=\"SimpleDateFormat\" severity=\"ignore\" />\n    <issue id=\"TrulyRandom\" severity=\"ignore\" />\n    <issue id=\"UnknownIdInLayout\" severity=\"ignore\" />\n    <issue id=\"UnusedAttribute\" severity=\"ignore\" />\n    <issue id=\"UseCompoundDrawables\" severity=\"ignore\" />\n    <issue id=\"UselessParent\" severity=\"ignore\" />\n    <issue id=\"WorldReadableFiles\" severity=\"ignore\" />\n</lint>\n"
  },
  {
    "path": "config/quality/pmd/pmd-ruleset.xml",
    "content": "<?xml version=\"1.0\"?>\n<ruleset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"Bankdroid Rules\"\n    xmlns=\"http://pmd.sf.net/ruleset/1.0.0\"\n    xsi:noNamespaceSchemaLocation=\"http://pmd.sf.net/ruleset_xml_schema.xsd\"\n    xsi:schemaLocation=\"http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd\">\n\n    <description>Custom ruleset for Bankdroid, created by update-suppressions.sh</description>\n\n    <exclude-pattern>.*/R.java</exclude-pattern>\n    <exclude-pattern>.*/gen/.*</exclude-pattern>\n\n    <rule ref=\"rulesets/internal/all-java.xml/TooManyStaticImports\">\n        <properties>\n            <property name=\"legalPackages\" type=\"String\"\n              description=\"Allow static imports for following packages.\"\n              value=\"org.hamcrest.*|org.junit.*\"/>\n            <property name=\"xpath\">\n                <value><![CDATA[\n                    .[count(ImportDeclaration[@Static='true' and\n                    not(\n                        matches(@PackageName, $legalPackages)\n                    )]) > $maximumStaticImports]\n                ]]></value>\n            </property>\n        </properties>\n    </rule>\n\n    <!-- Add Cursor to the classes that need closing -->\n    <rule ref=\"rulesets/internal/all-java.xml/CloseResource\">\n        <properties>\n            <property name=\"types\" value=\"Connection,Statement,ResultSet,Cursor\" />\n        </properties>\n    </rule>\n\n    <!-- FIXME: This file should be empty and all violations fixed. Then we will all hug. -->\n    <rule ref=\"rulesets/internal/all-java.xml\">\n\n        <!-- This check needs extra configuration to work, disable it for now -->\n        <exclude name=\"LoosePackageCoupling\" />\n\n        <exclude name=\"AbstractNaming\" />\n        <exclude name=\"AccessorClassGeneration\" />\n        <exclude name=\"AppendCharacterWithChar\" />\n        <exclude name=\"ArrayIsStoredDirectly\" />\n        <exclude name=\"AssignmentInOperand\" />\n        <exclude name=\"AssignmentToNonFinalStatic\" />\n        <exclude name=\"AtLeastOneConstructor\" />\n        <exclude name=\"AvoidCatchingGenericException\" />\n        <exclude name=\"AvoidConstantsInterface\" />\n        <exclude name=\"AvoidDecimalLiteralsInBigDecimalConstructor\" />\n        <exclude name=\"AvoidDeeplyNestedIfStmts\" />\n        <exclude name=\"AvoidDuplicateLiterals\" />\n        <exclude name=\"AvoidFieldNameMatchingMethodName\" />\n        <exclude name=\"AvoidFieldNameMatchingTypeName\" />\n        <exclude name=\"AvoidInstantiatingObjectsInLoops\" />\n        <exclude name=\"AvoidLiteralsInIfCondition\" />\n        <exclude name=\"AvoidPrefixingMethodParameters\" />\n        <exclude name=\"AvoidReassigningParameters\" />\n        <exclude name=\"AvoidSynchronizedAtMethodLevel\" />\n        <exclude name=\"AvoidThrowingRawExceptionTypes\" />\n        <exclude name=\"BeanMembersShouldSerialize\" />\n        <exclude name=\"BigIntegerInstantiation\" />\n        <exclude name=\"BooleanGetMethodName\" />\n        <exclude name=\"CallSuperInConstructor\" />\n        <exclude name=\"ClassWithOnlyPrivateConstructorsShouldBeFinal\" />\n        <exclude name=\"CollapsibleIfStatements\" />\n        <exclude name=\"CommentDefaultAccessModifier\" />\n        <exclude name=\"CommentRequired\" />\n        <exclude name=\"CommentSize\" />\n        <exclude name=\"CompareObjectsWithEquals\" />\n        <exclude name=\"ConfusingTernary\" />\n        <exclude name=\"ConstantsInInterface\" />\n        <exclude name=\"ConstructorCallsOverridableMethod\" />\n        <exclude name=\"CyclomaticComplexity\" />\n        <exclude name=\"DataflowAnomalyAnalysis\" />\n        <exclude name=\"DefaultPackage\" />\n        <exclude name=\"DoNotUseThreads\" />\n        <exclude name=\"EmptyIfStmt\" />\n        <exclude name=\"EmptyMethodInAbstractClassShouldBeAbstract\" />\n        <exclude name=\"ExcessiveClassLength\" />\n        <exclude name=\"ExcessiveImports\" />\n        <exclude name=\"ExcessiveMethodLength\" />\n        <exclude name=\"ExcessiveParameterList\" />\n        <exclude name=\"ExcessivePublicCount\" />\n        <exclude name=\"FieldDeclarationsShouldBeAtStartOfClass\" />\n        <exclude name=\"GodClass\" />\n        <exclude name=\"ImmutableField\" />\n        <exclude name=\"InefficientStringBuffering\" />\n        <exclude name=\"InsufficientStringBufferDeclaration\" />\n        <exclude name=\"JUnit4TestShouldUseBeforeAnnotation\" />\n        <exclude name=\"JUnitTestsShouldIncludeAssert\" />\n        <exclude name=\"LawOfDemeter\" />\n        <exclude name=\"LocalVariableCouldBeFinal\" />\n        <exclude name=\"LongVariable\" />\n        <exclude name=\"LooseCoupling\" />\n        <exclude name=\"MethodArgumentCouldBeFinal\" />\n        <exclude name=\"MethodNamingConventions\" />\n        <exclude name=\"MissingBreakInSwitch\" />\n        <exclude name=\"ModifiedCyclomaticComplexity\" />\n        <exclude name=\"NPathComplexity\" />\n        <exclude name=\"NcssMethodCount\" />\n        <exclude name=\"NullAssignment\" />\n        <exclude name=\"OneDeclarationPerLine\" />\n        <exclude name=\"OnlyOneReturn\" />\n        <exclude name=\"PositionLiteralsFirstInComparisons\" />\n        <exclude name=\"PrematureDeclaration\" />\n        <exclude name=\"RedundantFieldInitializer\" />\n        <exclude name=\"ShortClassName\" />\n        <exclude name=\"ShortMethodName\" />\n        <exclude name=\"ShortVariable\" />\n        <exclude name=\"SignatureDeclareThrowsException\" />\n        <exclude name=\"SimpleDateFormatNeedsLocale\" />\n        <exclude name=\"SimplifyBooleanReturns\" />\n        <exclude name=\"SimplifyStartsWith\" />\n        <exclude name=\"StdCyclomaticComplexity\" />\n        <exclude name=\"SwitchDensity\" />\n        <exclude name=\"SwitchStmtsShouldHaveDefault\" />\n        <exclude name=\"TooFewBranchesForASwitchStatement\" />\n        <exclude name=\"TooManyFields\" />\n        <exclude name=\"TooManyMethods\" />\n        <exclude name=\"UncommentedEmptyMethodBody\" />\n        <exclude name=\"UnnecessaryConstructor\" />\n        <exclude name=\"UnnecessaryFullyQualifiedName\" />\n        <exclude name=\"UnnecessaryLocalBeforeReturn\" />\n        <exclude name=\"UnnecessaryParentheses\" />\n        <exclude name=\"UnnecessaryWrapperObjectCreation\" />\n        <exclude name=\"UnsynchronizedStaticDateFormatter\" />\n        <exclude name=\"UnusedLocalVariable\" />\n        <exclude name=\"UseCollectionIsEmpty\" />\n        <exclude name=\"UseConcurrentHashMap\" />\n        <exclude name=\"UseEqualsToCompareStrings\" />\n        <exclude name=\"UseIndexOfChar\" />\n        <exclude name=\"UseLocaleWithCaseConversions\" />\n        <exclude name=\"UseObjectForClearerAPI\" />\n        <exclude name=\"UseStringBufferForStringAppends\" />\n        <exclude name=\"UseUtilityClass\" />\n        <exclude name=\"UseVarargs\" />\n        <exclude name=\"UselessOverridingMethod\" />\n        <exclude name=\"UselessParentheses\" />\n        <exclude name=\"UselessQualifiedThis\" />\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "config/quality/quality.gradle",
    "content": "apply plugin: 'checkstyle'\napply plugin: 'findbugs'\napply plugin: 'pmd'\n\n// Add checkstyle, findbugs and lint to the check task.\ncheck.dependsOn 'checkstyle', 'findbugs', 'pmd'\n\ntask checkstyle(type: Checkstyle) {\n    source 'src'\n    include '**/*.java'\n    classpath = files()\n}\n\ncheckstyle {\n    toolVersion '6.1.1' // TODO https://github.com/jshiell/checkstyle-idea/blob/dbe595028c3488400790e6caed2f122fba0bded1/README#L13-19\n    ignoreFailures false\n    configFile file(\"${project.rootDir}/config/quality/checkstyle/checkstyle.xml\")\n    configProperties.checkstyleSuppressionsPath = file(\"${project.rootDir}/config/quality/checkstyle/suppressions.xml\").absolutePath\n}\n\ntask findbugs(type: FindBugs) {\n    effort = \"max\"\n    reportLevel = \"high\"\n    excludeFilter = new File(\"${project.rootDir}/config/quality/findbugs/findbugs-filter.xml\")\n\n    source 'src'\n    include '**/*.java'\n    exclude '**/generated/**'\n\n    reports {\n        xml.enabled = false\n        html.enabled = true\n        xml {\n            destination \"$project.buildDir/reports/findbugs/findbugs.xml\"\n        }\n        html {\n            destination \"$project.buildDir/reports/findbugs/findbugs.html\"\n        }\n    }\n\n    classpath = files()\n}\n\ntask pmd(type: Pmd) {\n    ruleSetFiles = files(\"${project.rootDir}/config/quality/pmd/pmd-ruleset.xml\")\n    ignoreFailures = false\n    consoleOutput = true\n    ruleSets = []\n\n    source 'src'\n    include '**/*.java'\n    exclude '**/generated/**'\n\n    reports {\n        xml.enabled = true\n        html.enabled = true\n        xml {\n            destination \"$project.buildDir/reports/pmd/pmd.xml\"\n        }\n        html {\n            destination \"$project.buildDir/reports/pmd/pmd.html\"\n        }\n    }\n}\n\nif (plugins.hasPlugin('android') || plugins.hasPlugin('com.android.library')) {\n    check.dependsOn 'lint'\n    tasks.getByName(\"findbugs\").dependsOn 'compileDebugSources'\n    tasks.getByName('findbugs').classes = files(\"$project.buildDir/intermediates/classes\")\n    android {\n        lintOptions {\n            abortOnError true\n            warningsAsErrors true\n            checkAllWarnings true\n\n            // FIXME: This file contains *far* too many disabled checks. Somebody think of the children!\n            lintConfig file(\"${project.rootDir}/config/quality/lint/lint.xml\")\n\n            textOutput \"stdout\"\n            textReport true\n\n            htmlReport true\n            // optional path to report (default will be lint-results.html in the builddir)\n            htmlOutput file(\"$project.buildDir/reports/lint/lint.html\")\n        }\n    }\n}\nif (plugins.hasPlugin('java')) {\n    tasks.getByName('findbugs').classes = files(\"$project.buildDir/classes\")\n    tasks.getByName('findbugs').dependsOn 'classes'\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Mar 02 21:11:13 CET 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.3-bin.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Settings specified in this file will override any Gradle settings\n# configured through the IDE.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\norg.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':bankdroid-core', ':bankdroid-legacy', ':bankdroid-interface'\n"
  },
  {
    "path": "tools/nordea_captcha_breaker/captchabreaker.py",
    "content": "import datetime\nimport os\nimport random\nimport subprocess\nimport urllib2\n\nfrom PIL import Image\n\nconfirmed = {}\nimgdata = {}\n\ndef guess_number(img):\n    width, height = img.size\n    img = img.load()\n    for number in confirmed.values():\n        matches = 0\n        for point in number.points:\n            if point[0] >= width:\n                break\n            color = img[point[0], point[1]]\n            color = (color[0] << 16) + (color[1] << 8) + color[2]\n            if (color == 0xffffff and not point[2]) or (color != 0xffffff and point[2]):\n                matches += 1\n        #print \"matches: %d \" % matches\n        if matches == len(number.points):\n            return number.number\n    return None\n\ndef getCaptcha():\n    print \"Downloading new captcha...\"\n    r = urllib2.urlopen(\"https://mobil.nordea.se/banking-nordea/nordea-c3/captcha.png\")\n    f = open(\"captcha.png\", \"wb\")\n    f.write(r.read())\n    f.close()\n    img = Image.open(\"captcha.png\")\n    print \"Captcha downloaded.\"\n    return img\n\ndef extract_numbers(img):\n    pixels = img.load()\n    width, height = img.size\n    numbers = []\n\n    numberpart = False\n    current_start = None\n    current_end = None\n    for x in range(width-1):\n        numberpartcol = False\n        for y in range(height-1):\n            color = pixels[x, y]\n            color = (color[0] << 16) + (color[1] << 8) + color[2]\n            if color != 0xffffff:\n                if not numberpart:\n                    #print \"Start at %d\" % x\n                    current_start = x\n                numberpart = numberpartcol = True\n                break\n\n        if numberpart and not numberpartcol:            \n            numberpart = False\n            #print \"End at %d\" % (x-1,)\n            current_end = x-1\n            numbers.append((current_start, current_end))\n\n    if current_end is None:\n        numbers.append((current_start, width-1))\n\n    return numbers\n\ndef numbers2text(img, numbers):\n    text = []\n    width, height = img.size\n    for i, slice in enumerate(numbers):\n        number = img.crop((slice[0], 0, slice[1], height-1))\n        numguess = guess_number(number)\n        text.append(numguess)\n    return \"\".join(text)\n\n\n\nclass CaptchaNumber(object):\n    def __init__(self, number, points):\n        self.number = number\n        self.points = points\n\n    def __repr__(self):\n        return '<CaptchaNumber(%d)>' % number\n        \n\ndef main():\n    while True:\n        img = getCaptcha()\n        width, height = img.size\n        print \"Image size: %dx%d\" % (width, height)\n        numbers = extract_numbers(img)\n        print \"Found %d numbers in captcha\" % len(numbers)\n        for i, slice in enumerate(numbers):\n            number = img.crop((slice[0], 0, slice[1], height-1))\n\n            fname = \"tempslice.png\"\n            number.save(fname)\n            #print \"Number: width: %d, height: %d\" % number.size\n            pixels = number.load()\n            numguess = guess_number(number)\n            #os.system(fname)\n            #if numguess is not None:\n            #    correct = raw_input(\"Does the image display number %s? y/n: \" % numguess)\n            #    if not correct.startswith(\"y\"):\n            #        numguess = None\n\n\n            if numguess is None:\n                os.system(fname)\n                num = raw_input(\"Number in image?: \")\n                points = []\n                for j in range(32):\n                    x = random.randint(0, number.size[0]-1)\n                    y = random.randint(0, number.size[1]-1)\n                    color = pixels[x, y]\n                    color = (color[0] << 16) + (color[1] << 8) + color[2]\n                    points.append((x, y, color != 0xffffff))\n                confirmed[num] = CaptchaNumber(num, points)\n                imgdata[num] = number\n\n                if len(confirmed) < 10:\n                    confirmed_sorted = confirmed.keys()\n                    confirmed_sorted.sort()\n                    print \"Confirmed numbers: %s\" % confirmed_sorted\n                else:\n                    break\n\n        if len(confirmed) == 10:\n            print \"All numbers collected. Creating html and java files.\"\n            break\n\n\ndef create_html():\n    print \"Downloading 100 captchas for testing...\"\n    date = str(datetime.datetime.today())[:19]\n    dir = os.path.join(os.getcwd(), date.replace(\"-\",\"\").replace(\":\",\"\").replace(\" \", \"\"))\n    os.makedirs(dir)\n    for i in range(100):\n        f = open(os.path.join(dir, \"captcha%03d.png\" % (i+1)), \"wb\")\n        r = urllib2.urlopen(\"https://mobil.nordea.se/banking-nordea/nordea-c3/captcha.png\")\n        f.write(r.read())\n        f.close()\n    print \"Done.\"\n    html = open(\"captchas_template.html\", \"r\").read()\n    html_item = open(\"captchas_item_template.html\", \"r\").read()\n    captchas = []\n    for i in range(100):\n        img = Image.open(os.path.join(dir, \"captcha%03d.png\" % (i+1)))\n        captcha_item = html_item\n        captcha_item = captcha_item.replace(\"%decaptcha%\", numbers2text(img, extract_numbers(img))).replace(\"%number%\", \"%03d\" % (i+1))\n        captchas.append(captcha_item)\n    html = html.replace(\"%captchas%\", \"\\n\".join(captchas)).replace(\"%date%\", date)\n    f = open(os.path.join(dir, \"captchas.html\"), \"w\")\n    f.write(html)\n    f.close()\n    os.system(os.path.join(dir, \"captchas.html\"))\n    javadata = []\n    for x in range(len(confirmed.keys())):\n        points = []\n        captcha_number = confirmed[str(x)];\n        for point in captcha_number.points:\n            points.append((int(point[0]), int(point[1]), 1 if point[2] else 0))\n        javadata.append(points)\n    javadata = str(javadata).replace(\"[\",\"{\").replace(\"]\",\"}\").replace(\"(\",\"{\").replace(\")\",\"}\")\n    javadata = \"\"\"\n/**\n * Autogenerated captcha numbers for Nordea.\n *\n * @since %s\n */\npublic class CaptchaBreakerNumbers {\n    public final static int[][][] NUMBERS = %s;\n}\n\"\"\" % (date, javadata)\n    f = open(os.path.join(dir, \"CaptchaBreakerNumbers.java\"), \"w\")\n    f.write(javadata)\n    f.close()\n    print \"CaptchaBreakerNumbers.java generated.\"\n    print \"All done.\"\n\nif __name__ == '__main__':\n    main()\n    create_html()"
  },
  {
    "path": "tools/nordea_captcha_breaker/captchas_item_template.html",
    "content": "        <div class=\"captcha-block\">\n            <div class=\"number\">%number%</div>\n            <div class=\"captcha\"><img src=\"captcha%number%.png\"></div>\n            <div class=\"decaptcha\">%decaptcha%</div>\n        </div>"
  },
  {
    "path": "tools/nordea_captcha_breaker/captchas_template.html",
    "content": "<html>\n<head>\n    <title>Nordea Captchas</title>\n    <style type=\"text/css\">\n    body {\n        font-family: Arial, helvetica, sans-serif;\n        background: #f8f8f8;\n        color: #363636;\n    }\n    .captcha-block {\n        display: inline-block;\n        padding: 10px;\n        border-bottom: solid #e3e3e3 1px; \n        border-right: solid #e3e3e3 1px; \n    }\n    .decaptcha {\n        font-family: monospace;\n        font-size: 40px;\n        font-weight: bold;\n        background-color: #fff;\n        display: inline-block;\n    }\n    .captcha {\n        margin-top: 3px;\n    }\n    .number {\n        background-color: #72a3f3;\n        color: #fff;\n        display: table-cell;\n        padding: 2px 4px;\n    }\n    .container {\n        max-width: 900px;\n    }\n    p {\n        font-size: 11px;\n\n    }\n    </style>\n</head>\n<body>\n    <h1>Nordea Captchas</h1>\n    <div class=\"container\">\n        %captchas%\n    </div>\n    <p>Generated on %date%</p>\n</body>"
  },
  {
    "path": "tools/refresh_bank_certificates",
    "content": "#!/usr/bin/python\n\n# This script can be used to update bankdroid's bank certificates to\n# match the certificates used by the servers.\n#\n# For this script to understand which server it should contact to\n# refresh a certificate, the server's hostname and port need to be\n# added on the last line of the certificate (after the certificate's\n# pem data).\n#\n# Note: The downloaded certificates are not validated, so you should\n# verify that each updated certificate is really from a trusted\n# server.\n\nimport glob\nimport os\nimport re\nimport select\nimport socket\nimport time\nimport OpenSSL.crypto as crypto\nimport OpenSSL.SSL as ssl\n\n\ndef read_host_information(cert_file):\n    for line in reversed(open(cert_file).readlines()):\n        line = line.strip()\n        if len(line) == 0:\n            continue\n\n        m = re.match(\"([-.0-9a-z]+):([0-9]{2,5})\", line, re.IGNORECASE)\n        if not m:\n            break\n\n        return (m.group(1), int(m.group(2)))\n\n    return None\n\n\ndef get_pem_certificate(host):\n    CONNECTION_TIMEOUT = 10.0  # seconds\n\n    for ssl_method in [ssl.TLSv1_METHOD, ssl.SSLv23_METHOD]:\n        s = None\n        ssl_connection = None\n\n        try:\n            s = socket.socket()\n            s.settimeout(CONNECTION_TIMEOUT)\n            s.connect(host)\n            ssl_connection = ssl.Connection(ssl.Context(ssl_method), s)\n            ssl_connection.set_connect_state()\n\n            handshake_start_time = time.time()\n            while time.time() - handshake_start_time < CONNECTION_TIMEOUT:\n                try:\n                    ssl_connection.do_handshake()\n                    break\n                except ssl.WantReadError:\n                    select.select([ssl_connection], [], [], 1)\n                except ssl.WantWriteError:\n                    select.select([], [ssl_connection], [], 1)\n            else:\n                continue\n\n            return crypto.dump_certificate(\n                crypto.FILETYPE_PEM, ssl_connection.get_peer_certificate())\n        except (socket.error, ssl.Error):\n            continue\n        finally:\n            if ssl_connection:\n                ssl_connection.close()\n            if s:\n                s.close()\n\n    return None\n\n\ndef write_certificate(cert_file, host, cert):\n    f = open(cert_file, \"w\")\n    f.write(cert)\n    f.write(\"%s:%d\\n\" % host)\n    f.close()\n\n\nif __name__ == \"__main__\":\n    certificate_files_pattern = os.path.normpath(os.path.dirname(\n        os.path.realpath(__file__)) + \"/../bankdroid-legacy/src/main/res/raw/*.pem\")\n    for cert_file in glob.glob(certificate_files_pattern):\n        host = read_host_information(cert_file)\n        if host is None:\n            print \"Could not find host information in %s.\" % cert_file\n            print \"This script needs to know hostname and port of the server\"\n            print \"from where the certificate can be retrieved. Please add\"\n            print \"this information in the last line of the certificate file\"\n            print \"(after the certificate data). Write the hostname\"\n            print \"information in the form 'hostname:port'.\"\n            print\n            continue\n\n        cert = get_pem_certificate(host)\n        if cert is None:\n            print \"Failed to get certificate for %s (from %s:%d)\" % (\n                cert_file, host[0], host[1])\n            print\n            continue\n\n        write_certificate(cert_file, host, cert)\n"
  },
  {
    "path": "tools/update-suppressions.sh",
    "content": "#!/bin/bash\n\n# This script generates suppressions files for PMD and Android Lint.\n# The suppressions files list all rules that we violate.\n#\n# Before committing the result of running this script, make sure no\n# new suppressions have been added. We want to get rid of them, not\n# introduce more problems.\n#\n# Note that this script will do a build with all suppressions\n# disabled. That will print a lot of error messages, but that's OK.\n\nROOTDIR=$(cd $(dirname \"$0\") ; cd .. ; pwd)\nLINT_XML=\"${ROOTDIR}/config/quality/lint/lint.xml\"\nPMD_XML=\"${ROOTDIR}/config/quality/pmd/pmd-ruleset.xml\"\n\n# From: https://sipb.mit.edu/doc/safe-shell/\nset -euf -o pipefail\n\nfunction set_lint_suppressions() {\n  cat > ${LINT_XML} << EOF\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n    <!-- Disable since it has external dependencies that we cannot affect. -->\n    <issue id=\"GradleDependency\" severity=\"ignore\" />\n\n    <!-- Disable since it starts failing for non-code-related reasons. -->\n    <issue id=\"OldTargetApi\" severity=\"ignore\" />\n\n    <!-- FIXME: This file should be empty and all violations fixed. Then we will all hug. -->\n\nEOF\n\n  for RULE in $1 ; do\n    echo \"    <issue id=\\\"${RULE}\\\" severity=\\\"ignore\\\" />\" >> ${LINT_XML}\n  done\n\n  echo '</lint>' >> ${LINT_XML}\n}\n\nfunction set_pmd_suppressions() {\n  cat > ${PMD_XML} << EOF\n<?xml version=\"1.0\"?>\n<ruleset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"Bankdroid Rules\"\n    xmlns=\"http://pmd.sf.net/ruleset/1.0.0\"\n    xsi:noNamespaceSchemaLocation=\"http://pmd.sf.net/ruleset_xml_schema.xsd\"\n    xsi:schemaLocation=\"http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd\">\n\n    <description>Custom ruleset for Bankdroid, created by $(basename $0)</description>\n\n    <exclude-pattern>.*/R.java</exclude-pattern>\n    <exclude-pattern>.*/gen/.*</exclude-pattern>\n\n    <rule ref=\"rulesets/internal/all-java.xml/TooManyStaticImports\">\n        <properties>\n            <property name=\"legalPackages\" type=\"String\"\n              description=\"Allow static imports for following packages.\"\n              value=\"org.hamcrest.*|org.junit.*\"/>\n            <property name=\"xpath\">\n                <value><![CDATA[\n                    .[count(ImportDeclaration[@Static='true' and\n                    not(\n                        matches(@PackageName, \\$legalPackages)\n                    )]) > \\$maximumStaticImports]\n                ]]></value>\n            </property>\n        </properties>\n    </rule>\n\n    <!-- Add Cursor to the classes that need closing -->\n    <rule ref=\"rulesets/internal/all-java.xml/CloseResource\">\n        <properties>\n            <property name=\"types\" value=\"Connection,Statement,ResultSet,Cursor\" />\n        </properties>\n    </rule>\n\n    <!-- FIXME: This file should be empty and all violations fixed. Then we will all hug. -->\n    <rule ref=\"rulesets/internal/all-java.xml\">\n\n        <!-- This check needs extra configuration to work, disable it for now -->\n        <exclude name=\"LoosePackageCoupling\" />\n\nEOF\n\n  for RULE in $1; do\n    echo \"        <exclude name=\\\"${RULE}\\\" />\" >> ${PMD_XML}\n  done\n\n  cat >> ${PMD_XML} << EOF\n    </rule>\n</ruleset>\nEOF\n}\n\nset_lint_suppressions \"\"\nset_pmd_suppressions \"\"\n\n./gradlew clean check --continue || true\n\nLINT_RESULTFILES=$(find ${ROOTDIR} -name 'lint-results*.xml')\nLINT_VIOLATIONS=$(egrep -h ' *id=\".*\"$' ${LINT_RESULTFILES} | cut '-d\"' -f2 | sort | uniq)\nset_lint_suppressions \"$LINT_VIOLATIONS\"\n\nPMD_RESULTFILES=$(find ${ROOTDIR} -name 'pmd.xml')\nPMD_VIOLATIONS=$(grep externalInfoUrl= ${PMD_RESULTFILES} | sed 's/.*rule=\"//' | cut '-d\"' -f1 | sort | uniq)\nset_pmd_suppressions \"$PMD_VIOLATIONS\"\n\ngit diff ${ROOTDIR}/config\n"
  }
]